Test Failed
Pull Request — master (#15)
by
unknown
02:56
created

Normalizer::isWithinGroup()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

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

This method has been deprecated.

Loading history...
217
            return true;
218
        }
219
220
        @trigger_error(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
221
            sprintf(
222
                'Use "%s" instead of "%s::setGroups"',
223
                GroupPolicy::class,
224
                NormalizerContextInterface::class
225
            ),
226
            E_USER_DEPRECATED
227
        );
228
229
        foreach ($mapping->getGroups() as $group) {
230
            if (in_array($group, $groups, true)) {
231
                return true;
232
            }
233
        }
234
235
        return false;
236
    }
237
238
    /**
239
     * @param string $path
240
     * @param string $name
241
     *
242
     * @return string
243
     */
244
    private function getSubPathByName(string $path, string $name): string
245
    {
246
        return '' === $path ? $name : $path.'.'.$name;
247
    }
248
}
249