Passed
Pull Request — master (#8)
by Pascal
03:27
created

Normalizer   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 205
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 0
loc 205
c 0
b 0
f 0
wmc 25
lcom 1
cbo 12
ccs 65
cts 65
cp 1
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
B normalize() 0 40 7
A validateDataType() 0 10 2
A getObjectMapping() 0 10 2
A getFieldsByFieldNormalizationMappings() 0 25 3
A getLinksByLinkNormalizationMappings() 0 23 4
A isWithinGroup() 0 14 4
A getSubPathByName() 0 4 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Chubbyphp\Serialization\Normalizer;
6
7
use Chubbyphp\Serialization\Mapping\EmbeddedNormalizationObjectMapping;
8
use Chubbyphp\Serialization\Mapping\LinkNormalizationObjectMapping;
9
use Chubbyphp\Serialization\Mapping\NormalizationFieldMappingInterface;
10
use Chubbyphp\Serialization\Mapping\NormalizationLinkMappingInterface;
11
use Chubbyphp\Serialization\Mapping\NormalizationObjectMappingInterface;
12
use Chubbyphp\Serialization\Mapping\TypeNormalizationObjectMapping;
13
use Chubbyphp\Serialization\SerializerLogicException;
14
use Psr\Log\LoggerInterface;
15
use Psr\Log\NullLogger;
16
17
final class Normalizer implements NormalizerInterface
18
{
19
    /**
20
     * @var NormalizerObjectMappingRegistryInterface
21
     */
22
    private $normalizerObjectMappingRegistry;
23
24
    /**
25
     * @var LoggerInterface
26
     */
27
    private $logger;
28
29
    /**
30
     * @param NormalizerObjectMappingRegistryInterface $normalizerObjectMappingRegistry
31
     * @param LoggerInterface|null                     $logger
32
     */
33 5
    public function __construct(
34
        NormalizerObjectMappingRegistryInterface $normalizerObjectMappingRegistry,
35
        LoggerInterface $logger = null
36
    ) {
37 5
        $this->normalizerObjectMappingRegistry = $normalizerObjectMappingRegistry;
38 5
        $this->logger = $logger ?? new NullLogger();
39 5
    }
40
41
    /**
42
     * @param object                          $object
43
     * @param NormalizerContextInterface|null $context
44
     * @param string                          $path
45
     *
46
     * @return array
47
     */
48 5
    public function normalize(
49
        $object,
50
        NormalizerContextInterface $context = null,
51
        string $path = ''
52
    ): array {
53 5
        $this->validateDataType($object, $path);
54
55 4
        $context = $context ?? NormalizerContextBuilder::create()->getContext();
56
57 4
        $class = is_object($object) ? get_class($object) : $object;
58 4
        $objectMapping = $this->getObjectMapping($class);
59
60 3
        $fieldMappings = $objectMapping->getNormalizationFieldMappings($path);
61
62 3
        $data = $this->getFieldsByFieldNormalizationMappings($context, $fieldMappings, $path, $object);
63
64 3
        if ($objectMapping instanceof EmbeddedNormalizationObjectMapping) {
65 3
            $embeddedMappings = $objectMapping->getNormalizationEmbeddedFieldMappings($path);
66 3
            $embedded = $this->getFieldsByFieldNormalizationMappings($context, $embeddedMappings, $path, $object);
67
68 3
            if ([] !== $embedded) {
69 2
                $data['_embedded'] = $embedded;
70
            }
71
        }
72
73 3
        if ($objectMapping instanceof LinkNormalizationObjectMapping) {
74 3
            $linkMappings = $objectMapping->getNormalizationLinkMappings($path);
75 3
            $links = $this->getLinksByLinkNormalizationMappings($context, $linkMappings, $path, $object);
76
77 3
            if ([] !== $links) {
78 1
                $data['_links'] = $links;
79
            }
80
        }
81
82 3
        if ($objectMapping instanceof TypeNormalizationObjectMapping) {
83 3
            $data['_type'] = $objectMapping->getNormalizationType();
84
        }
85
86 3
        return $data;
87
    }
88
89
    /**
90
     * @param object $object
91
     * @param string $path
92
     *
93
     * @throws SerializerLogicException
94
     */
95 5
    private function validateDataType($object, string $path)
96
    {
97 5
        if (!is_object($object)) {
98 1
            $exception = SerializerLogicException::createWrongDataType(gettype($object), $path);
99
100 1
            $this->logger->error('serialize: {exception}', ['exception' => $exception->getMessage()]);
101
102 1
            throw $exception;
103
        }
104 4
    }
105
106
    /**
107
     * @param string $class
108
     *
109
     * @return NormalizationObjectMappingInterface
110
     *
111
     * @throws SerializerLogicException
112
     */
113 4
    private function getObjectMapping(string $class): NormalizationObjectMappingInterface
114
    {
115
        try {
116 4
            return $this->normalizerObjectMappingRegistry->getObjectMapping($class);
117 1
        } catch (SerializerLogicException $exception) {
118 1
            $this->logger->error('serialize: {exception}', ['exception' => $exception->getMessage()]);
119
120 1
            throw $exception;
121
        }
122
    }
123
124
    /**
125
     * @param NormalizerContextInterface           $context
126
     * @param NormalizationFieldMappingInterface[] $normalizationFieldMappings
127
     * @param string                               $path
128
     * @param object                               $object
129
     *
130
     * @return array
131
     */
132 3
    private function getFieldsByFieldNormalizationMappings(
133
        NormalizerContextInterface $context,
134
        array $normalizationFieldMappings,
135
        string $path,
136
        $object
137
    ): array {
138 3
        $data = [];
139 3
        foreach ($normalizationFieldMappings as $normalizationFieldMapping) {
140 3
            if (!$this->isWithinGroup($context, $normalizationFieldMapping)) {
141 1
                continue;
142
            }
143
144 3
            $fieldNormalizer = $normalizationFieldMapping->getFieldNormalizer();
145
146 3
            $name = $normalizationFieldMapping->getName();
147
148 3
            $subPath = $this->getSubPathByName($path, $name);
149
150 3
            $this->logger->info('serialize: path {path}', ['path' => $subPath]);
151
152 3
            $data[$name] = $fieldNormalizer->normalizeField($subPath, $object, $context, $this);
153
        }
154
155 3
        return $data;
156
    }
157
158
    /**
159
     * @param NormalizerContextInterface          $context
160
     * @param NormalizationLinkMappingInterface[] $normalizationLinkMappings
161
     * @param string                              $path
162
     * @param object                              $object
163
     *
164
     * @return array
165
     */
166 3
    private function getLinksByLinkNormalizationMappings(
167
        NormalizerContextInterface $context,
168
        array $normalizationLinkMappings,
169
        string $path,
170
        $object
171
    ): array {
172 3
        $links = [];
173 3
        foreach ($normalizationLinkMappings as $normalizationLinkMapping) {
174 3
            if (!$this->isWithinGroup($context, $normalizationLinkMapping)) {
175 1
                continue;
176
            }
177
178 2
            $linkNormalizer = $normalizationLinkMapping->getLinkNormalizer();
179
180 2
            if (null === $link = $linkNormalizer->normalizeLink($path, $object, $context)) {
181 1
                continue;
182
            }
183
184 1
            $links[$normalizationLinkMapping->getName()] = $link;
185
        }
186
187 3
        return $links;
188
    }
189
190
    /**
191
     * @param NormalizerContextInterface                                           $context
192
     * @param NormalizationFieldMappingInterface|NormalizationLinkMappingInterface $mapping
193
     *
194
     * @return bool
195
     */
196 3
    private function isWithinGroup(NormalizerContextInterface $context, $mapping): bool
197
    {
198 3
        if ([] === $groups = $context->getGroups()) {
199 2
            return true;
200
        }
201
202 1
        foreach ($mapping->getGroups() as $group) {
203 1
            if (in_array($group, $groups, true)) {
204 1
                return true;
205
            }
206
        }
207
208 1
        return false;
209
    }
210
211
    /**
212
     * @param string $path
213
     * @param string $name
214
     *
215
     * @return string
216
     */
217 3
    private function getSubPathByName(string $path, string $name): string
218
    {
219 3
        return '' === $path ? $name : $path.'.'.$name;
220
    }
221
}
222