Completed
Pull Request — master (#11)
by Eric
04:22
created

loadPropertyMetadataXmlEntry()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 15
Ratio 100 %

Code Coverage

Tests 10
CRAP Score 4

Importance

Changes 0
Metric Value
dl 15
loc 15
ccs 10
cts 10
cp 1
rs 9.2
c 0
b 0
f 0
cc 4
eloc 8
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 2256
    public function __construct(TypeParserInterface $typeParser = null)
40
    {
41 2256
        $this->typeParser = $typeParser ?: new TypeParser();
42 2256
    }
43
44
    /**
45
     * {@inheritdoc}
46
     */
47 1836
    public function loadClassMetadata(ClassMetadataInterface $classMetadata)
48
    {
49 1836
        $class = $classMetadata->getName();
50
51 1836
        if (!array_key_exists($class, $this->data)) {
52 1836
            $this->data[$class] = $this->loadData($class);
53 888
        }
54
55 1776
        if (!is_array($data = $this->data[$class])) {
56 24
            return false;
57
        }
58
59 1752
        $this->doLoadClassMetadata($classMetadata, $data);
60
61 1504
        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 1752
    private function doLoadClassMetadata(ClassMetadataInterface $classMetadata, array $data)
76
    {
77 1752
        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 1740
        $policy = $this->getExclusionPolicy($data);
85 1728
        $readableClass = $this->getReadable($data);
86 1720
        $writableClass = $this->getWritable($data);
87 1712
        $properties = $classMetadata->getProperties();
88
89 1712
        foreach ($data['properties'] as $property => $value) {
90 1712
            $propertyMetadata = $classMetadata->getProperty($property)
91 1712
                ?: new PropertyMetadata($property, $classMetadata->getName());
92
93 1712
            $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 1548
            if ($this->isPropertyMetadataExposed($value, $policy)) {
96 1548
                $properties[$property] = $propertyMetadata;
97 774
            } else {
98 822
                unset($properties[$property]);
99
            }
100 774
        }
101
102 1548
        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 1512
        $classMetadata->setProperties($properties);
107
108 1512
        if (array_key_exists('xml_root', $data)) {
109 104
            $this->loadClassMetadataXmlRoot($classMetadata, $data['xml_root']);
110 48
        }
111 1504
    }
112
113
    /**
114
     * @param PropertyMetadataInterface $propertyMetadata
115
     * @param mixed                     $data
116
     * @param bool                      $classReadable
117
     * @param bool                      $classWritable
118
     */
119 1712
    private function loadPropertyMetadata(
120
        PropertyMetadataInterface $propertyMetadata,
121
        $data,
122
        $classReadable,
123
        $classWritable
124
    ) {
125 1712
        if (!is_array($data)) {
126 64
            $data = [];
127 32
        }
128
129 1712
        $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 1700
        $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 1696
        if (array_key_exists('exclude', $data)) {
133 56
            $this->validatePropertyMetadataExclude($data['exclude']);
134 24
        }
135
136 1688
        if (array_key_exists('expose', $data)) {
137 56
            $this->validatePropertyMetadataExpose($data['expose']);
138 24
        }
139
140 1680
        if (array_key_exists('alias', $data)) {
141 156
            $this->loadPropertyMetadataAlias($propertyMetadata, $data['alias']);
142 72
        }
143
144 1668
        if (array_key_exists('type', $data)) {
145 1220
            $this->loadPropertyMetadataType($propertyMetadata, $data['type']);
146 604
        }
147
148 1656
        if (array_key_exists('accessor', $data)) {
149 60
            $this->loadPropertyMetadataAccessor($propertyMetadata, $data['accessor']);
150 24
        }
151
152 1644
        if (array_key_exists('mutator', $data)) {
153 60
            $this->loadPropertyMetadataMutator($propertyMetadata, $data['mutator']);
154 24
        }
155
156 1632
        if (array_key_exists('since', $data)) {
157 124
            $this->loadPropertyMetadataSinceVersion($propertyMetadata, $data['since']);
158 56
        }
159
160 1620
        if (array_key_exists('until', $data)) {
161 124
            $this->loadPropertyMetadataUntilVersion($propertyMetadata, $data['until']);
162 56
        }
163
164 1608
        if (array_key_exists('max_depth', $data)) {
165 88
            $this->loadPropertyMetadataMaxDepth($propertyMetadata, $data['max_depth']);
166 40
        }
167
168 1600
        if (array_key_exists('groups', $data)) {
169 140
            $this->loadPropertyMetadataGroups($propertyMetadata, $data['groups']);
170 64
        }
171
172 1588
        if (array_key_exists('xml_attribute', $data)) {
173 100
            $this->loadPropertyMetadataXmlAttribute($propertyMetadata, $data['xml_attribute']);
174 48
        }
175
176 1584
        if (array_key_exists('xml_value', $data)) {
177 56
            $this->loadPropertyMetadataXmlValue($propertyMetadata, $data['xml_value']);
178 24
        }
179
180 1576
        if (array_key_exists('xml_inline', $data)) {
181 52
            $this->loadPropertyMetadataXmlInline($propertyMetadata, $data['xml_inline']);
182
183 48
            if (!array_key_exists('xml_key_as_attribute', $data)) {
184 48
                $data['xml_key_as_attribute'] = true;
185 24
            }
186
187 48
            if (!array_key_exists('xml_key_as_node', $data)) {
188 48
                $data['xml_key_as_node'] = false;
189 24
            }
190 24
        }
191
192 1572
        if (array_key_exists('xml_entry', $data)) {
193 56
            $this->loadPropertyMetadataXmlEntry($propertyMetadata, $data['xml_entry']);
194 24
        }
195
196 1564
        if (array_key_exists('xml_entry_attribute', $data)) {
197 56
            $this->loadPropertyMetadataXmlEntryAttribute($propertyMetadata, $data['xml_entry_attribute']);
198 24
        }
199
200 1556
        if (array_key_exists('xml_key_as_attribute', $data)) {
201 52
            $this->loadPropertyMetadataXmlKeyAsAttribute($propertyMetadata, $data['xml_key_as_attribute']);
202 24
        }
203
204 1552
        if (array_key_exists('xml_key_as_node', $data)) {
205 52
            $this->loadPropertyMetadataXmlKeyAsNode($propertyMetadata, $data['xml_key_as_node']);
206 24
        }
207 1548
    }
208
209
    /**
210
     * @param ClassMetadataInterface $classMetadata
211
     * @param string                 $xmlRoot
212
     */
213 104 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
    {
215 104
        if (!is_string($xmlRoot)) {
216 4
            throw new \InvalidArgumentException(sprintf(
217 4
                'The mapping xml root must be a non empty string, got "%s".',
218 4
                is_object($xmlRoot) ? get_class($xmlRoot) : gettype($xmlRoot)
219 2
            ));
220
        }
221
222 100
        if (empty($xmlRoot)) {
223 4
            throw new \InvalidArgumentException('The mapping xml root must be a non empty string.');
224
        }
225
226 96
        $classMetadata->setXmlRoot($xmlRoot);
227 96
    }
228
229
    /**
230
     * @param PropertyMetadataInterface $propertyMetadata
231
     * @param string                    $alias
232
     */
233 156 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 156
        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 148
        $alias = trim($alias);
243
244 148
        if (empty($alias)) {
245 4
            throw new \InvalidArgumentException('The mapping property alias must be a non empty string.');
246
        }
247
248 144
        $propertyMetadata->setAlias($alias);
249 144
    }
250
251
    /**
252
     * @param PropertyMetadataInterface $propertyMetadata
253
     * @param string                    $type
254
     */
255 1220
    private function loadPropertyMetadataType(PropertyMetadataInterface $propertyMetadata, $type)
256
    {
257 1220
        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 1212
        $propertyMetadata->setType($this->typeParser->parse($type));
265 1208
    }
266
267
    /**
268
     * @param PropertyMetadataInterface $propertyMetadata
269
     * @param string                    $accessor
270
     */
271 60 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 60
        if (!is_string($accessor)) {
274 8
            throw new \InvalidArgumentException(sprintf(
275 8
                'The mapping property accessor must be a non empty string, got "%s".',
276 8
                is_object($accessor) ? get_class($accessor) : gettype($accessor)
277 4
            ));
278
        }
279
280 52
        $accessor = trim($accessor);
281
282 52
        if (empty($accessor)) {
283 4
            throw new \InvalidArgumentException('The mapping property accessor must be a non empty string.');
284
        }
285
286 48
        $propertyMetadata->setAccessor($accessor);
287 48
    }
288
289
    /**
290
     * @param PropertyMetadataInterface $propertyMetadata
291
     * @param string                    $mutator
292
     */
293 60 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 60
        if (!is_string($mutator)) {
296 8
            throw new \InvalidArgumentException(sprintf(
297 8
                'The mapping property mutator must be a non empty string, got "%s".',
298 8
                is_object($mutator) ? get_class($mutator) : gettype($mutator)
299 4
            ));
300
        }
301
302 52
        $mutator = trim($mutator);
303
304 52
        if (empty($mutator)) {
305 4
            throw new \InvalidArgumentException('The mapping property mutator must be a non empty string.');
306
        }
307
308 48
        $propertyMetadata->setMutator($mutator);
309 48
    }
310
311
    /**
312
     * @param PropertyMetadataInterface $propertyMetadata
313
     * @param string                    $version
314
     */
315 124 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 124
        if (!is_string($version)) {
318 8
            throw new \InvalidArgumentException(sprintf(
319 8
                'The mapping property since version must be a non empty string, got "%s".',
320 8
                is_object($version) ? get_class($version) : gettype($version)
321 4
            ));
322
        }
323
324 116
        $version = trim($version);
325
326 116
        if (empty($version)) {
327 4
            throw new \InvalidArgumentException('The mapping property since version must be a non empty string.');
328
        }
329
330 112
        $propertyMetadata->setSinceVersion($version);
331 112
    }
332
333
    /**
334
     * @param PropertyMetadataInterface $propertyMetadata
335
     * @param string                    $version
336
     */
337 124 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
    {
339 124
        if (!is_string($version)) {
340 8
            throw new \InvalidArgumentException(sprintf(
341 8
                'The mapping property until version must be a non empty string, got "%s".',
342 8
                is_object($version) ? get_class($version) : gettype($version)
343 4
            ));
344
        }
345
346 116
        $version = trim($version);
347
348 116
        if (empty($version)) {
349 4
            throw new \InvalidArgumentException('The mapping property until version must be a non empty string.');
350
        }
351
352 112
        $propertyMetadata->setUntilVersion($version);
353 112
    }
354
355
    /**
356
     * @param PropertyMetadataInterface $propertyMetadata
357
     * @param string|int                $maxDepth
358
     */
359 88
    private function loadPropertyMetadataMaxDepth(PropertyMetadataInterface $propertyMetadata, $maxDepth)
360
    {
361 88
        if (!is_int($maxDepth) && !is_string($maxDepth) && !ctype_digit($maxDepth)) {
362 4
            throw new \InvalidArgumentException(sprintf(
363 4
                'The mapping property max depth must be a positive integer, got "%s".',
364 4
                is_object($maxDepth) ? get_class($maxDepth) : gettype($maxDepth)
365 2
            ));
366
        }
367
368 84
        $maxDepth = (int) $maxDepth;
369
370 84
        if ($maxDepth <= 0) {
371 4
            throw new \InvalidArgumentException(sprintf(
372 4
                'The mapping property max depth must be a positive integer, got "%d".',
373
                $maxDepth
374 2
            ));
375
        }
376
377 80
        $propertyMetadata->setMaxDepth($maxDepth);
378 80
    }
379
380
    /**
381
     * @param PropertyMetadataInterface $propertyMetadata
382
     * @param string[]                  $groups
383
     */
384 140
    private function loadPropertyMetadataGroups(PropertyMetadataInterface $propertyMetadata, $groups)
385
    {
386 140
        if (!is_array($groups)) {
387 4
            throw new \InvalidArgumentException(sprintf(
388 4
                'The mapping property groups must be an array of non empty strings, got "%s".',
389 4
                is_object($groups) ? get_class($groups) : gettype($groups)
390 2
            ));
391
        }
392
393 136
        foreach ($groups as $group) {
394 136
            if (!is_string($group)) {
395 4
                throw new \InvalidArgumentException(sprintf(
396 4
                    'The mapping property groups must be an array of non empty strings, got "%s".',
397 4
                    is_object($group) ? get_class($group) : gettype($group)
398 2
                ));
399
            }
400
401 132
            $group = trim($group);
402
403 132
            if (empty($group)) {
404 4
                throw new \InvalidArgumentException(
405 2
                    'The mapping property groups must be an array of non empty strings.'
406 2
                );
407
            }
408
409 128
            $propertyMetadata->addGroup($group);
410 64
        }
411 128
    }
412
413
    /**
414
     * @param PropertyMetadataInterface $propertyMetadata
415
     * @param bool                      $xmlAttribute
416
     */
417 100 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 100
        if (!is_bool($xmlAttribute)) {
420 4
            throw new \InvalidArgumentException(sprintf(
421 4
                'The mapping property xml attribute must be a boolean, got "%s".',
422 4
                is_object($xmlAttribute) ? get_class($xmlAttribute) : gettype($xmlAttribute)
423 2
            ));
424
        }
425
426 96
        $propertyMetadata->setXmlAttribute($xmlAttribute);
427 96
    }
428
429
    /**
430
     * @param PropertyMetadataInterface $propertyMetadata
431
     * @param bool                      $xmlValue
432
     */
433 56 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
    {
435 56
        if (!is_bool($xmlValue)) {
436 8
            throw new \InvalidArgumentException(sprintf(
437 8
                'The mapping property xml value must be a boolean, got "%s".',
438 8
                is_object($xmlValue) ? get_class($xmlValue) : gettype($xmlValue)
439 4
            ));
440
        }
441
442 48
        $propertyMetadata->setXmlValue($xmlValue);
443 48
    }
444
445
    /**
446
     * @param PropertyMetadataInterface $propertyMetadata
447
     * @param bool                      $xmlInline
448
     */
449 52 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 52
        if (!is_bool($xmlInline)) {
452 4
            throw new \InvalidArgumentException(sprintf(
453 4
                'The mapping property xml inline must be a boolean, got "%s".',
454 4
                is_object($xmlInline) ? get_class($xmlInline) : gettype($xmlInline)
455 2
            ));
456
        }
457
458 48
        $propertyMetadata->setXmlInline($xmlInline);
459 48
    }
460
461
    /**
462
     * @param PropertyMetadataInterface $propertyMetadata
463
     * @param string                    $xmlEntry
464
     */
465 56 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
    {
467 56
        if (!is_string($xmlEntry)) {
468 4
            throw new \InvalidArgumentException(sprintf(
469 4
                'The mapping property xml entry must be a non empty string, got "%s".',
470 4
                is_object($xmlEntry) ? get_class($xmlEntry) : gettype($xmlEntry)
471 2
            ));
472
        }
473
474 52
        if (empty($xmlEntry)) {
475 4
            throw new \InvalidArgumentException('The mapping property xml entry must be a non empty string.');
476
        }
477
478 48
        $propertyMetadata->setXmlEntry($xmlEntry);
479 48
    }
480
481
    /**
482
     * @param PropertyMetadataInterface $propertyMetadata
483
     * @param string                    $xmlEntryAttribute
484
     */
485 56 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
        $xmlEntryAttribute
488
    ) {
489 56
        if (!is_string($xmlEntryAttribute)) {
490 4
            throw new \InvalidArgumentException(sprintf(
491 4
                'The mapping property xml entry attribute must be a non empty string, got "%s".',
492 4
                is_object($xmlEntryAttribute) ? get_class($xmlEntryAttribute) : gettype($xmlEntryAttribute)
493 2
            ));
494
        }
495
496 52
        if (empty($xmlEntryAttribute)) {
497 4
            throw new \InvalidArgumentException(
498 2
                'The mapping property xml entry attribute must be a non empty string.'
499 2
            );
500
        }
501
502 48
        $propertyMetadata->setXmlEntryAttribute($xmlEntryAttribute);
503 48
    }
504
505
    /**
506
     * @param PropertyMetadataInterface $propertyMetadata
507
     * @param string                    $xmlKeyAsAttribute
508
     */
509 52 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
        PropertyMetadataInterface $propertyMetadata,
511
        $xmlKeyAsAttribute
512
    ) {
513 52
        if (!is_bool($xmlKeyAsAttribute)) {
514 4
            throw new \InvalidArgumentException(sprintf(
515 4
                'The mapping property xml key as attribute must be a boolean, got "%s".',
516 4
                is_object($xmlKeyAsAttribute) ? get_class($xmlKeyAsAttribute) : gettype($xmlKeyAsAttribute)
517 2
            ));
518
        }
519
520 48
        $propertyMetadata->setXmlKeyAsAttribute($xmlKeyAsAttribute);
521 48
    }
522
523
    /**
524
     * @param PropertyMetadataInterface $propertyMetadata
525
     * @param string                    $xmlKeyAsNode
526
     */
527 52 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
    {
529 52
        if (!is_bool($xmlKeyAsNode)) {
530 4
            throw new \InvalidArgumentException(sprintf(
531 4
                'The mapping property xml key as node must be a boolean, got "%s".',
532 4
                is_object($xmlKeyAsNode) ? get_class($xmlKeyAsNode) : gettype($xmlKeyAsNode)
533 2
            ));
534
        }
535
536 48
        $propertyMetadata->setXmlKeyAsNode($xmlKeyAsNode);
537 48
    }
538
539
    /**
540
     * @param mixed[] $data
541
     *
542
     * @return string|null
543
     */
544 1740
    private function getExclusionPolicy(array $data)
545
    {
546 1740
        if (!isset($data['exclusion_policy'])) {
547 1696
            return ExclusionPolicy::NONE;
548
        }
549
550 108
        $policy = $data['exclusion_policy'];
551
552 108
        if (!is_string($policy)) {
553 4
            throw new \InvalidArgumentException(sprintf(
554 4
                'The mapping exclusion policy must be "%s" or "%s", got "%s".',
555 4
                ExclusionPolicy::ALL,
556 4
                ExclusionPolicy::NONE,
557 4
                is_object($policy) ? get_class($policy) : gettype($policy)
558 2
            ));
559
        }
560
561 104
        $policy = strtolower(trim($policy));
562
563 104
        if ($policy !== ExclusionPolicy::ALL && $policy !== ExclusionPolicy::NONE) {
564 8
            throw new \InvalidArgumentException(sprintf(
565 8
                'The mapping exclusion policy must be "%s" or "%s", got "%s".',
566 8
                ExclusionPolicy::ALL,
567 8
                ExclusionPolicy::NONE,
568
                $policy
569 4
            ));
570
        }
571
572 96
        return $policy;
573
    }
574
575
    /**
576
     * @param mixed[] $data
577
     * @param bool    $default
578
     *
579
     * @return bool|null
580
     */
581 1728 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 1728
        if (!array_key_exists('readable', $data)) {
584 1720
            return $default;
585
        }
586
587 116
        $readable = $data['readable'];
588
589 116
        if (!is_bool($readable)) {
590 20
            throw new \InvalidArgumentException(sprintf(
591 20
                'The mapping readable must be a boolean, got "%s".',
592 20
                is_object($readable) ? get_class($readable) : gettype($readable)
593 10
            ));
594
        }
595
596 96
        return $readable;
597
    }
598
599
    /**
600
     * @param mixed[] $data
601
     * @param bool    $default
602
     *
603
     * @return bool|null
604
     */
605 1720 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 1720
        if (!array_key_exists('writable', $data)) {
608 1712
            return $default;
609
        }
610
611 108
        $writable = $data['writable'];
612
613 108
        if (!is_bool($writable)) {
614 12
            throw new \InvalidArgumentException(sprintf(
615 12
                'The mapping readable must be a boolean, got "%s".',
616 12
                is_object($writable) ? get_class($writable) : gettype($writable)
617 6
            ));
618
        }
619
620 96
        return $writable;
621
    }
622
623
    /**
624
     * @param mixed[]                     $data
625
     * @param PropertyMetadataInterface[] $properties
626
     *
627
     * @return string|string[]|null
628
     */
629 1548
    private function getOrder(array $data, array $properties)
630
    {
631 1548
        if (!isset($data['order'])) {
632 1464
            return;
633
        }
634
635 180
        $order = $data['order'];
636
637 180
        if (is_string($order)) {
638 112
            $order = trim($order);
639
640 112
            if (empty($order)) {
641 4
                throw new \InvalidArgumentException(
642 2
                    'The mapping order must be an non empty strings or an array of non empty strings.'
643 2
                );
644
            }
645
646 108
            if (strcasecmp($order, 'ASC') === 0 || strcasecmp($order, 'DESC') === 0) {
647 96
                return strtoupper($order);
648
            }
649
650 12
            $order = explode(',', $order);
651 74
        } elseif (!is_array($order)) {
652 4
            throw new \InvalidArgumentException(
653 2
                'The mapping order must be an non empty strings or an array of non empty strings.'
654 2
            );
655
        }
656
657 76
        if (empty($order)) {
658 8
            throw new \InvalidArgumentException(
659 4
                'The mapping order must be an non empty strings or an array of non empty strings.'
660 4
            );
661
        }
662
663 68
        foreach ($order as &$property) {
664 68
            if (!is_string($property)) {
665 4
                throw new \InvalidArgumentException(sprintf(
666 4
                    'The mapping order must be an non empty strings or an array of non empty strings, got "%s".',
667 4
                    is_object($property) ? get_class($property) : gettype($property)
668 2
                ));
669
            }
670
671 64
            $property = trim($property);
672
673 64
            if (empty($property)) {
674 8
                throw new \InvalidArgumentException(
675 4
                    'The mapping order must be an non empty strings or an array of non empty strings.'
676 4
                );
677
            }
678
679 56
            if (!isset($properties[$property])) {
680 8
                throw new \InvalidArgumentException(sprintf(
681 32
                    'The property "%s" defined in the mapping order does not exist.',
682
                    $property
683 4
                ));
684
            }
685 24
        }
686
687 48
        return $order;
688
    }
689
690
    /**
691
     * @param PropertyMetadataInterface[] $properties
692
     * @param string|string[]             $order
693
     *
694
     * @return PropertyMetadataInterface[]
695
     */
696 144
    private function sortProperties(array $properties, $order)
697
    {
698 144
        if (is_string($order)) {
699 96
            if ($order === 'ASC') {
700 48
                ksort($properties);
701 24
            } else {
702 72
                krsort($properties);
703
            }
704 96
        } elseif (is_array($order)) {
705 48
            $properties = array_merge(array_flip($order), $properties);
706 24
        }
707
708 144
        return $properties;
709
    }
710
711
    /**
712
     * @param bool $exclude
713
     */
714 56 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 56
        if (!is_bool($exclude)) {
717 8
            throw new \InvalidArgumentException(sprintf(
718 8
                'The mapping property exclude must be a boolean, got "%s".',
719 8
                is_object($exclude) ? get_class($exclude) : gettype($exclude)
720 4
            ));
721
        }
722 48
    }
723
724
    /**
725
     * @param bool $expose
726
     */
727 56 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 56
        if (!is_bool($expose)) {
730 8
            throw new \InvalidArgumentException(sprintf(
731 8
                'The mapping property expose must be a boolean, got "%s".',
732 8
                is_object($expose) ? get_class($expose) : gettype($expose)
733 4
            ));
734
        }
735 48
    }
736
737
    /**
738
     * @param mixed[] $property
739
     * @param string  $policy
740
     *
741
     * @return bool
742
     */
743 1548
    private function isPropertyMetadataExposed($property, $policy)
744
    {
745 1548
        $expose = isset($property['expose']) && $property['expose'];
746 1548
        $exclude = isset($property['exclude']) && $property['exclude'];
747
748 1548
        return ($policy === ExclusionPolicy::ALL && $expose) || ($policy === ExclusionPolicy::NONE && !$exclude);
749
    }
750
}
751