Completed
Push — master ( 5bf305...2d7c2d )
by Dominik
01:49
created

Denormalizer::getFieldDenormalizerMappings()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 0
cts 8
cp 0
rs 9.6666
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 1
crap 6
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|string                     $object
38
     * @param array                             $data
39
     * @param DenormalizerContextInterface|null $context
40
     * @param string                            $path
41
     *
42
     * @return object
43
     *
44
     * @throws DenormalizerException
45
     */
46
    public function denormalize($object, array $data, DenormalizerContextInterface $context = null, string $path = '')
47
    {
48
        $context = $context ?? new DenormalizerContext();
49
50
        $class = is_object($object) ? get_class($object) : $object;
51
        $objectMapping = $this->getObjectMapping($class);
52
53
        if (!is_object($object)) {
54
            $factory = $objectMapping->getFactory();
55
            $object = $factory();
56
        }
57
58
        $fieldDenormalizerMappings = $this->getFieldDenormalizerMappings($objectMapping);
59
60
        foreach ($data as $field => $value) {
61
            $subPath = '' === $path ? $field : $path.'.'.$field;
62
63
            if (!isset($fieldDenormalizerMappings[$field])) {
64
                if (!$context->isAllowedAdditionalFields()) {
65
                    throw DenormalizerException::createNotAllowedAddtionalField($subPath);
66
                }
67
68
                continue;
69
            }
70
71
            $fieldMapping = $fieldDenormalizerMappings[$field];
72
73
            if ($this->isWithinGroup($context, $fieldMapping)) {
74
                $fieldMapping->getFieldDenormalizer()->denormalizeField($subPath, $object, $value, $this, $context);
75
            }
76
        }
77
78
        return $object;
79
    }
80
81
    /**
82
     * @param string $class
83
     *
84
     * @return DenormalizingObjectMappingInterface
85
     */
86
    private function getObjectMapping(string $class): DenormalizingObjectMappingInterface
87
    {
88
        if (isset($this->objectMappings[$class])) {
89
            return $this->objectMappings[$class];
90
        }
91
92
        throw DenormalizerException::createMissingMapping($class);
93
    }
94
95
    /**
96
     * @param DenormalizingObjectMappingInterface $objectMapping
97
     *
98
     * @return DenormalizingFieldMappingInterface[]
99
     */
100
    private function getFieldDenormalizerMappings(DenormalizingObjectMappingInterface $objectMapping): array
101
    {
102
        $fieldMappings = [];
103
        foreach ($objectMapping->getDenormalizingFieldMappings() as $denormalizingFieldMapping) {
104
            $fieldMappings[$denormalizingFieldMapping->getName()] = $denormalizingFieldMapping;
105
        }
106
107
        return $fieldMappings;
108
    }
109
110
    /**
111
     * @param DenormalizerContextInterface       $context
112
     * @param DenormalizingFieldMappingInterface $fieldMapping
113
     *
114
     * @return bool
115
     */
116
    private function isWithinGroup(
117
        DenormalizerContextInterface $context,
118
        DenormalizingFieldMappingInterface $fieldMapping
119
    ): bool {
120
        if ([] === $groups = $context->getGroups()) {
121
            return true;
122
        }
123
124
        foreach ($fieldMapping->getGroups() as $group) {
125
            if (in_array($group, $groups, true)) {
126
                return true;
127
            }
128
        }
129
130
        return false;
131
    }
132
}
133