Test Setup Failed
Push — master ( b50703...9d91c5 )
by Dominik
06:16
created

Denormalizer::denormalize()   C

Complexity

Conditions 8
Paths 36

Size

Total Lines 32
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 32
c 0
b 0
f 0
rs 5.3846
cc 8
eloc 17
nc 36
nop 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Chubbyphp\Deserialization\Denormalizer;
6
7
use Chubbyphp\Deserialization\Mapping\DenormalizingFieldMappingInterface;
8
use Chubbyphp\Deserialization\Mapping\DenormalizingObjectMappingInterface;
9
10
final class Denormalizer implements DenormalizerInterface
11
{
12
    /**
13
     * @var DenormalizingObjectMappingInterface[]
14
     */
15
    private $objectMappings;
16
17
    /**
18
     * @param DenormalizingObjectMappingInterface[] $objectMappings
19
     */
20
    public function __construct(array $objectMappings)
21
    {
22
        $this->objectMappings = [];
23
        foreach ($objectMappings as $objectMapping) {
24
            $this->addObjectMapping($objectMapping);
25
        }
26
    }
27
28
    /**
29
     * @param DenormalizingObjectMappingInterface $objectMapping
30
     */
31
    private function addObjectMapping(DenormalizingObjectMappingInterface $objectMapping)
32
    {
33
        $this->objectMappings[$objectMapping->getClass()] = $objectMapping;
34
    }
35
36
    /**
37
     * @param object                       $object
38
     * @param array                        $data
39
     * @param DenormalizerContextInterface $context
40
     * @param string                       $path
41
     *
42
     * @return object
43
     *
44
     * @throws DenormalizerException
45
     */
46
    public function denormalize($object, array $data, DenormalizerContextInterface $context, string $path = '')
47
    {
48
        $class = is_object($object) ? get_class($object) : $object;
49
        $objectMapping = $this->getObjectMapping($class);
50
51
        if (!is_object($object)) {
52
            $factory = $objectMapping->getFactory();
53
            $object = $factory();
54
        }
55
56
        $fieldDenormalizerMappings = $this->getFieldDenormalizerMappings($objectMapping);
57
58
        foreach ($data as $field => $value) {
59
            $subPath = '' === $path ? $field : $path.'.'.$field;
60
61
            if (!isset($fieldDenormalizerMappings[$field])) {
62
                if (!$context->isAllowedAdditionalFields()) {
63
                    throw DenormalizerException::createNotAllowedAddtionalField($subPath);
64
                }
65
66
                continue;
67
            }
68
69
            $fieldDenormalizer = $fieldDenormalizerMappings[$field]->getFieldDenormalizer();
70
71
            if ($this->isWithinGroup($context, $fieldDenormalizer)) {
72
                $fieldDenormalizer->denormalizeField($subPath, $object, $value, $this);
73
            }
74
        }
75
76
        return $object;
77
    }
78
79
    /**
80
     * @param string $class
81
     *
82
     * @return DenormalizingObjectMappingInterface
83
     */
84
    private function getObjectMapping(string $class): DenormalizingObjectMappingInterface
85
    {
86
        if (isset($this->objectMappings[$class])) {
87
            return $this->objectMappings[$class];
88
        }
89
90
        throw DenormalizerException::createMissingMapping($class);
91
    }
92
93
    /**
94
     * @param DenormalizingObjectMappingInterface $objectMapping
95
     *
96
     * @return DenormalizingFieldMappingInterface[]
97
     */
98
    private function getFieldDenormalizerMappings(DenormalizingObjectMappingInterface $objectMapping): array
99
    {
100
        $fieldMappings = [];
101
        foreach ($objectMapping->getDenormalizingFieldMappings() as $denormalizingFieldMapping) {
102
            $fieldMappings[$denormalizingFieldMapping->getName()] = $denormalizingFieldMapping;
103
        }
104
105
        return $fieldMappings;
106
    }
107
108
    /**
109
     * @param DenormalizerContextInterface $context
110
     * @param FieldDenormalizerInterface   $fieldDenormalizer
111
     *
112
     * @return bool
113
     */
114
    private function isWithinGroup(
115
        DenormalizerContextInterface $context,
116
        FieldDenormalizerInterface $fieldDenormalizer
117
    ): bool {
118
        if ([] === $groups = $context->getGroups()) {
119
            return true;
120
        }
121
122
        foreach ($fieldDenormalizer->getGroups() as $group) {
123
            if (in_array($group, $groups, true)) {
124
                return true;
125
            }
126
        }
127
128
        return false;
129
    }
130
}
131