adrema/app/Letter/DocumentFactory.php

150 lines
4.0 KiB
PHP
Raw Normal View History

2022-11-07 16:18:11 +01:00
<?php
namespace App\Letter;
use App\Member\Member;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
class DocumentFactory
{
/**
* @var array<int, class-string<Letter>>
*/
public array $types = [
BillDocument::class,
RememberDocument::class,
];
/**
* @return Collection<int, Letter>
*/
public function getTypes(): Collection
{
/** @var array<int, Member> */
$emptyMembers = [];
return collect(array_map(fn ($classString) => new $classString(collect($emptyMembers)), $this->types));
}
/**
* @param class-string<Letter> $type
*/
public function fromSingleRequest(string $type, Member $member): ?Letter
{
2022-12-06 22:16:37 +01:00
$members = $this->singleMemberPages($member, $type);
2022-11-07 16:18:11 +01:00
if ($members->isEmpty()) {
return null;
}
2022-12-06 22:16:37 +01:00
return tap(
$this->resolve($type, $members),
fn ($repo) => $repo->setFilename(Str::slug("{$repo->getSubject()} für {$members->first()->singleName}"))
);
2022-11-07 16:18:11 +01:00
}
/**
* @param class-string<Letter> $type
*/
public function forAll(string $type, string $billKind): ?Letter
{
2022-12-06 22:16:37 +01:00
$pages = $this->allMemberPages($type, $billKind);
2022-11-07 16:18:11 +01:00
2022-12-06 22:16:37 +01:00
if ($pages->isEmpty()) {
2022-11-07 16:18:11 +01:00
return null;
}
2022-12-06 22:16:37 +01:00
return tap($this->resolve($type, $pages), fn ($repo) => $repo->setFilename('alle-rechnungen'));
}
/**
* @param class-string<Letter> $type
*/
public function afterAll(string $type, string $billKind): void
{
$letter = $this->forAll($type, $billKind);
$this->afterSingle($letter);
2022-11-07 16:18:11 +01:00
}
/**
* @param class-string<Letter> $type
*
* @return Collection<int, Letter>
*/
2022-12-06 22:16:37 +01:00
public function letterCollection(string $type, string $billKind): Collection
2022-11-07 16:18:11 +01:00
{
2022-12-06 22:16:37 +01:00
$pages = $this->allMemberPages($type, $billKind);
2022-11-07 16:18:11 +01:00
return $pages->map(fn ($page) => $this->resolve($type, collect([$page])));
}
2022-12-06 22:16:37 +01:00
public function afterSingle(Letter $letter): void
2022-11-07 16:18:11 +01:00
{
2022-12-06 22:16:37 +01:00
foreach ($letter->allPayments() as $payment) {
$letter->afterSingle($payment);
2022-11-07 16:18:11 +01:00
}
}
/**
* @param class-string<Letter> $type
*
* @return Collection<int, Page>
*/
2022-12-06 22:16:37 +01:00
private function singleMemberPages(Member $member, string $type): Collection
2022-11-07 16:18:11 +01:00
{
$members = Member::where($member->only(['lastname', 'address', 'zip', 'location']))
->with([
'payments' => fn ($query) => $type::paymentsQuery($query)
->orderByRaw('nr, member_id'),
])
->get()
->filter(fn (Member $member) => $member->payments->count() > 0);
return $this->toPages($members);
}
/**
* @param class-string<Letter> $type
*
2022-12-06 22:16:37 +01:00
* @return Collection<int, Page>
2022-11-07 16:18:11 +01:00
*/
2022-12-06 22:16:37 +01:00
private function allMemberPages(string $type, string $billKind): Collection
2022-11-07 16:18:11 +01:00
{
2022-12-06 22:16:37 +01:00
$members = Member::whereHas('billKind', fn (Builder $q) => $q->where('name', $billKind))
2022-11-07 16:18:11 +01:00
->with([
'payments' => fn ($query) => $type::paymentsQuery($query)
->orderByRaw('nr, member_id'),
])
->get()
->filter(fn (Member $member) => $member->payments->count() > 0);
2022-12-06 22:16:37 +01:00
return $this->toPages($members);
2022-11-07 16:18:11 +01:00
}
/**
* @param class-string<Letter> $type
* @param Collection<int, Page> $pages
*/
private function resolve(string $type, Collection $pages): Letter
{
return new $type($pages);
}
/**
* @param EloquentCollection<Member> $members
*
* @return Collection<int, Page>
*/
private function toPages(EloquentCollection $members): Collection
{
return $members->groupBy(
fn ($member) => Str::slug(
"{$member->lastname}{$member->address}{$member->zip}{$member->location}",
),
)->map(fn ($page) => new Page($page));
}
}