Test Failed
Push — master ( a73f17...e430c9 )
by Dominik
01:54
created

Normalizer::getDataByFieldNormalizationMappings()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 25
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 25
rs 8.8571
c 0
b 0
f 0
cc 3
eloc 16
nc 3
nop 4
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\NormalizationObjectMappingInterface;
9
use Chubbyphp\Serialization\SerializerLogicException;
10
use Psr\Log\LoggerInterface;
11
use Psr\Log\NullLogger;
12
13
final class Normalizer implements NormalizerInterface
14
{
15
    /**
16
     * @var NormalizerObjectMappingRegistryInterface
17
     */
18
    private $normalizerObjectMappingRegistry;
19
20
    /**
21
     * @var LoggerInterface
22
     */
23
    private $logger;
24
25
    /**
26
     * @param NormalizerObjectMappingRegistryInterface $normalizerObjectMappingRegistry
27
     * @param LoggerInterface|null                     $logger
28
     */
29
    public function __construct(
30
        NormalizerObjectMappingRegistryInterface $normalizerObjectMappingRegistry,
31
        LoggerInterface $logger = null
32
    ) {
33
        $this->normalizerObjectMappingRegistry = $normalizerObjectMappingRegistry;
34
        $this->logger = $logger ?? new NullLogger();
35
    }
36
37
    /**
38
     * @param object                          $object
39
     * @param NormalizerContextInterface|null $context
40
     * @param string                          $path
41
     *
42
     * @return array
43
     */
44
    public function normalize($object, NormalizerContextInterface $context = null, string $path = ''): array
45
    {
46
        $this->validateDataType($object, $path);
47
48
        $context = $context ?? NormalizerContextBuilder::create()->getContext();
49
50
        $class = is_object($object) ? get_class($object) : $object;
51
        $objectMapping = $this->getObjectMapping($class);
52
53
        $fields = $this->getDataByFieldNormalizationMappings(
54
            $context,
55
            $objectMapping->getNormalizationFieldMappings($path),
56
            $path,
57
            $object
58
        );
59
60
        $embeddedFields = $this->getDataByFieldNormalizationMappings(
61
            $context,
62
            $objectMapping->getNormalizationEmbeddedFieldMappings($path),
63
            $path,
64
            $object
65
        );
66
67
        $links = [];
68
69
        $data = $fields;
70
71
        if ([] === $embeddedFields) {
72
            $data['_embedded'] = $embeddedFields;
73
        }
74
75
        if ([] === $links) {
76
            $data['_links'] = $links;
77
        }
78
79
        $data['_type'] = $objectMapping->getNormalizationType();
80
81
        return $data;
82
    }
83
84
    /**
85
     * @param object $object
86
     * @param string $path
87
     *
88
     * @throws SerializerLogicException
89
     */
90
    private function validateDataType($object, string $path)
91
    {
92
        if (!is_object($object)) {
93
            $exception = SerializerLogicException::createWrongDataType(gettype($object), $path);
94
95
            $this->logger->error('serialize: {exception}', ['exception' => $exception->getMessage()]);
96
97
            throw $exception;
98
        }
99
    }
100
101
    /**
102
     * @param string $class
103
     *
104
     * @return NormalizationObjectMappingInterface
105
     *
106
     * @throws SerializerLogicException
107
     */
108
    private function getObjectMapping(string $class): NormalizationObjectMappingInterface
109
    {
110
        try {
111
            return $this->normalizerObjectMappingRegistry->getObjectMapping($class);
112
        } catch (SerializerLogicException $exception) {
113
            $this->logger->error('serialize: {exception}', ['exception' => $exception->getMessage()]);
114
115
            throw $exception;
116
        }
117
    }
118
119
    /**
120
     * @param NormalizerContextInterface           $context
121
     * @param NormalizationFieldMappingInterface[] $normalizationFieldMappings
122
     * @param string                               $path
123
     * @param $object
124
     *
125
     * @return array
126
     */
127
    private function getDataByFieldNormalizationMappings(
128
        NormalizerContextInterface $context,
129
        array $normalizationFieldMappings,
130
        string $path,
131
        $object
132
    ): array {
133
        $data = [];
134
        foreach ($normalizationFieldMappings as $normalizationFieldMapping) {
135
            $fieldNormalizer = $normalizationFieldMapping->getFieldNormalizer();
136
137
            if (!$this->isWithinGroup($context, $normalizationFieldMapping)) {
138
                continue;
139
            }
140
141
            $name = $normalizationFieldMapping->getName();
142
143
            $subPath = $this->getSubPathByName($path, $name);
144
145
            $this->logger->info('serialize: path {path}', ['path' => $subPath]);
146
147
            $data[$name] = $fieldNormalizer->normalizeField($subPath, $object, $context, $this);
148
        }
149
150
        return $data;
151
    }
152
153
    /**
154
     * @param NormalizerContextInterface         $context
155
     * @param NormalizationFieldMappingInterface $fieldMapping
156
     *
157
     * @return bool
158
     */
159
    private function isWithinGroup(
160
        NormalizerContextInterface $context,
161
        NormalizationFieldMappingInterface $fieldMapping
162
    ): bool {
163
        if ([] === $groups = $context->getGroups()) {
164
            return true;
165
        }
166
167
        foreach ($fieldMapping->getGroups() as $group) {
168
            if (in_array($group, $groups, true)) {
169
                return true;
170
            }
171
        }
172
173
        return false;
174
    }
175
176
    /**
177
     * @param string $path
178
     * @param string $name
179
     *
180
     * @return string
181
     */
182
    private function getSubPathByName(string $path, string $name): string
183
    {
184
        return '' === $path ? $name : $path.'.'.$name;
185
    }
186
}
187