Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
UpdateCategoryController
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
2 / 2
4
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
 update
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3declare(strict_types=1);
4
5namespace App\Expense\Infrastructure\Controllers\Admin;
6
7use App\Expense\Application\Command\UpdateCategoryCommand;
8use App\Expense\Application\Command\UpdateCategoryHandler;
9use App\Expense\Domain\Exceptions\CategoryNotFound;
10use App\Shared\Infrastructure\Http\ReadsJsonPayload;
11use InvalidArgumentException;
12use OpenApi\Attributes as OA;
13use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
14use Symfony\Component\HttpFoundation\JsonResponse;
15use Symfony\Component\HttpFoundation\Request;
16use Symfony\Component\Routing\Attribute\Route;
17
18#[OA\Tag(name: 'Admin')]
19class UpdateCategoryController extends AbstractController
20{
21    use ReadsJsonPayload;
22
23    public function __construct(
24        private readonly UpdateCategoryHandler $handler,
25    ) {
26    }
27
28    /**
29     * Curate one category: toggle it active and override its presentation. An empty
30     * label/icon/color resets that field to the enum default. No create/delete —
31     * {value} must be one of the enum's cases (anything else → 404).
32     */
33    #[Route('/admin/categories/{value}', name: 'admin_categories_update', methods: ['PUT'])]
34    public function update(string $value, Request $request): JsonResponse
35    {
36        try {
37            $payload = $this->decodeJsonBody($request);
38
39            $view = $this->handler->handle(new UpdateCategoryCommand(
40                category: $value,
41                label: $this->stringField($payload, 'label'),
42                icon: $this->stringField($payload, 'icon'),
43                color: $this->stringField($payload, 'color'),
44                active: $this->boolField($payload, 'active'),
45            ));
46        } catch (CategoryNotFound $e) {
47            return new JsonResponse(['error' => $e->getMessage()], 404);
48        } catch (InvalidArgumentException $e) {
49            return new JsonResponse(['error' => $e->getMessage()], 400);
50        }
51
52        return new JsonResponse($view, 200);
53    }
54}