Test Failed
Push — master ( 851737...5a0e08 )
by Dominik
01:50
created

Normalizer::isWithinGroup()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.2
c 0
b 0
f 0
cc 4
eloc 10
nc 4
nop 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\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
     * @return array
42
     */
43
    public function normalize($object, NormalizerContextInterface $context = null, string $path = ''): array
44
    {
45
        $this->validateDataType($object, $path);
46
47
        $context = $context ?? NormalizerContextBuilder::create()->getContext();
48
49
        $class = is_object($object) ? get_class($object) : $object;
50
        $objectMapping = $this->getObjectMapping($class);
51
52
        $fields = [];
53
        foreach ($objectMapping->getNormalizationFieldMappings($path) as $normalizationFieldMapping) {
54
            $this->normalizeField($context, $normalizationFieldMapping, $path, $fields, $object);
55
        }
56
57
        $embeddedFields = [];
58
        foreach ($objectMapping->getNormalizationEmbeddedFieldMappings($path) as $normalizationFieldMapping) {
59
            $this->normalizeField($context, $normalizationFieldMapping, $path, $embeddedFields, $object);
60
        }
61
62
        $links = [];
63
64
        $data = $fields;
65
66
        if ([] === $embeddedFields) {
67
            $data['_embedded'] = $embeddedFields;
68
        }
69
70
        if ([] === $links) {
71
            $data['_links'] = $links;
72
        }
73
74
        $data['_type'] = $objectMapping->getNormalizationType();
75
76
        return $data;
77
    }
78
79
    /**
80
     * @param object $object
81
     * @param string $path
82
     * @throws SerializerLogicException
83
     */
84
    private function validateDataType($object, string $path)
85
    {
86
        if (!is_object($object)) {
87
            $exception = SerializerLogicException::createWrongDataType(gettype($object), $path);
88
89
            $this->logger->error('serialize: {exception}', ['exception' => $exception->getMessage()]);
90
91
            throw $exception;
92
        }
93
    }
94
95
    /**
96
     * @param string $class
97
     *
98
     * @return NormalizationObjectMappingInterface
99
     *
100
     * @throws SerializerLogicException
101
     */
102
    private function getObjectMapping(string $class): NormalizationObjectMappingInterface
103
    {
104
        try {
105
            return $this->normalizerObjectMappingRegistry->getObjectMapping($class);
106
        } catch (SerializerLogicException $exception) {
107
            $this->logger->error('serialize: {exception}', ['exception' => $exception->getMessage()]);
108
109
            throw $exception;
110
        }
111
    }
112
113
    /**
114
     * @param NormalizerContextInterface $context
115
     * @param NormalizationFieldMappingInterface $normalizationFieldMapping
116
     * @param string $path
117
     * @param array $data
118
     * @param $object
119
     */
120
    private function normalizeField(
121
        NormalizerContextInterface $context,
122
        NormalizationFieldMappingInterface $normalizationFieldMapping,
123
        string $path,
124
        array &$data,
125
        $object
126
    ) {
127
        $fieldNormalizer = $normalizationFieldMapping->getFieldNormalizer();
128
129
        if (!$this->isWithinGroup($context, $normalizationFieldMapping)) {
130
            return;
131
        }
132
133
        $name = $normalizationFieldMapping->getName();
134
135
        $subPath = $this->getSubPathByName($path, $name);
136
137
        $this->logger->info('serialize: path {path}', ['path' => $subPath]);
138
139
        $data[$name] = $fieldNormalizer->normalizeField($subPath, $object, $context, $this);
140
    }
141
142
    /**
143
     * @param NormalizerContextInterface         $context
144
     * @param NormalizationFieldMappingInterface $fieldMapping
145
     *
146
     * @return bool
147
     */
148
    private function isWithinGroup(
149
        NormalizerContextInterface $context,
150
        NormalizationFieldMappingInterface $fieldMapping
151
    ): bool {
152
        if ([] === $groups = $context->getGroups()) {
153
            return true;
154
        }
155
156
        foreach ($fieldMapping->getGroups() as $group) {
157
            if (in_array($group, $groups, true)) {
158
                return true;
159
            }
160
        }
161
162
        return false;
163
    }
164
165
    /**
166
     * @param string $path
167
     * @param string $name
168
     *
169
     * @return string
170
     */
171
    private function getSubPathByName(string $path, string $name): string
172
    {
173
        return '' === $path ? $name : $path.'.'.$name;
174
    }
175
}
176