Completed
Push — master ( a3231e...8de51f )
by Dominik
02:02
created

Denormalizer::getSubPathByName()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 2
eloc 2
nc 2
nop 2
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
        foreach ($objectMapping->getDenormalizingFieldMappings() as $denormalizingFieldMapping) {
59
            $name = $denormalizingFieldMapping->getName();
60
            if (!isset($data[$name]) && !$context->isReplaceMode()) {
61
                continue;
62
            }
63
64
            $fieldDenormalizer = $denormalizingFieldMapping->getFieldDenormalizer();
65
66
            $value = $data[$name] ?? $fieldDenormalizer->getDefault();
67
68
            unset($data[$name]);
69
70
            if (!$this->isWithinGroup($context, $denormalizingFieldMapping)) {
71
                continue;
72
            }
73
74
            $subPath = $this->getSubPathByName($path, $name);
75
76
            $fieldDenormalizer->denormalizeField($subPath, $object, $value, $this, $context);
77
        }
78
79
        if ([] !== $data && !$context->isAllowedAdditionalFields()) {
80
            throw DenormalizerException::createNotAllowedAddtionalFields(
81
                $this->getSubPathsByNames($path, array_keys($data))
82
            );
83
        }
84
85
        return $object;
86
    }
87
88
    /**
89
     * @param string $class
90
     *
91
     * @return DenormalizingObjectMappingInterface
92
     */
93
    private function getObjectMapping(string $class): DenormalizingObjectMappingInterface
94
    {
95
        if (isset($this->objectMappings[$class])) {
96
            return $this->objectMappings[$class];
97
        }
98
99
        throw DenormalizerException::createMissingMapping($class);
100
    }
101
102
    /**
103
     * @param DenormalizerContextInterface       $context
104
     * @param DenormalizingFieldMappingInterface $fieldMapping
105
     *
106
     * @return bool
107
     */
108
    private function isWithinGroup(
109
        DenormalizerContextInterface $context,
110
        DenormalizingFieldMappingInterface $fieldMapping
111
    ): bool {
112
        if ([] === $groups = $context->getGroups()) {
113
            return true;
114
        }
115
116
        foreach ($fieldMapping->getGroups() as $group) {
117
            if (in_array($group, $groups, true)) {
118
                return true;
119
            }
120
        }
121
122
        return false;
123
    }
124
125
    /**
126
     * @param string $path
127
     * @param string $name
128
     *
129
     * @return string
130
     */
131
    private function getSubPathByName(string $path, string $name): string
132
    {
133
        return '' === $path ? $name : $path.'.'.$name;
134
    }
135
136
    /**
137
     * @param string $path
138
     * @param array  $names
139
     *
140
     * @return array
141
     */
142
    private function getSubPathsByNames(string $path, array $names): array
143
    {
144
        $subPaths = [];
145
        foreach ($names as $name) {
146
            $subPaths[] = $this->getSubPathByName($path, $name);
147
        }
148
149
        return $subPaths;
150
    }
151
}
152