Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.14% covered (success)
97.14%
34 / 35
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
NormalizeChildGroup
97.14% covered (success)
97.14%
34 / 35
50.00% covered (danger)
50.00%
1 / 2
10
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
 buildNormalizedData
97.06% covered (success)
97.06%
33 / 34
0.00% covered (danger)
0.00%
0 / 1
9
1<?php
2namespace Apie\Serializer\Context;
3
4use Apie\Core\Context\ApieContext;
5use Apie\Core\Exceptions\IndexNotFoundException;
6use Apie\Core\Metadata\Fields\FallbackFieldInterface;
7use Apie\Core\Metadata\Fields\FieldInterface;
8use Apie\Core\Metadata\MetadataInterface;
9use Apie\Core\Metadata\SetterInterface;
10use Apie\Serializer\Exceptions\ThisIsNotAFieldException;
11use Exception;
12use ReflectionClass;
13
14class NormalizeChildGroup
15{
16    private ApieContext $apieContext;
17
18    public function __construct(
19        private readonly ApieSerializerContext $serializerContext,
20        private readonly MetadataInterface $metadata
21    ) {
22        $this->apieContext = $serializerContext->getContext();
23    }
24
25    /**
26     * @template T of object
27     * @param ReflectionClass<T> $class
28     * @return NormalizedData<T>
29     */
30    public function buildNormalizedData(ReflectionClass $class, array $input): NormalizedData
31    {
32        $built = [];
33        $validationErrors = [];
34        $todoList = [];
35        foreach ($this->metadata->getHashmap()->filterOnContext($this->apieContext, setters: true) as $fieldName => $fieldMetadata) {
36            $todoList[] = [$fieldName, $fieldMetadata];
37        }
38        // this construction is for performance reasons as it maintains only one try catch context.
39        while (!empty($todoList)) {
40            try {
41                while (!empty($todoList)) {
42                    /** @var FieldInterface&SetterInterface $fieldMetadata */
43                    list($fieldName, $fieldMetadata) = array_pop($todoList);
44                    if (!array_key_exists($fieldName, $input)) {
45                        if ($fieldMetadata->isRequired()) {
46                            $validationErrors[$fieldName] = new IndexNotFoundException($fieldName);
47                        }
48                        if ($fieldMetadata instanceof FallbackFieldInterface) {
49                            $built[$fieldName] = new NormalizedValue(
50                                $fieldMetadata->getMissingValue($this->apieContext),
51                                $fieldMetadata
52                            );
53                        }
54                        continue;
55                    }
56                    if (!$fieldMetadata->isField()) {
57                        throw new ThisIsNotAFieldException($fieldName);
58                    }
59                    $built[$fieldName] = new NormalizedValue(
60                        $this->serializerContext->visit($fieldName)->denormalizeFromTypehint(
61                            $input[$fieldName],
62                            $fieldMetadata->getTypehint()
63                        ),
64                        $fieldMetadata
65                    );
66                }
67            } catch (Exception $error) {
68                // @phpstan-ignore variable.undefined
69                $validationErrors[$fieldName] = $error;
70            }
71        }
72
73        return new NormalizedData(
74            $class,
75            $this->apieContext,
76            $built,
77            $validationErrors
78        );
79    }
80}