Passed
Pull Request — master (#15)
by
unknown
02:38
created

Normalizer::isCompliant()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 3
crap 2
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
     */
31 8
    public function __construct(
32
        NormalizerObjectMappingRegistryInterface $normalizerObjectMappingRegistry,
33
        LoggerInterface $logger = null
34
    ) {
35 8
        $this->normalizerObjectMappingRegistry = $normalizerObjectMappingRegistry;
36 8
        $this->logger = $logger ?? new NullLogger();
37 8
    }
38
39
    /**
40
     * @param object                          $object
41
     * @param NormalizerContextInterface|null $context
42
     * @param string                          $path
43
     *
44
     * @return array
45
     */
46 8
    public function normalize(
47
        $object,
48
        NormalizerContextInterface $context = null,
49
        string $path = ''
50
    ): array {
51 8
        $this->validateDataType($object, $path);
52
53 7
        $context = $context ?? NormalizerContextBuilder::create()->getContext();
54
55 7
        $class = is_object($object) ? get_class($object) : $object;
56 7
        $objectMapping = $this->getObjectMapping($class);
57
58 6
        $fieldMappings = $objectMapping->getNormalizationFieldMappings($path);
59
60 6
        $data = $this->getFieldsByFieldNormalizationMappings($context, $fieldMappings, $path, $object);
61
62 6
        $embeddedMappings = $objectMapping->getNormalizationEmbeddedFieldMappings($path);
63 6
        $embedded = $this->getFieldsByFieldNormalizationMappings($context, $embeddedMappings, $path, $object);
64
65 6
        $linkMappings = $objectMapping->getNormalizationLinkMappings($path);
66 6
        $links = $this->getLinksByLinkNormalizationMappings($context, $linkMappings, $path, $object);
67
68 6
        if ([] !== $embedded) {
69 3
            $data['_embedded'] = $embedded;
70
        }
71
72 6
        if ([] !== $links) {
73 3
            $data['_links'] = $links;
74
        }
75
76 6
        if (null !== $type = $objectMapping->getNormalizationType()) {
77 6
            $data['_type'] = $type;
78
        }
79
80 6
        return $data;
81
    }
82
83
    /**
84
     * @param object $object
85
     * @param string $path
86
     *
87
     * @throws SerializerLogicException
88
     */
89 8
    private function validateDataType($object, string $path)
90
    {
91 8
        if (!is_object($object)) {
92 1
            $exception = SerializerLogicException::createWrongDataType(gettype($object), $path);
93
94 1
            $this->logger->error('serialize: {exception}', ['exception' => $exception->getMessage()]);
95
96 1
            throw $exception;
97
        }
98 7
    }
99
100
    /**
101
     * @param string $class
102
     *
103
     * @return NormalizationObjectMappingInterface
104
     *
105
     * @throws SerializerLogicException
106
     */
107 7
    private function getObjectMapping(string $class): NormalizationObjectMappingInterface
108
    {
109
        try {
110 7
            return $this->normalizerObjectMappingRegistry->getObjectMapping($class);
111 1
        } catch (SerializerLogicException $exception) {
112 1
            $this->logger->error('serialize: {exception}', ['exception' => $exception->getMessage()]);
113
114 1
            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
     */
126 6
    private function getFieldsByFieldNormalizationMappings(
127
        NormalizerContextInterface $context,
128
        array $normalizationFieldMappings,
129
        string $path,
130
        $object
131
    ): array {
132 6
        $data = [];
133 6
        foreach ($normalizationFieldMappings as $normalizationFieldMapping) {
134 5
            if (!$this->isCompliant($context, $normalizationFieldMapping, $object)) {
135 1
                continue;
136
            }
137
138 4
            if (!$this->isWithinGroup($context, $normalizationFieldMapping)) {
139 1
                continue;
140
            }
141
142 3
            $fieldNormalizer = $normalizationFieldMapping->getFieldNormalizer();
143
144 3
            $name = $normalizationFieldMapping->getName();
145
146 3
            $subPath = $this->getSubPathByName($path, $name);
147
148 3
            $this->logger->info('serialize: path {path}', ['path' => $subPath]);
149
150 3
            $data[$name] = $fieldNormalizer->normalizeField($subPath, $object, $context, $this);
151
        }
152
153 6
        return $data;
154
    }
155
156
    /**
157
     * @param NormalizerContextInterface          $context
158
     * @param NormalizationLinkMappingInterface[] $normalizationLinkMappings
159
     * @param string                              $path
160
     * @param object                              $object
161
     *
162
     * @return array
163
     */
164 6
    private function getLinksByLinkNormalizationMappings(
165
        NormalizerContextInterface $context,
166
        array $normalizationLinkMappings,
167
        string $path,
168
        $object
169
    ): array {
170 6
        $links = [];
171 6
        foreach ($normalizationLinkMappings as $normalizationLinkMapping) {
172 6
            if (!$this->isCompliant($context, $normalizationLinkMapping, $object)) {
173 1
                continue;
174
            }
175
176 5
            if (!$this->isWithinGroup($context, $normalizationLinkMapping)) {
177 1
                continue;
178
            }
179
180 4
            $linkNormalizer = $normalizationLinkMapping->getLinkNormalizer();
181
182 4
            if (null === $link = $linkNormalizer->normalizeLink($path, $object, $context)) {
183 1
                continue;
184
            }
185
186 3
            $links[$normalizationLinkMapping->getName()] = $link;
187
        }
188
189 6
        return $links;
190
    }
191
192
    /**
193
     * @param NormalizerContextInterface                                           $context
194
     * @param NormalizationFieldMappingInterface|NormalizationLinkMappingInterface $mapping
195
     * @param object                                                               $object
196
     *
197
     * @return bool
198
     */
199 6
    private function isCompliant(NormalizerContextInterface $context, $mapping, $object): bool
200
    {
201 6
        if (!is_callable([$mapping, 'getPolicy'])) {
202 4
            return true;
203
        }
204
205 2
        return $mapping->getPolicy()->isCompliant($context, $object);
206
    }
207
208
    /**
209
     * @param NormalizerContextInterface                                           $context
210
     * @param NormalizationFieldMappingInterface|NormalizationLinkMappingInterface $mapping
211
     *
212
     * @return bool
213
     */
214 5
    private function isWithinGroup(NormalizerContextInterface $context, $mapping): bool
215
    {
216 5
        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 3
            return true;
218
        }
219
220 2
        @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 2
            sprintf(
222 2
                'Use "%s" instead of "%s::setGroups"',
223 2
                GroupPolicy::class,
224 2
                NormalizerContextInterface::class
225
            ),
226 2
            E_USER_DEPRECATED
227
        );
228
229 2
        foreach ($mapping->getGroups() as $group) {
230 2
            if (in_array($group, $groups, true)) {
231 2
                return true;
232
            }
233
        }
234
235 1
        return false;
236
    }
237
238
    /**
239
     * @param string $path
240
     * @param string $name
241
     *
242
     * @return string
243
     */
244 3
    private function getSubPathByName(string $path, string $name): string
245
    {
246 3
        return '' === $path ? $name : $path.'.'.$name;
247
    }
248
}
249