Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.00% covered (success)
95.00%
19 / 20
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
InviteMemberController
95.00% covered (success)
95.00%
19 / 20
50.00% covered (danger)
50.00%
1 / 2
7
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 invite
94.74% covered (success)
94.74%
18 / 19
0.00% covered (danger)
0.00%
0 / 1
6.01
1<?php
2
3declare(strict_types=1);
4
5namespace App\Trip\Infrastructure\Controllers;
6
7use App\Identity\Infrastructure\Http\ResolvesAuthenticatedUser;
8use App\Shared\Infrastructure\Http\ReadsJsonPayload;
9use App\Trip\Application\Command\InviteMemberCommand;
10use App\Trip\Application\Command\InviteMemberHandler;
11use App\Trip\Domain\Exceptions\AlreadyMemberOrInvited;
12use App\Trip\Domain\Exceptions\InviteeNotFound;
13use App\Trip\Domain\Exceptions\TripAccessDenied;
14use App\Trip\Domain\Exceptions\TripNotFound;
15use App\Trip\Infrastructure\Http\ValidatesTripId;
16use InvalidArgumentException;
17use OpenApi\Attributes as OA;
18use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
19use Symfony\Component\HttpFoundation\JsonResponse;
20use Symfony\Component\HttpFoundation\Request;
21use Symfony\Component\Routing\Attribute\Route;
22
23#[OA\Tag(name: 'Trips')]
24class InviteMemberController extends AbstractController
25{
26    use ReadsJsonPayload;
27    use ResolvesAuthenticatedUser;
28    use ValidatesTripId;
29
30    public function __construct(
31        private readonly InviteMemberHandler $handler,
32    ) {
33    }
34
35    #[Route('/trips/{tripId}/invitations', name: 'trips_invite_member', methods: ['POST'])]
36    public function invite(string $tripId, Request $request): JsonResponse
37    {
38        $securityUser = $this->securityUser();
39
40        if ($this->parseTripId($tripId) === null) {
41            return new JsonResponse(['error' => 'Trip not found.'], 404);
42        }
43
44        try {
45            $payload = $this->decodeJsonBody($request);
46
47            $invitationId = $this->handler->handle(new InviteMemberCommand(
48                tripId: $tripId,
49                inviterUserId: $securityUser->userId(),
50                email: $this->stringField($payload, 'email'),
51                role: $this->stringField($payload, 'role'),
52            ));
53        } catch (TripNotFound|InviteeNotFound $e) {
54            return new JsonResponse(['error' => $e->getMessage()], 404);
55        } catch (TripAccessDenied $e) {
56            return new JsonResponse(['error' => $e->getMessage()], 403);
57        } catch (AlreadyMemberOrInvited $e) {
58            return new JsonResponse(['error' => $e->getMessage()], 409);
59        } catch (InvalidArgumentException $e) {
60            return new JsonResponse(['error' => $e->getMessage()], 400);
61        }
62
63        return new JsonResponse(['id' => $invitationId->value()], 201);
64    }
65}