Completed
Push — master ( 3e05ae...99069b )
by Asmir
12s
created

ClassMetadata::merge()   C

Complexity

Conditions 14
Paths 67

Size

Total Lines 77
Code Lines 52

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 38
CRAP Score 18.4423

Importance

Changes 0
Metric Value
cc 14
eloc 52
nc 67
nop 1
dl 0
loc 77
ccs 38
cts 53
cp 0.717
crap 18.4423
rs 5.2115
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * Copyright 2016 Johannes M. Schmitt <[email protected]>
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
21
namespace JMS\Serializer\Metadata;
22
23
use JMS\Serializer\Exception\InvalidArgumentException;
24
use JMS\Serializer\Exception\LogicException;
25
use JMS\Serializer\Ordering\AlphabeticalPropertyOrderingStrategy;
26
use JMS\Serializer\Ordering\CustomPropertyOrderingStrategy;
27
use JMS\Serializer\Ordering\IdenticalPropertyOrderingStrategy;
28
use Metadata\MergeableClassMetadata;
29
use Metadata\MergeableInterface;
30
use Metadata\MethodMetadata;
31
use Metadata\PropertyMetadata as BasePropertyMetadata;
32
33
/**
34
 * Class Metadata used to customize the serialization process.
35
 *
36
 * @author Johannes M. Schmitt <[email protected]>
37
 */
38
class ClassMetadata extends MergeableClassMetadata
39
{
40
    const ACCESSOR_ORDER_UNDEFINED = 'undefined';
41
    const ACCESSOR_ORDER_ALPHABETICAL = 'alphabetical';
42
    const ACCESSOR_ORDER_CUSTOM = 'custom';
43
44
    /** @var \ReflectionMethod[] */
45
    public $preSerializeMethods = [];
46
47
    /** @var \ReflectionMethod[] */
48
    public $postSerializeMethods = [];
49
50
    /** @var \ReflectionMethod[] */
51
    public $postDeserializeMethods = [];
52
53
    public $xmlRootName;
54
    public $xmlRootNamespace;
55
    public $xmlRootPrefix;
56
    public $xmlNamespaces = [];
57
    public $accessorOrder;
58
    public $customOrder;
59
    public $usingExpression = false;
60
    public $isList = false;
61
    public $isMap = false;
62
63
    public $discriminatorDisabled = false;
64
    public $discriminatorBaseClass;
65
    public $discriminatorFieldName;
66
    public $discriminatorValue;
67
    public $discriminatorMap = [];
68
    public $discriminatorGroups = [];
69
70
    public $xmlDiscriminatorAttribute = false;
71
    public $xmlDiscriminatorCData = true;
72
    public $xmlDiscriminatorNamespace;
73
74 32
    public function setDiscriminator($fieldName, array $map, array $groups = []):void
75
    {
76 32
        if (empty($fieldName)) {
77
            throw new InvalidArgumentException('The $fieldName cannot be empty.');
78
        }
79
80 32
        if (empty($map)) {
81
            throw new InvalidArgumentException('The discriminator map cannot be empty.');
82
        }
83
84 32
        $this->discriminatorBaseClass = $this->name;
85 32
        $this->discriminatorFieldName = $fieldName;
86 32
        $this->discriminatorMap = $map;
87 32
        $this->discriminatorGroups = $groups;
88 32
    }
89
90 15
    private function getReflection(): \ReflectionClass
91
    {
92 15
        return new \ReflectionClass($this->name);
93
    }
94
95
    /**
96
     * Sets the order of properties in the class.
97
     *
98
     * @param string $order
99
     * @param array $customOrder
100
     *
101
     * @throws InvalidArgumentException When the accessor order is not valid
102
     * @throws InvalidArgumentException When the custom order is not valid
103
     */
104 39
    public function setAccessorOrder(string $order, array $customOrder = []):void
105
    {
106 39
        if (!in_array($order, [self::ACCESSOR_ORDER_UNDEFINED, self::ACCESSOR_ORDER_ALPHABETICAL, self::ACCESSOR_ORDER_CUSTOM], true)) {
107
            throw new InvalidArgumentException(sprintf('The accessor order "%s" is invalid.', $order));
108
        }
109
110 39
        foreach ($customOrder as $name) {
111 34
            if (!\is_string($name)) {
112 34
                throw new InvalidArgumentException(sprintf('$customOrder is expected to be a list of strings, but got element of value %s.', json_encode($name)));
113
            }
114
        }
115
116 39
        $this->accessorOrder = $order;
117 39
        $this->customOrder = array_flip($customOrder);
118 39
        $this->sortProperties();
119 39
    }
120
121 275
    public function addPropertyMetadata(BasePropertyMetadata $metadata):void
122
    {
123 275
        parent::addPropertyMetadata($metadata);
124 275
        $this->sortProperties();
125 275
        if ($metadata instanceof PropertyMetadata && $metadata->excludeIf) {
126 26
            $this->usingExpression = true;
127
        }
128 275
    }
129
130 2
    public function addPreSerializeMethod(MethodMetadata $method):void
131
    {
132 2
        $this->preSerializeMethods[] = $method;
133 2
    }
134
135 2
    public function addPostSerializeMethod(MethodMetadata $method):void
136
    {
137 2
        $this->postSerializeMethods[] = $method;
138 2
    }
139
140 4
    public function addPostDeserializeMethod(MethodMetadata $method):void
141
    {
142 4
        $this->postDeserializeMethods[] = $method;
143 4
    }
144
145 25
    public function merge(MergeableInterface $object):void
146
    {
147 25
        if (!$object instanceof ClassMetadata) {
148
            throw new InvalidArgumentException('$object must be an instance of ClassMetadata.');
149
        }
150 25
        parent::merge($object);
151
152 25
        $this->preSerializeMethods = array_merge($this->preSerializeMethods, $object->preSerializeMethods);
153 25
        $this->postSerializeMethods = array_merge($this->postSerializeMethods, $object->postSerializeMethods);
154 25
        $this->postDeserializeMethods = array_merge($this->postDeserializeMethods, $object->postDeserializeMethods);
155 25
        $this->xmlRootName = $object->xmlRootName;
156 25
        $this->xmlRootNamespace = $object->xmlRootNamespace;
157 25
        $this->xmlNamespaces = array_merge($this->xmlNamespaces, $object->xmlNamespaces);
158
159 25
        if ($object->accessorOrder) {
160 2
            $this->accessorOrder = $object->accessorOrder;
161 2
            $this->customOrder = $object->customOrder;
162
        }
163
164 25
        if ($object->discriminatorFieldName && $this->discriminatorFieldName) {
165
            throw new LogicException(sprintf(
166
                'The discriminator of class "%s" would overwrite the discriminator of the parent class "%s". Please define all possible sub-classes in the discriminator of %s.',
167
                $object->name,
168
                $this->discriminatorBaseClass,
169
                $this->discriminatorBaseClass
170
            ));
171 25
        } elseif (!$this->discriminatorFieldName && $object->discriminatorFieldName) {
172 2
            $this->discriminatorFieldName = $object->discriminatorFieldName;
173 2
            $this->discriminatorMap = $object->discriminatorMap;
174
        }
175
176 25
        if ($object->discriminatorDisabled !== null) {
177 25
            $this->discriminatorDisabled = $object->discriminatorDisabled;
178
        }
179
180 25
        if ($object->discriminatorMap) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $object->discriminatorMap of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
181 2
            $this->discriminatorFieldName = $object->discriminatorFieldName;
182 2
            $this->discriminatorMap = $object->discriminatorMap;
183 2
            $this->discriminatorBaseClass = $object->discriminatorBaseClass;
184
        }
185
186 25
        if ($this->discriminatorMap && !$this->getReflection()->isAbstract()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->discriminatorMap of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
187 15
            if (false === $typeValue = array_search($this->name, $this->discriminatorMap, true)) {
188
                throw new LogicException(sprintf(
189
                    'The sub-class "%s" is not listed in the discriminator of the base class "%s".',
190
                    $this->name,
191
                    $this->discriminatorBaseClass
192
                ));
193
            }
194
195 15
            $this->discriminatorValue = $typeValue;
196
197 15
            if (isset($this->propertyMetadata[$this->discriminatorFieldName])
198 15
                && !$this->propertyMetadata[$this->discriminatorFieldName] instanceof StaticPropertyMetadata
199
            ) {
200
                throw new LogicException(sprintf(
201
                    'The discriminator field name "%s" of the base-class "%s" conflicts with a regular property of the sub-class "%s".',
202
                    $this->discriminatorFieldName,
203
                    $this->discriminatorBaseClass,
204
                    $this->name
205
                ));
206
            }
207
208 15
            $discriminatorProperty = new StaticPropertyMetadata(
209 15
                $this->name,
210 15
                $this->discriminatorFieldName,
211 15
                $typeValue,
212 15
                $this->discriminatorGroups
213
            );
214 15
            $discriminatorProperty->serializedName = $this->discriminatorFieldName;
215 15
            $discriminatorProperty->xmlAttribute = $this->xmlDiscriminatorAttribute;
216 15
            $discriminatorProperty->xmlElementCData = $this->xmlDiscriminatorCData;
217 15
            $discriminatorProperty->xmlNamespace = $this->xmlDiscriminatorNamespace;
218 15
            $this->propertyMetadata[$this->discriminatorFieldName] = $discriminatorProperty;
219
        }
220
221 25
        $this->sortProperties();
222 25
    }
223
224 31
    public function registerNamespace(string $uri, ?string $prefix = null):void
225
    {
226 31
        if (!\is_string($uri)) {
0 ignored issues
show
introduced by
The condition is_string($uri) is always true.
Loading history...
227
            throw new InvalidArgumentException(sprintf('$uri is expected to be a strings, but got value %s.', json_encode($uri)));
228
        }
229
230 31
        if ($prefix !== null) {
231 31
            if (!\is_string($prefix)) {
0 ignored issues
show
introduced by
The condition is_string($prefix) is always true.
Loading history...
232 31
                throw new InvalidArgumentException(sprintf('$prefix is expected to be a strings, but got value %s.', json_encode($prefix)));
233
            }
234
        } else {
235 2
            $prefix = "";
236
        }
237
238 31
        $this->xmlNamespaces[$prefix] = $uri;
239 31
    }
240
241
    public function serialize()
242
    {
243
        $this->sortProperties();
244
245
        return serialize([
246
            $this->preSerializeMethods,
247
            $this->postSerializeMethods,
248
            $this->postDeserializeMethods,
249
            $this->xmlRootName,
250
            $this->xmlRootNamespace,
251
            $this->xmlNamespaces,
252
            $this->accessorOrder,
253
            $this->customOrder,
254
            $this->discriminatorDisabled,
255
            $this->discriminatorBaseClass,
256
            $this->discriminatorFieldName,
257
            $this->discriminatorValue,
258
            $this->discriminatorMap,
259
            $this->discriminatorGroups,
260
            parent::serialize(),
261
            'discriminatorGroups' => $this->discriminatorGroups,
262
            'xmlDiscriminatorAttribute' => $this->xmlDiscriminatorAttribute,
263
            'xmlDiscriminatorCData' => $this->xmlDiscriminatorCData,
264
            'usingExpression' => $this->usingExpression,
265
            'xmlDiscriminatorNamespace' => $this->xmlDiscriminatorNamespace,
266
            'isList' => $this->isList,
267
            'isMap' => $this->isMap,
268
        ]);
269
    }
270
271
    public function unserialize($str)
272
    {
273
        $unserialized = unserialize($str);
274
275
        list(
276
            $this->preSerializeMethods,
277
            $this->postSerializeMethods,
278
            $this->postDeserializeMethods,
279
            $this->xmlRootName,
280
            $this->xmlRootNamespace,
281
            $this->xmlNamespaces,
282
            $this->accessorOrder,
283
            $this->customOrder,
284
            $this->discriminatorDisabled,
285
            $this->discriminatorBaseClass,
286
            $this->discriminatorFieldName,
287
            $this->discriminatorValue,
288
            $this->discriminatorMap,
289
            $this->discriminatorGroups,
290
            $parentStr
291
            ) = $unserialized;
292
293
        if (isset($unserialized['discriminatorGroups'])) {
294
            $this->discriminatorGroups = $unserialized['discriminatorGroups'];
295
        }
296
        if (isset($unserialized['usingExpression'])) {
297
            $this->usingExpression = $unserialized['usingExpression'];
298
        }
299
300
        if (isset($unserialized['xmlDiscriminatorAttribute'])) {
301
            $this->xmlDiscriminatorAttribute = $unserialized['xmlDiscriminatorAttribute'];
302
        }
303
304
        if (isset($unserialized['xmlDiscriminatorNamespace'])) {
305
            $this->xmlDiscriminatorNamespace = $unserialized['xmlDiscriminatorNamespace'];
306
        }
307
308
        if (isset($unserialized['xmlDiscriminatorCData'])) {
309
            $this->xmlDiscriminatorCData = $unserialized['xmlDiscriminatorCData'];
310
        }
311
312
        if (isset($unserialized['isList'])) {
313
            $this->isList = $unserialized['isList'];
314
        }
315
        if (isset($unserialized['isMap'])) {
316
            $this->isMap = $unserialized['isMap'];
317
        }
318
        parent::unserialize($parentStr);
319
    }
320
321 279
    private function sortProperties()
322
    {
323 279
        switch ($this->accessorOrder) {
324 279
            case self::ACCESSOR_ORDER_UNDEFINED:
325
                $this->propertyMetadata = (new IdenticalPropertyOrderingStrategy())->order($this->propertyMetadata);
326
                break;
327
328 279
            case self::ACCESSOR_ORDER_ALPHABETICAL:
329 7
                $this->propertyMetadata = (new AlphabeticalPropertyOrderingStrategy())->order($this->propertyMetadata);
330 7
                break;
331
332 277
            case self::ACCESSOR_ORDER_CUSTOM:
333 34
                $this->propertyMetadata = (new CustomPropertyOrderingStrategy($this->customOrder))->order($this->propertyMetadata);
334 34
                break;
335
        }
336 279
    }
337
}
338
339