Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
ListMyInvitationsHandler
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
2 / 2
5
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 handle
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2
3declare(strict_types=1);
4
5namespace App\Trip\Application\Query;
6
7use App\Trip\Application\Port\MemberDirectory;
8use App\Trip\Domain\TripInvitationRepository;
9use App\Trip\Domain\TripRepository;
10use App\Trip\Domain\ValueObject\MemberId;
11
12/**
13 * The caller's pending received invitations (their inbox). Each item carries the
14 * trip name and inviter name so the UI needs no follow-up lookups.
15 *
16 * @phpstan-type InvitationItem array{id: string, tripName: string, inviterName: string, role: string}
17 */
18final readonly class ListMyInvitationsHandler
19{
20    public function __construct(
21        private TripInvitationRepository $invitations,
22        private TripRepository $trips,
23        private MemberDirectory $directory,
24    ) {
25    }
26
27    /**
28     * @return list<array{id: string, tripName: string, inviterName: string, role: string}>
29     */
30    public function handle(ListMyInvitationsQuery $query): array
31    {
32        $pending = $this->invitations->pendingOfInvitee(new MemberId($query->userId));
33        if ($pending === []) {
34            return [];
35        }
36
37        $inviterIds = [];
38        foreach ($pending as $invitation) {
39            $inviterIds[] = $invitation->inviterId();
40        }
41        $inviters = $this->directory->summariesOf($inviterIds);
42
43        $items = [];
44        foreach ($pending as $invitation) {
45            $trip = $this->trips->ofId($invitation->tripId());
46            // FK CASCADE guarantees the inviter still exists; the trip may not
47            // be re-fetchable only in impossible races, so it stays nullsafe.
48            $inviter = $inviters[$invitation->inviterId()->value()];
49            $items[] = [
50                'id' => $invitation->id()->value(),
51                'tripName' => $trip?->name() ?? '',
52                'inviterName' => $inviter->name,
53                'role' => $invitation->role()->value,
54            ];
55        }
56
57        return $items;
58    }
59}