Test Failed
Push — main ( 53a49f...a78b1c )
by Fractal
02:58
created

RequestConverter::convert()   B

Complexity

Conditions 8
Paths 14

Size

Total Lines 35
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 8

Importance

Changes 0
Metric Value
cc 8
eloc 24
nc 14
nop 1
dl 0
loc 35
ccs 20
cts 20
cp 1
crap 8
rs 8.4444
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace FRZB\Component\RequestMapper\Converter;
6
7
use FRZB\Component\DependencyInjection\Attribute\AsService;
8
use FRZB\Component\RequestMapper\Data\ConverterData;
9
use FRZB\Component\RequestMapper\Data\ValidationError;
10
use FRZB\Component\RequestMapper\Exception\ClassExtractorException;
11
use FRZB\Component\RequestMapper\Exception\ConverterException;
12
use FRZB\Component\RequestMapper\Exception\ValidationException;
13
use FRZB\Component\RequestMapper\Extractor\ConstraintExtractor;
14
use FRZB\Component\RequestMapper\Extractor\DiscriminatorMapExtractor;
15
use FRZB\Component\RequestMapper\Extractor\ParametersExtractor;
16
use FRZB\Component\RequestMapper\Parser\ExceptionConverterInterface as ExceptionConverter;
17
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
18
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface as Denormalizer;
19
use Symfony\Component\Validator\Constraints\Collection;
20
use Symfony\Component\Validator\Validator\ValidatorInterface as Validator;
21
22
#[AsService]
23
class RequestConverter implements ConverterInterface
24
{
25
    private const DENORMALIZE_TYPE = 'array';
26
27 19
    public function __construct(
28
        private readonly Validator $validator,
29
        private readonly Denormalizer $denormalizer,
30
        private readonly ExceptionConverter $exceptionConverter,
31
        private readonly DiscriminatorMapExtractor $classExtractor,
32
        private readonly ConstraintExtractor $constraintExtractor,
33
        private readonly ParametersExtractor $parametersExtractor,
34
    ) {
35
    }
36
37 19
    public function convert(ConverterData $data): object
38
    {
39 19
        $parameters = $data->getRequestParameters();
40 19
        $parameterClass = $data->getParameterClass() ?? throw ConverterException::nullableParameterClass();
41
42
        try {
43 18
            $class = $this->classExtractor->extract($parameterClass, $parameters);
44 2
        } catch (ClassExtractorException $e) {
45 1
            throw ValidationException::fromErrors(ValidationError::fromTypeAndClassExtractorException(DiscriminatorMap::class, $e));
46 1
        } catch (\Throwable $e) {
47 1
            throw ConverterException::fromThrowable($e);
48
        }
49
50 16
        if ($data->isValidationNeeded()) {
51 16
            try {
52 16
                $parameters = $this->parametersExtractor->extract($parameterClass, $parameters);
53
                $constraints = $this->constraintExtractor->extract($class, $parameters);
54 16
55
                $this->validate($parameters, $data->getValidationGroups(), $constraints);
56
            } catch (\TypeError $e) {
57
                throw ValidationException::fromErrors($this->exceptionConverter->convert($e, $parameters));
58 14
            } catch (\Throwable $e) {
59 2
                throw ConverterException::fromThrowable($e);
60 1
            }
61 1
        }
62 1
63
        try {
64
            $object = $this->denormalizer->denormalize($parameters, $class, self::DENORMALIZE_TYPE, $data->getSerializerContext());
65 12
        } catch (\TypeError $e) {
66
            throw ValidationException::fromErrors($this->exceptionConverter->convert($e, $parameters));
67
        } catch (\Throwable $e) {
68
            throw ConverterException::fromThrowable($e);
69 16
        }
70
71 16
        return $object;
72 2
    }
73
74
    /** @throws ValidationException */
75
    private function validate(mixed $target, array $validationGroups, ?Collection $constraints = null): void
76
    {
77
        if (($violations = $this->validator->validate($target, $constraints, $validationGroups))->count()) {
78
            throw ValidationException::fromConstraintViolationList($violations);
79
        }
80
    }
81
}
82