Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
92.31% covered (success)
92.31%
12 / 13
92.31% covered (success)
92.31%
12 / 13
50.00% covered (danger)
50.00%
5 / 10
80.00% covered (warning)
80.00%
4 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
ValidationExceptionNormalizer
92.31% covered (success)
92.31%
12 / 13
92.31% covered (success)
92.31%
12 / 13
50.00% covered (danger)
50.00%
5 / 10
80.00% covered (warning)
80.00%
4 / 5
16.00
0.00% covered (danger)
0.00%
0 / 1
 supportsNormalization
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 normalizeErrors
88.89% covered (warning)
88.89%
8 / 9
88.89% covered (warning)
88.89%
8 / 9
16.67% covered (danger)
16.67%
1 / 6
0.00% covered (danger)
0.00%
0 / 1
13.26
 getSupportedTypes
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getErrorCode
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getStatus
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace App\Shared\Infrastructure\Normalizer;
4
5use App\Shared\Domain\Exception\ValidationException;
6use InvalidArgumentException;
7use Symfony\Component\Clock\ClockAwareTrait;
8use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;
9use Symfony\Component\HttpFoundation\Response;
10use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
11use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
12use Throwable;
13
14#[AutoconfigureTag('app.exception_normalizer')]
15class ValidationExceptionNormalizer extends ExceptionNormalizer
16{
17
18    use ClockAwareTrait;
19
20    /**
21     * @param mixed $data
22     * @param string|null $format
23     * @param array<string, mixed> $context
24     * @return bool
25     */
26    public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool
27    {
28        return $data instanceof ValidationException;
29    }
30
31
32    /**
33     * @param Throwable $throwable
34     * @return array<string, array<string, string[]|int[]>>
35     */
36    protected function normalizeErrors(Throwable $throwable): array
37    {
38        if (!$throwable instanceof ValidationException) {
39            throw new InvalidArgumentException();
40        }
41
42        $errors = $throwable->getValidationErrors()->getErrors();
43
44        $errorsAsArray = [];
45        foreach ($errors as $field => $validationErrors) {
46            $errorsAsArray[$field] = [];
47            foreach ($validationErrors as $validationError) {
48                $errorsAsArray[$field][$validationError->code()->getCode()] = $validationError->details();
49            }
50        }
51
52        return $errorsAsArray;
53    }
54
55    public function getSupportedTypes(?string $format): array
56    {
57        return [ValidationException::class => true];
58    }
59
60    #[\Override]
61    protected function getErrorCode(Throwable $throwable): string
62    {
63        return 'validation-error';
64    }
65
66    #[\Override]
67    protected function getStatus(Throwable $throwable): int
68    {
69        return Response::HTTP_UNPROCESSABLE_ENTITY;
70    }
71}