Test Failed
Push — master ( 13a00a...ad5f1c )
by Dominik
02:00
created

getFieldsByFieldNormalizationMappings()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 26
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 26
ccs 11
cts 11
cp 1
rs 8.8571
c 0
b 0
f 0
cc 3
eloc 17
nc 3
nop 5
crap 3
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\Http\Message\ServerRequestInterface as Request;
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
    /**
28
     * @param NormalizerObjectMappingRegistryInterface $normalizerObjectMappingRegistry
29
     * @param LoggerInterface|null                     $logger
30
     */
31 4
    public function __construct(
32
        NormalizerObjectMappingRegistryInterface $normalizerObjectMappingRegistry,
33
        LoggerInterface $logger = null
34
    ) {
35 4
        $this->normalizerObjectMappingRegistry = $normalizerObjectMappingRegistry;
36 4
        $this->logger = $logger ?? new NullLogger();
37 4
    }
38
39
    /**
40
     * @param Request                         $request
41
     * @param object                          $object
42
     * @param NormalizerContextInterface|null $context
43
     * @param string                          $path
44
     *
45
     * @return array
46
     */
47 4
    public function normalize(
48
        Request $request,
49
        $object,
50
        NormalizerContextInterface $context = null,
51
        string $path = ''
52
    ): array {
53 4
        $this->validateDataType($object, $path);
54
55 3
        $context = $context ?? NormalizerContextBuilder::create()->getContext();
56
57 3
        $class = is_object($object) ? get_class($object) : $object;
58 3
        $objectMapping = $this->getObjectMapping($class);
59
60 2
        $fieldMappings = $objectMapping->getNormalizationFieldMappings($path);
61
62 2
        $data = $this->getFieldsByFieldNormalizationMappings($context, $fieldMappings, $path, $request, $object);
63
64 2
        $embeddedMappings = $objectMapping->getNormalizationEmbeddedFieldMappings($path);
65 2
        $embedded = $this->getFieldsByFieldNormalizationMappings($context, $embeddedMappings, $path, $request, $object);
66
67 2
        $linkMappings = $objectMapping->getNormalizationLinkMappings($path);
68 2
        $links = $this->getLinksByLinkNormalizationMappings($context, $linkMappings, $path, $request, $object);
69
70 2
        if ([] !== $embedded) {
71 1
            $data['_embedded'] = $embedded;
72
        }
73
74 2
        if ([] !== $links) {
75
            $data['_links'] = $links;
76
        }
77
78 2
        $data['_type'] = $objectMapping->getNormalizationType();
79
80 2
        return $data;
81
    }
82
83
    /**
84
     * @param object $object
85
     * @param string $path
86
     *
87
     * @throws SerializerLogicException
88
     */
89 4
    private function validateDataType($object, string $path)
90
    {
91 4
        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 3
    }
99
100
    /**
101
     * @param string $class
102
     *
103
     * @return NormalizationObjectMappingInterface
104
     *
105
     * @throws SerializerLogicException
106
     */
107 3
    private function getObjectMapping(string $class): NormalizationObjectMappingInterface
108
    {
109
        try {
110 3
            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 Request                              $request
123
     * @param $object
124
     *
125
     * @return array
126
     */
127 2
    private function getFieldsByFieldNormalizationMappings(
128
        NormalizerContextInterface $context,
129
        array $normalizationFieldMappings,
130
        string $path,
131
        Request $request,
132
        $object
133
    ): array {
134 2
        $data = [];
135 2
        foreach ($normalizationFieldMappings as $normalizationFieldMapping) {
136 2
            if (!$this->isWithinGroup($context, $normalizationFieldMapping)) {
137 1
                continue;
138
            }
139
140 2
            $fieldNormalizer = $normalizationFieldMapping->getFieldNormalizer();
141
142 2
            $name = $normalizationFieldMapping->getName();
143
144 2
            $subPath = $this->getSubPathByName($path, $name);
145
146 2
            $this->logger->info('serialize: path {path}', ['path' => $subPath]);
147
148 2
            $data[$name] = $fieldNormalizer->normalizeField($subPath, $request, $object, $context, $this);
149
        }
150
151 2
        return $data;
152
    }
153
154
    /**
155
     * @param NormalizerContextInterface          $context
156
     * @param NormalizationLinkMappingInterface[] $normalizationLinkMappings
157
     * @param string                              $path
158
     * @param Request                             $request
159
     * @param object                              $object
160
     *
161
     * @return array
162
     */
163 2
    private function getLinksByLinkNormalizationMappings(
164
        NormalizerContextInterface $context,
165
        array $normalizationLinkMappings,
166
        string $path,
167
        Request $request,
168
        $object
169
    ): array {
170 2
        $links = [];
171 2
        foreach ($normalizationLinkMappings as $normalizationLinkMapping) {
172
            if (!$this->isWithinGroup($context, $normalizationLinkMapping)) {
173
                continue;
174
            }
175
176
            $linkNormalizer = $normalizationLinkMapping->getLinkNormalizer();
177
178
            if (null === $link = $linkNormalizer->normalizeLink($path, $request, $object, $context)) {
179
                continue;
180
            }
181
182
            $links[$normalizationLinkMapping->getName()] = $link;
183
        }
184
185 2
        return $links;
186
    }
187
188
    /**
189
     * @param NormalizerContextInterface                                           $context
190
     * @param NormalizationFieldMappingInterface|NormalizationLinkMappingInterface $mapping
191
     *
192
     * @return bool
193
     */
194 2
    private function isWithinGroup(NormalizerContextInterface $context, $mapping): bool
195
    {
196 2
        if ([] === $groups = $context->getGroups()) {
197 1
            return true;
198
        }
199
200 1
        foreach ($mapping->getGroups() as $group) {
201 1
            if (in_array($group, $groups, true)) {
202 1
                return true;
203
            }
204
        }
205
206 1
        return false;
207
    }
208
209
    /**
210
     * @param string $path
211
     * @param string $name
212
     *
213
     * @return string
214
     */
215 2
    private function getSubPathByName(string $path, string $name): string
216
    {
217 2
        return '' === $path ? $name : $path.'.'.$name;
218
    }
219
}
220