Completed
Pull Request — master (#11)
by Eric
65:27
created

loadPropertyMetadataAlias()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 17
Code Lines 9

Duplication

Lines 17
Ratio 100 %

Code Coverage

Tests 11
CRAP Score 4

Importance

Changes 0
Metric Value
dl 17
loc 17
ccs 11
cts 11
cp 1
rs 9.2
c 0
b 0
f 0
cc 4
eloc 9
nc 3
nop 2
crap 4
1
<?php
2
3
/*
4
 * This file is part of the Ivory Serializer package.
5
 *
6
 * (c) Eric GELOEN <[email protected]>
7
 *
8
 * For the full copyright and license information, please read the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Ivory\Serializer\Mapping\Loader;
13
14
use Ivory\Serializer\Exclusion\ExclusionPolicy;
15
use Ivory\Serializer\Mapping\ClassMetadataInterface;
16
use Ivory\Serializer\Mapping\PropertyMetadata;
17
use Ivory\Serializer\Mapping\PropertyMetadataInterface;
18
use Ivory\Serializer\Type\Parser\TypeParser;
19
use Ivory\Serializer\Type\Parser\TypeParserInterface;
20
21
/**
22
 * @author GeLo <[email protected]>
23
 */
24
abstract class AbstractClassMetadataLoader implements ClassMetadataLoaderInterface
25
{
26
    /**
27
     * @var TypeParserInterface
28
     */
29
    private $typeParser;
30
31
    /**
32
     * @var mixed[][]
33
     */
34
    private $data = [];
35
36
    /**
37
     * @param TypeParserInterface|null $typeParser
38
     */
39 2048
    public function __construct(TypeParserInterface $typeParser = null)
40
    {
41 2048
        $this->typeParser = $typeParser ?: new TypeParser();
42 2048
    }
43
44
    /**
45
     * {@inheritdoc}
46
     */
47 1664
    public function loadClassMetadata(ClassMetadataInterface $classMetadata)
48
    {
49 1664
        $class = $classMetadata->getName();
50
51 1664
        if (!array_key_exists($class, $this->data)) {
52 1664
            $this->data[$class] = $this->loadData($class);
53 816
        }
54
55 1632
        if (!is_array($data = $this->data[$class])) {
56 24
            return false;
57
        }
58
59 1608
        $this->doLoadClassMetadata($classMetadata, $data);
60
61 1408
        return true;
62
    }
63
64
    /**
65
     * @param string $class
66
     *
67
     * @return mixed[]|null
68
     */
69
    abstract protected function loadData($class);
70
71
    /**
72
     * @param ClassMetadataInterface $classMetadata
73
     * @param mixed[]                $data
74
     */
75 1608
    private function doLoadClassMetadata(ClassMetadataInterface $classMetadata, array $data)
76
    {
77 1608
        if (!isset($data['properties']) || empty($data['properties'])) {
78 12
            throw new \InvalidArgumentException(sprintf(
79 12
                'No mapping properties found for "%s".',
80 12
                $classMetadata->getName()
81 6
            ));
82
        }
83
84 1596
        $policy = $this->getExclusionPolicy($data);
85 1584
        $readableClass = $this->getReadable($data);
86 1576
        $writableClass = $this->getWritable($data);
87 1568
        $properties = $classMetadata->getProperties();
88
89 1568
        foreach ($data['properties'] as $property => $value) {
90 1568
            $propertyMetadata = $classMetadata->getProperty($property)
91 1568
                ?: new PropertyMetadata($property, $classMetadata->getName());
92
93 1568
            $this->loadPropertyMetadata($propertyMetadata, $value, $readableClass, $writableClass);
0 ignored issues
show
Bug introduced by
It seems like $readableClass defined by $this->getReadable($data) on line 85 can also be of type null; however, Ivory\Serializer\Mapping...:loadPropertyMetadata() does only seem to accept boolean, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug introduced by
It seems like $writableClass defined by $this->getWritable($data) on line 86 can also be of type null; however, Ivory\Serializer\Mapping...:loadPropertyMetadata() does only seem to accept boolean, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
94
95 1444
            if ($this->isPropertyMetadataExposed($value, $policy)) {
96 1444
                $properties[$property] = $propertyMetadata;
97 722
            } else {
98 770
                unset($properties[$property]);
99
            }
100 722
        }
101
102 1444
        if (($order = $this->getOrder($data, $properties)) !== null) {
103 144
            $properties = $this->sortProperties($properties, $order);
0 ignored issues
show
Bug introduced by
It seems like $order defined by $this->getOrder($data, $properties) on line 102 can also be of type array; however, Ivory\Serializer\Mapping...oader::sortProperties() does only seem to accept string|array<integer,string>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
104 72
        }
105
106 1408
        $classMetadata->setProperties($properties);
107 1408
108
        if (array_key_exists('xml_root', $data)) {
109
            $this->loadClassMetadataXmlRoot($classMetadata, $data['xml_root']);
110
        }
111
    }
112
113
    /**
114
     * @param PropertyMetadataInterface $propertyMetadata
115 1568
     * @param mixed                     $data
116
     * @param bool                      $classReadable
117
     * @param bool                      $classWritable
118
     */
119
    private function loadPropertyMetadata(
120
        PropertyMetadataInterface $propertyMetadata,
121 1568
        $data,
122 56
        $classReadable,
123 28
        $classWritable
124
    ) {
125 1568
        if (!is_array($data)) {
126 1556
            $data = [];
127
        }
128 1552
129 56
        $propertyMetadata->setReadable($this->getReadable($data, $classReadable));
0 ignored issues
show
Bug introduced by
It seems like $this->getReadable($data, $classReadable) targeting Ivory\Serializer\Mapping...taLoader::getReadable() can also be of type null; however, Ivory\Serializer\Mapping...nterface::setReadable() does only seem to accept boolean, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
130 24
        $propertyMetadata->setWritable($this->getWritable($data, $classWritable));
0 ignored issues
show
Bug introduced by
It seems like $this->getWritable($data, $classWritable) targeting Ivory\Serializer\Mapping...taLoader::getWritable() can also be of type null; however, Ivory\Serializer\Mapping...nterface::setWritable() does only seem to accept boolean, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
131
132 1544
        if (array_key_exists('exclude', $data)) {
133 56
            $this->validatePropertyMetadataExclude($data['exclude']);
134 24
        }
135
136 1536
        if (array_key_exists('expose', $data)) {
137 156
            $this->validatePropertyMetadataExpose($data['expose']);
138 72
        }
139
140 1524
        if (array_key_exists('alias', $data)) {
141 1156
            $this->loadPropertyMetadataAlias($propertyMetadata, $data['alias']);
142 572
        }
143
144 1512
        if (array_key_exists('type', $data)) {
145 60
            $this->loadPropertyMetadataType($propertyMetadata, $data['type']);
146 24
        }
147
148 1500
        if (array_key_exists('accessor', $data)) {
149 60
            $this->loadPropertyMetadataAccessor($propertyMetadata, $data['accessor']);
150 24
        }
151
152 1488
        if (array_key_exists('mutator', $data)) {
153 124
            $this->loadPropertyMetadataMutator($propertyMetadata, $data['mutator']);
154 56
        }
155
156 1476
        if (array_key_exists('since', $data)) {
157 124
            $this->loadPropertyMetadataSinceVersion($propertyMetadata, $data['since']);
158 56
        }
159
160 1464
        if (array_key_exists('until', $data)) {
161 88
            $this->loadPropertyMetadataUntilVersion($propertyMetadata, $data['until']);
162 40
        }
163
164 1456
        if (array_key_exists('max_depth', $data)) {
165 140
            $this->loadPropertyMetadataMaxDepth($propertyMetadata, $data['max_depth']);
166 64
        }
167 1444
168
        if (array_key_exists('groups', $data)) {
169
            $this->loadPropertyMetadataGroups($propertyMetadata, $data['groups']);
170
        }
171
172
        if (array_key_exists('xml_attribute', $data)) {
173 156
            $this->loadPropertyMetadataXmlAttribute($propertyMetadata, $data['xml_attribute']);
174
        }
175 156
176 8
        if (array_key_exists('xml_value', $data)) {
177 8
            $this->loadPropertyMetadataXmlValue($propertyMetadata, $data['xml_value']);
178 8
        }
179 4
180
        if (array_key_exists('xml_inline', $data)) {
181
            $this->loadPropertyMetadataXmlInline($propertyMetadata, $data['xml_inline']);
182 148
183
            if (!array_key_exists('xml_key_as_attribute', $data)) {
184 148
                $data['xml_key_as_attribute'] = true;
185 4
            }
186
187
            if (!array_key_exists('xml_key_as_node', $data)) {
188 144
                $data['xml_key_as_node'] = false;
189 144
            }
190
        }
191
192
        if (array_key_exists('xml_entry', $data)) {
193
            $this->loadPropertyMetadataXmlEntry($propertyMetadata, $data['xml_entry']);
194
        }
195 1156
196
        if (array_key_exists('xml_entry_attribute', $data)) {
197 1156
            $this->loadPropertyMetadataXmlEntryAttribute($propertyMetadata, $data['xml_entry_attribute']);
198 8
        }
199 8
200 8
        if (array_key_exists('xml_key_as_attribute', $data)) {
201 4
            $this->loadPropertyMetadataXmlKeyAsAttribute($propertyMetadata, $data['xml_key_as_attribute']);
202
        }
203
204 1148
        if (array_key_exists('xml_key_as_node', $data)) {
205 1144
            $this->loadPropertyMetadataXmlKeyAsNode($propertyMetadata, $data['xml_key_as_node']);
206
        }
207
    }
208
209
    /**
210
     * @param ClassMetadataInterface $classMetadata
211 60
     * @param string                 $xmlRoot
212
     */
213 60 View Code Duplication
    private function loadClassMetadataXmlRoot(ClassMetadataInterface $classMetadata, $xmlRoot)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
214 8
    {
215 8
        if (!is_string($xmlRoot)) {
216 8
            throw new \InvalidArgumentException(sprintf(
217 4
                'The mapping xml root must be a non empty string, got "%s".',
218
                is_object($xmlRoot) ? get_class($xmlRoot) : gettype($xmlRoot)
219
            ));
220 52
        }
221
222 52
        if (empty($xmlRoot)) {
223 4
            throw new \InvalidArgumentException('The mapping xml root must be a non empty string.');
224
        }
225
226 48
        $classMetadata->setXmlRoot($xmlRoot);
227 48
    }
228
229
    /**
230
     * @param PropertyMetadataInterface $propertyMetadata
231
     * @param string                    $alias
232
     */
233 60 View Code Duplication
    private function loadPropertyMetadataAlias(PropertyMetadataInterface $propertyMetadata, $alias)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
234
    {
235 60
        if (!is_string($alias)) {
236 8
            throw new \InvalidArgumentException(sprintf(
237 8
                'The mapping property alias must be a non empty string, got "%s".',
238 8
                is_object($alias) ? get_class($alias) : gettype($alias)
239 4
            ));
240
        }
241
242 52
        $alias = trim($alias);
243
244 52
        if (empty($alias)) {
245 4
            throw new \InvalidArgumentException('The mapping property alias must be a non empty string.');
246
        }
247
248 48
        $propertyMetadata->setAlias($alias);
249 48
    }
250
251
    /**
252
     * @param PropertyMetadataInterface $propertyMetadata
253
     * @param string                    $type
254
     */
255 124
    private function loadPropertyMetadataType(PropertyMetadataInterface $propertyMetadata, $type)
256
    {
257 124
        if (!is_string($type)) {
258 8
            throw new \InvalidArgumentException(sprintf(
259 8
                'The mapping property type must be a non empty string, got "%s".',
260 8
                is_object($type) ? get_class($type) : gettype($type)
261 4
            ));
262
        }
263
264 116
        $propertyMetadata->setType($this->typeParser->parse($type));
265
    }
266 116
267 4
    /**
268
     * @param PropertyMetadataInterface $propertyMetadata
269
     * @param string                    $accessor
270 112
     */
271 112 View Code Duplication
    private function loadPropertyMetadataAccessor(PropertyMetadataInterface $propertyMetadata, $accessor)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
272
    {
273
        if (!is_string($accessor)) {
274
            throw new \InvalidArgumentException(sprintf(
275
                'The mapping property accessor must be a non empty string, got "%s".',
276
                is_object($accessor) ? get_class($accessor) : gettype($accessor)
277 124
            ));
278
        }
279 124
280 8
        $accessor = trim($accessor);
281 8
282 8
        if (empty($accessor)) {
283 4
            throw new \InvalidArgumentException('The mapping property accessor must be a non empty string.');
284
        }
285
286 116
        $propertyMetadata->setAccessor($accessor);
287
    }
288 116
289 4
    /**
290
     * @param PropertyMetadataInterface $propertyMetadata
291
     * @param string                    $mutator
292 112
     */
293 112 View Code Duplication
    private function loadPropertyMetadataMutator(PropertyMetadataInterface $propertyMetadata, $mutator)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
294
    {
295
        if (!is_string($mutator)) {
296
            throw new \InvalidArgumentException(sprintf(
297
                'The mapping property mutator must be a non empty string, got "%s".',
298
                is_object($mutator) ? get_class($mutator) : gettype($mutator)
299 88
            ));
300
        }
301 88
302 4
        $mutator = trim($mutator);
303 4
304 4
        if (empty($mutator)) {
305 2
            throw new \InvalidArgumentException('The mapping property mutator must be a non empty string.');
306
        }
307
308 84
        $propertyMetadata->setMutator($mutator);
309
    }
310 84
311 4
    /**
312 4
     * @param PropertyMetadataInterface $propertyMetadata
313
     * @param string                    $version
314 2
     */
315 View Code Duplication
    private function loadPropertyMetadataSinceVersion(PropertyMetadataInterface $propertyMetadata, $version)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
316
    {
317 80
        if (!is_string($version)) {
318 80
            throw new \InvalidArgumentException(sprintf(
319
                'The mapping property since version must be a non empty string, got "%s".',
320
                is_object($version) ? get_class($version) : gettype($version)
321
            ));
322
        }
323
324 140
        $version = trim($version);
325
326 140
        if (empty($version)) {
327 4
            throw new \InvalidArgumentException('The mapping property since version must be a non empty string.');
328 4
        }
329 4
330 2
        $propertyMetadata->setSinceVersion($version);
331
    }
332
333 136
    /**
334 136
     * @param PropertyMetadataInterface $propertyMetadata
335 4
     * @param string                    $version
336 4
     */
337 4 View Code Duplication
    private function loadPropertyMetadataUntilVersion(PropertyMetadataInterface $propertyMetadata, $version)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
338 2
    {
339
        if (!is_string($version)) {
340
            throw new \InvalidArgumentException(sprintf(
341 132
                'The mapping property until version must be a non empty string, got "%s".',
342
                is_object($version) ? get_class($version) : gettype($version)
343 132
            ));
344 4
        }
345 2
346 2
        $version = trim($version);
347
348
        if (empty($version)) {
349 128
            throw new \InvalidArgumentException('The mapping property until version must be a non empty string.');
350 64
        }
351 128
352
        $propertyMetadata->setUntilVersion($version);
353
    }
354
355
    /**
356
     * @param PropertyMetadataInterface $propertyMetadata
357
     * @param string|int                $maxDepth
358 1596
     */
359
    private function loadPropertyMetadataMaxDepth(PropertyMetadataInterface $propertyMetadata, $maxDepth)
360 1596
    {
361 1552
        if (!is_int($maxDepth) && !is_string($maxDepth) && !ctype_digit($maxDepth)) {
362
            throw new \InvalidArgumentException(sprintf(
363
                'The mapping property max depth must be a positive integer, got "%s".',
364 108
                is_object($maxDepth) ? get_class($maxDepth) : gettype($maxDepth)
365
            ));
366 108
        }
367 4
368 4
        $maxDepth = (int) $maxDepth;
369 4
370 4
        if ($maxDepth <= 0) {
371 4
            throw new \InvalidArgumentException(sprintf(
372 2
                'The mapping property max depth must be a positive integer, got "%d".',
373
                $maxDepth
374
            ));
375 104
        }
376
377 104
        $propertyMetadata->setMaxDepth($maxDepth);
378 8
    }
379 8
380 8
    /**
381 8
     * @param PropertyMetadataInterface $propertyMetadata
382
     * @param string[]                  $groups
383 4
     */
384
    private function loadPropertyMetadataGroups(PropertyMetadataInterface $propertyMetadata, $groups)
385
    {
386 96
        if (!is_array($groups)) {
387
            throw new \InvalidArgumentException(sprintf(
388
                'The mapping property groups must be an array of non empty strings, got "%s".',
389
                is_object($groups) ? get_class($groups) : gettype($groups)
390
            ));
391
        }
392
393
        foreach ($groups as $group) {
394
            if (!is_string($group)) {
395 1584
                throw new \InvalidArgumentException(sprintf(
396
                    'The mapping property groups must be an array of non empty strings, got "%s".',
397 1584
                    is_object($group) ? get_class($group) : gettype($group)
398 1576
                ));
399
            }
400
401 116
            $group = trim($group);
402
403 116
            if (empty($group)) {
404 20
                throw new \InvalidArgumentException(
405 20
                    'The mapping property groups must be an array of non empty strings.'
406 20
                );
407 10
            }
408
409
            $propertyMetadata->addGroup($group);
410 96
        }
411
    }
412
413
    /**
414
     * @param PropertyMetadataInterface $propertyMetadata
415
     * @param bool                      $xmlAttribute
416
     */
417 View Code Duplication
    private function loadPropertyMetadataXmlAttribute(PropertyMetadataInterface $propertyMetadata, $xmlAttribute)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
418
    {
419 1576
        if (!is_bool($xmlAttribute)) {
420
            throw new \InvalidArgumentException(sprintf(
421 1576
                'The mapping property xml attribute must be a boolean, got "%s".',
422 1568
                is_object($xmlAttribute) ? get_class($xmlAttribute) : gettype($xmlAttribute)
423
            ));
424
        }
425 108
426
        $propertyMetadata->setXmlAttribute($xmlAttribute);
427 108
    }
428 12
429 12
    /**
430 12
     * @param PropertyMetadataInterface $propertyMetadata
431 6
     * @param bool                      $xmlValue
432
     */
433 View Code Duplication
    private function loadPropertyMetadataXmlValue(PropertyMetadataInterface $propertyMetadata, $xmlValue)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
434 96
    {
435
        if (!is_bool($xmlValue)) {
436
            throw new \InvalidArgumentException(sprintf(
437
                'The mapping property xml value must be a boolean, got "%s".',
438
                is_object($xmlValue) ? get_class($xmlValue) : gettype($xmlValue)
439
            ));
440
        }
441
442
        $propertyMetadata->setXmlValue($xmlValue);
443 1444
    }
444
445 1444
    /**
446 1360
     * @param PropertyMetadataInterface $propertyMetadata
447
     * @param bool                      $xmlInline
448
     */
449 180 View Code Duplication
    private function loadPropertyMetadataXmlInline(PropertyMetadataInterface $propertyMetadata, $xmlInline)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
450
    {
451 180
        if (!is_bool($xmlInline)) {
452 112
            throw new \InvalidArgumentException(sprintf(
453
                'The mapping property xml inline must be a boolean, got "%s".',
454 112
                is_object($xmlInline) ? get_class($xmlInline) : gettype($xmlInline)
455 4
            ));
456 2
        }
457 2
458
        $propertyMetadata->setXmlInline($xmlInline);
459
    }
460 108
461 96
    /**
462
     * @param PropertyMetadataInterface $propertyMetadata
463
     * @param string                    $xmlEntry
464 12
     */
465 74 View Code Duplication
    private function loadPropertyMetadataXmlEntry(PropertyMetadataInterface $propertyMetadata, $xmlEntry)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
466 4
    {
467 2
        if (!is_string($xmlEntry)) {
468 2
            throw new \InvalidArgumentException(sprintf(
469
                'The mapping property xml entry must be a non empty string, got "%s".',
470
                is_object($xmlEntry) ? get_class($xmlEntry) : gettype($xmlEntry)
471 76
            ));
472 8
        }
473 4
474 4
        if (empty($xmlEntry)) {
475
            throw new \InvalidArgumentException('The mapping property xml entry must be a non empty string.');
476
        }
477 68
478 68
        $propertyMetadata->setXmlEntry($xmlEntry);
479 4
    }
480 4
481 4
    /**
482 2
     * @param PropertyMetadataInterface $propertyMetadata
483
     * @param string                    $xmlEntryAttribute
484
     */
485 64 View Code Duplication
    private function loadPropertyMetadataXmlEntryAttribute(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
486
        PropertyMetadataInterface $propertyMetadata,
487 64
        $xmlEntryAttribute
488 8
    ) {
489 4
        if (!is_string($xmlEntryAttribute)) {
490 4
            throw new \InvalidArgumentException(sprintf(
491
                'The mapping property xml entry attribute must be a non empty string, got "%s".',
492
                is_object($xmlEntryAttribute) ? get_class($xmlEntryAttribute) : gettype($xmlEntryAttribute)
493 56
            ));
494 8
        }
495 32
496
        if (empty($xmlEntryAttribute)) {
497 4
            throw new \InvalidArgumentException(
498
                'The mapping property xml entry attribute must be a non empty string.'
499 24
            );
500
        }
501 48
502
        $propertyMetadata->setXmlEntryAttribute($xmlEntryAttribute);
503
    }
504
505
    /**
506
     * @param PropertyMetadataInterface $propertyMetadata
507
     * @param string                    $xmlKeyAsAttribute
508
     */
509 View Code Duplication
    private function loadPropertyMetadataXmlKeyAsAttribute(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
510 144
        PropertyMetadataInterface $propertyMetadata,
511
        $xmlKeyAsAttribute
512 144
    ) {
513 96
        if (!is_bool($xmlKeyAsAttribute)) {
514 48
            throw new \InvalidArgumentException(sprintf(
515 24
                'The mapping property xml key as attribute must be a boolean, got "%s".',
516 72
                is_object($xmlKeyAsAttribute) ? get_class($xmlKeyAsAttribute) : gettype($xmlKeyAsAttribute)
517
            ));
518 96
        }
519 48
520 24
        $propertyMetadata->setXmlKeyAsAttribute($xmlKeyAsAttribute);
521
    }
522 144
523
    /**
524
     * @param PropertyMetadataInterface $propertyMetadata
525
     * @param string                    $xmlKeyAsNode
526
     */
527 View Code Duplication
    private function loadPropertyMetadataXmlKeyAsNode(PropertyMetadataInterface $propertyMetadata, $xmlKeyAsNode)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
528 56
    {
529
        if (!is_bool($xmlKeyAsNode)) {
530 56
            throw new \InvalidArgumentException(sprintf(
531 8
                'The mapping property xml key as node must be a boolean, got "%s".',
532 8
                is_object($xmlKeyAsNode) ? get_class($xmlKeyAsNode) : gettype($xmlKeyAsNode)
533 8
            ));
534 4
        }
535
536 48
        $propertyMetadata->setXmlKeyAsNode($xmlKeyAsNode);
537
    }
538
539
    /**
540
     * @param mixed[] $data
541 56
     *
542
     * @return string|null
543 56
     */
544 8
    private function getExclusionPolicy(array $data)
545 8
    {
546 8
        if (!isset($data['exclusion_policy'])) {
547 4
            return ExclusionPolicy::NONE;
548
        }
549 48
550
        $policy = $data['exclusion_policy'];
551
552
        if (!is_string($policy)) {
553
            throw new \InvalidArgumentException(sprintf(
554
                'The mapping exclusion policy must be "%s" or "%s", got "%s".',
555
                ExclusionPolicy::ALL,
556
                ExclusionPolicy::NONE,
557 1444
                is_object($policy) ? get_class($policy) : gettype($policy)
558
            ));
559 1444
        }
560 1444
561
        $policy = strtolower(trim($policy));
562 1444
563
        if ($policy !== ExclusionPolicy::ALL && $policy !== ExclusionPolicy::NONE) {
564
            throw new \InvalidArgumentException(sprintf(
565
                'The mapping exclusion policy must be "%s" or "%s", got "%s".',
566
                ExclusionPolicy::ALL,
567
                ExclusionPolicy::NONE,
568
                $policy
569
            ));
570
        }
571
572
        return $policy;
573
    }
574
575
    /**
576
     * @param mixed[] $data
577
     * @param bool    $default
578
     *
579
     * @return bool|null
580
     */
581 View Code Duplication
    private function getReadable(array $data, $default = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
582
    {
583
        if (!array_key_exists('readable', $data)) {
584
            return $default;
585
        }
586
587
        $readable = $data['readable'];
588
589
        if (!is_bool($readable)) {
590
            throw new \InvalidArgumentException(sprintf(
591
                'The mapping readable must be a boolean, got "%s".',
592
                is_object($readable) ? get_class($readable) : gettype($readable)
593
            ));
594
        }
595
596
        return $readable;
597
    }
598
599
    /**
600
     * @param mixed[] $data
601
     * @param bool    $default
602
     *
603
     * @return bool|null
604
     */
605 View Code Duplication
    private function getWritable(array $data, $default = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
606
    {
607
        if (!array_key_exists('writable', $data)) {
608
            return $default;
609
        }
610
611
        $writable = $data['writable'];
612
613
        if (!is_bool($writable)) {
614
            throw new \InvalidArgumentException(sprintf(
615
                'The mapping readable must be a boolean, got "%s".',
616
                is_object($writable) ? get_class($writable) : gettype($writable)
617
            ));
618
        }
619
620
        return $writable;
621
    }
622
623
    /**
624
     * @param mixed[]                     $data
625
     * @param PropertyMetadataInterface[] $properties
626
     *
627
     * @return string|string[]|null
628
     */
629
    private function getOrder(array $data, array $properties)
630
    {
631
        if (!isset($data['order'])) {
632
            return;
633
        }
634
635
        $order = $data['order'];
636
637
        if (is_string($order)) {
638
            $order = trim($order);
639
640
            if (empty($order)) {
641
                throw new \InvalidArgumentException(
642
                    'The mapping order must be an non empty strings or an array of non empty strings.'
643
                );
644
            }
645
646
            if (strcasecmp($order, 'ASC') === 0 || strcasecmp($order, 'DESC') === 0) {
647
                return strtoupper($order);
648
            }
649
650
            $order = explode(',', $order);
651
        } elseif (!is_array($order)) {
652
            throw new \InvalidArgumentException(
653
                'The mapping order must be an non empty strings or an array of non empty strings.'
654
            );
655
        }
656
657
        if (empty($order)) {
658
            throw new \InvalidArgumentException(
659
                'The mapping order must be an non empty strings or an array of non empty strings.'
660
            );
661
        }
662
663
        foreach ($order as &$property) {
664
            if (!is_string($property)) {
665
                throw new \InvalidArgumentException(sprintf(
666
                    'The mapping order must be an non empty strings or an array of non empty strings, got "%s".',
667
                    is_object($property) ? get_class($property) : gettype($property)
668
                ));
669
            }
670
671
            $property = trim($property);
672
673
            if (empty($property)) {
674
                throw new \InvalidArgumentException(
675
                    'The mapping order must be an non empty strings or an array of non empty strings.'
676
                );
677
            }
678
679
            if (!isset($properties[$property])) {
680
                throw new \InvalidArgumentException(sprintf(
681
                    'The property "%s" defined in the mapping order does not exist.',
682
                    $property
683
                ));
684
            }
685
        }
686
687
        return $order;
688
    }
689
690
    /**
691
     * @param PropertyMetadataInterface[] $properties
692
     * @param string|string[]             $order
693
     *
694
     * @return PropertyMetadataInterface[]
695
     */
696
    private function sortProperties(array $properties, $order)
697
    {
698
        if (is_string($order)) {
699
            if ($order === 'ASC') {
700
                ksort($properties);
701
            } else {
702
                krsort($properties);
703
            }
704
        } elseif (is_array($order)) {
705
            $properties = array_merge(array_flip($order), $properties);
706
        }
707
708
        return $properties;
709
    }
710
711
    /**
712
     * @param bool $exclude
713
     */
714 View Code Duplication
    private function validatePropertyMetadataExclude($exclude)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
715
    {
716
        if (!is_bool($exclude)) {
717
            throw new \InvalidArgumentException(sprintf(
718
                'The mapping property exclude must be a boolean, got "%s".',
719
                is_object($exclude) ? get_class($exclude) : gettype($exclude)
720
            ));
721
        }
722
    }
723
724
    /**
725
     * @param bool $expose
726
     */
727 View Code Duplication
    private function validatePropertyMetadataExpose($expose)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
728
    {
729
        if (!is_bool($expose)) {
730
            throw new \InvalidArgumentException(sprintf(
731
                'The mapping property expose must be a boolean, got "%s".',
732
                is_object($expose) ? get_class($expose) : gettype($expose)
733
            ));
734
        }
735
    }
736
737
    /**
738
     * @param mixed[] $property
739
     * @param string  $policy
740
     *
741
     * @return bool
742
     */
743
    private function isPropertyMetadataExposed($property, $policy)
744
    {
745
        $expose = isset($property['expose']) && $property['expose'];
746
        $exclude = isset($property['exclude']) && $property['exclude'];
747
748
        return ($policy === ExclusionPolicy::ALL && $expose) || ($policy === ExclusionPolicy::NONE && !$exclude);
749
    }
750
}
751