Normalizer::getSubPathByName()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 1
nc 2
nop 2
dl 0
loc 3
ccs 0
cts 0
cp 0
crap 6
rs 10
c 0
b 0
f 0
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\Policy\GroupPolicy;
11
use Chubbyphp\Serialization\SerializerLogicException;
12
use Psr\Log\LoggerInterface;
13
use Psr\Log\NullLogger;
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
    public function __construct(
28
        NormalizerObjectMappingRegistryInterface $normalizerObjectMappingRegistry,
29
        LoggerInterface $logger = null
30
    ) {
31 8
        $this->normalizerObjectMappingRegistry = $normalizerObjectMappingRegistry;
32
        $this->logger = $logger ?? new NullLogger();
33
    }
34
35 8
    /**
36 8
     * @param object $object
37 8
     */
38
    public function normalize(
39
        $object,
40
        NormalizerContextInterface $context = null,
41
        string $path = ''
42
    ): array {
43
        $this->validateDataType($object, $path);
44
45
        $context = $context ?? NormalizerContextBuilder::create()->getContext();
46 8
47
        $class = get_class($object);
48
        $objectMapping = $this->getObjectMapping($class);
49
50
        $fieldMappings = $objectMapping->getNormalizationFieldMappings($path);
51 8
52
        $data = $this->getFieldsByFieldNormalizationMappings($context, $fieldMappings, $path, $object);
53 7
54
        $embeddedMappings = $objectMapping->getNormalizationEmbeddedFieldMappings($path);
55 7
        $embedded = $this->getFieldsByFieldNormalizationMappings($context, $embeddedMappings, $path, $object);
56 7
57
        $linkMappings = $objectMapping->getNormalizationLinkMappings($path);
58 6
        $links = $this->getLinksByLinkNormalizationMappings($context, $linkMappings, $path, $object);
59
60 6
        if ([] !== $embedded) {
61
            $data['_embedded'] = $embedded;
62 6
        }
63 6
64
        if ([] !== $links) {
65 6
            $data['_links'] = $links;
66 6
        }
67
68 6
        if (null !== $type = $objectMapping->getNormalizationType()) {
69 3
            $data['_type'] = $type;
70
        }
71
72 6
        return $data;
73 3
    }
74
75
    /**
76 6
     * @param object $object
77 6
     *
78
     * @throws SerializerLogicException
79
     */
80 6
    private function validateDataType($object, string $path): void
81
    {
82
        if (!is_object($object)) {
83
            $exception = SerializerLogicException::createWrongDataType(gettype($object), $path);
84
85
            $this->logger->error('serialize: {exception}', ['exception' => $exception->getMessage()]);
86
87
            throw $exception;
88
        }
89 8
    }
90
91 8
    /**
92 1
     * @throws SerializerLogicException
93
     */
94 1
    private function getObjectMapping(string $class): NormalizationObjectMappingInterface
95
    {
96 1
        try {
97
            return $this->normalizerObjectMappingRegistry->getObjectMapping($class);
98 7
        } catch (SerializerLogicException $exception) {
99
            $this->logger->error('serialize: {exception}', ['exception' => $exception->getMessage()]);
100
101
            throw $exception;
102
        }
103
    }
104
105
    /**
106
     * @param NormalizationFieldMappingInterface[] $normalizationFieldMappings
107 7
     * @param object                               $object
108
     */
109
    private function getFieldsByFieldNormalizationMappings(
110 7
        NormalizerContextInterface $context,
111 1
        array $normalizationFieldMappings,
112 1
        string $path,
113
        $object
114 1
    ): array {
115
        $data = [];
116
        foreach ($normalizationFieldMappings as $normalizationFieldMapping) {
117
            if (!$this->isCompliant($context, $normalizationFieldMapping, $object)) {
118
                continue;
119
            }
120
121
            if (!$this->isWithinGroup($context, $normalizationFieldMapping)) {
122
                continue;
123
            }
124
125
            $fieldNormalizer = $normalizationFieldMapping->getFieldNormalizer();
126 6
127
            $name = $normalizationFieldMapping->getName();
128
129
            $subPath = $this->getSubPathByName($path, $name);
130
131
            $this->logger->info('serialize: path {path}', ['path' => $subPath]);
132 6
133 6
            $data[$name] = $fieldNormalizer->normalizeField($subPath, $object, $context, $this);
134 5
        }
135 1
136
        return $data;
137
    }
138 4
139 1
    /**
140
     * @param NormalizationLinkMappingInterface[] $normalizationLinkMappings
141
     * @param object                              $object
142 3
     */
143
    private function getLinksByLinkNormalizationMappings(
144 3
        NormalizerContextInterface $context,
145
        array $normalizationLinkMappings,
146 3
        string $path,
147
        $object
148 3
    ): array {
149
        $links = [];
150 3
        foreach ($normalizationLinkMappings as $normalizationLinkMapping) {
151
            if (!$this->isCompliant($context, $normalizationLinkMapping, $object)) {
152
                continue;
153 6
            }
154
155
            if (!$this->isWithinGroup($context, $normalizationLinkMapping)) {
156
                continue;
157
            }
158
159
            $linkNormalizer = $normalizationLinkMapping->getLinkNormalizer();
160
161
            if (null === $link = $linkNormalizer->normalizeLink($path, $object, $context)) {
162
                continue;
163
            }
164 6
165
            $links[$normalizationLinkMapping->getName()] = $link;
166
        }
167
168
        return $links;
169
    }
170 6
171 6
    /**
172 6
     * @param NormalizationFieldMappingInterface|NormalizationLinkMappingInterface $mapping
173 1
     * @param object                                                               $object
174
     */
175
    private function isCompliant(NormalizerContextInterface $context, $mapping, $object): bool
176 5
    {
177 1
        if (!is_callable([$mapping, 'getPolicy'])) {
178
            return true;
179
        }
180 4
181
        return $mapping->getPolicy()->isCompliant($context, $object);
0 ignored issues
show
Bug introduced by
The method getPolicy() does not exist on Chubbyphp\Serialization\...ionLinkMappingInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Chubbyphp\Serialization\...ionLinkMappingInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

181
        return $mapping->/** @scrutinizer ignore-call */ getPolicy()->isCompliant($context, $object);
Loading history...
Bug introduced by
The method getPolicy() does not exist on Chubbyphp\Serialization\...onFieldMappingInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Chubbyphp\Serialization\...onFieldMappingInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

181
        return $mapping->/** @scrutinizer ignore-call */ getPolicy()->isCompliant($context, $object);
Loading history...
182 4
    }
183 1
184
    /**
185
     * @param NormalizationFieldMappingInterface|NormalizationLinkMappingInterface $mapping
186 3
     */
187
    private function isWithinGroup(NormalizerContextInterface $context, $mapping): bool
188
    {
189 6
        if ([] === $groups = $context->getGroups()) {
0 ignored issues
show
Deprecated Code introduced by
The function Chubbyphp\Serialization\...tInterface::getGroups() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

189
        if ([] === $groups = /** @scrutinizer ignore-deprecated */ $context->getGroups()) {
Loading history...
190
            return true;
191
        }
192
193
        @trigger_error(
194
            sprintf(
195
                'Use "%s" instead of "%s::setGroups"',
196
                GroupPolicy::class,
197
                NormalizerContextInterface::class
198
            ),
199 6
            E_USER_DEPRECATED
200
        );
201 6
202 4
        foreach ($mapping->getGroups() as $group) {
0 ignored issues
show
Deprecated Code introduced by
The function Chubbyphp\Serialization\...gInterface::getGroups() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

202
        foreach (/** @scrutinizer ignore-deprecated */ $mapping->getGroups() as $group) {
Loading history...
Deprecated Code introduced by
The function Chubbyphp\Serialization\...gInterface::getGroups() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

202
        foreach (/** @scrutinizer ignore-deprecated */ $mapping->getGroups() as $group) {
Loading history...
203
            if (in_array($group, $groups, true)) {
204
                return true;
205 2
            }
206
        }
207
208
        return false;
209
    }
210
211
    private function getSubPathByName(string $path, string $name): string
212
    {
213
        return '' === $path ? $name : $path.'.'.$name;
214 5
    }
215
}
216