Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
86.36% covered (warning)
86.36%
19 / 22
33.33% covered (danger)
33.33%
1 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
ChangeMemberRoleController
86.36% covered (warning)
86.36%
19 / 22
33.33% covered (danger)
33.33%
1 / 3
9.21
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
 change
94.12% covered (success)
94.12%
16 / 17
0.00% covered (danger)
0.00%
0 / 1
6.01
 isUuid
50.00% covered (danger)
50.00%
2 / 4
0.00% covered (danger)
0.00%
0 / 1
2.50
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\ChangeMemberRoleCommand;
10use App\Trip\Application\Command\ChangeMemberRoleHandler;
11use App\Trip\Domain\Exceptions\MemberNotFound;
12use App\Trip\Domain\Exceptions\TripAccessDenied;
13use App\Trip\Domain\Exceptions\TripNotFound;
14use App\Trip\Domain\ValueObject\MemberId;
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\HttpFoundation\Response;
22use Symfony\Component\Routing\Attribute\Route;
23
24#[OA\Tag(name: 'Trips')]
25class ChangeMemberRoleController extends AbstractController
26{
27    use ReadsJsonPayload;
28    use ResolvesAuthenticatedUser;
29    use ValidatesTripId;
30
31    public function __construct(
32        private readonly ChangeMemberRoleHandler $handler,
33    ) {
34    }
35
36    #[Route('/trips/{tripId}/members/{userId}', name: 'trips_change_member_role', methods: ['PUT'])]
37    public function change(string $tripId, string $userId, Request $request): Response
38    {
39        $securityUser = $this->securityUser();
40
41        if ($this->parseTripId($tripId) === null || !$this->isUuid($userId)) {
42            return new JsonResponse(['error' => 'Not found.'], 404);
43        }
44
45        try {
46            $payload = $this->decodeJsonBody($request);
47
48            $this->handler->handle(new ChangeMemberRoleCommand(
49                tripId: $tripId,
50                actingUserId: $securityUser->userId(),
51                targetUserId: $userId,
52                role: $this->stringField($payload, 'role'),
53            ));
54        } catch (TripNotFound|MemberNotFound $e) {
55            return new JsonResponse(['error' => $e->getMessage()], 404);
56        } catch (TripAccessDenied $e) {
57            return new JsonResponse(['error' => $e->getMessage()], 403);
58        } catch (InvalidArgumentException $e) {
59            return new JsonResponse(['error' => $e->getMessage()], 400);
60        }
61
62        return new Response(null, Response::HTTP_NO_CONTENT);
63    }
64
65    private function isUuid(string $id): bool
66    {
67        try {
68            new MemberId($id);
69
70            return true;
71        } catch (InvalidArgumentException) {
72            return false;
73        }
74    }
75}