Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
CancelInvitationHandler
100.00% covered (success)
100.00%
10 / 10
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%
9 / 9
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2
3declare(strict_types=1);
4
5namespace App\Trip\Application\Command;
6
7use App\Trip\Application\TripAccess;
8use App\Trip\Domain\Exceptions\InvitationNotFound;
9use App\Trip\Domain\TripInvitationRepository;
10use App\Trip\Domain\ValueObject\InvitationId;
11use App\Trip\Domain\ValueObject\TripId;
12
13/**
14 * Owner cancels a pending invitation on their trip (DELETE .../invitations/{id}).
15 * A pending invitation, once cancelled, is deleted outright — there is no outcome
16 * to keep, unlike an accepted/declined one.
17 */
18final readonly class CancelInvitationHandler
19{
20    public function __construct(
21        private TripAccess $access,
22        private TripInvitationRepository $invitations,
23    ) {
24    }
25
26    public function handle(CancelInvitationCommand $command): void
27    {
28        $tripId = new TripId($command->tripId);
29        // Owner-only: stranger -> 404, non-owner member -> 403.
30        $this->access->getForManage($tripId, $command->actingUserId);
31
32        $invitationId = new InvitationId($command->invitationId);
33        $invitation = $this->invitations->ofId($invitationId);
34        if ($invitation === null
35            || !$invitation->tripId()->equals($tripId)
36            || !$invitation->isPending()) {
37            throw InvitationNotFound::withId($invitationId);
38        }
39
40        $this->invitations->remove($invitation);
41    }
42}