GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 0d846c...fab3df )
by Sergey
03:21
created

DataParser   D

Complexity

Total Complexity 91

Size/Duplication

Total Lines 630
Duplicated Lines 6.98 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 92.93%

Importance

Changes 5
Bugs 1 Features 0
Metric Value
wmc 91
c 5
b 1
f 0
lcom 1
cbo 9
dl 44
loc 630
ccs 289
cts 311
cp 0.9293
rs 4.7506

26 Methods

Rating   Name   Duplication   Size   Complexity  
B parseDateTime() 0 25 5
A __construct() 0 7 1
A setPath() 0 6 1
A restorePath() 0 6 1
A getPath() 0 9 2
A hasValue() 0 4 1
A getValue() 0 4 1
A parseString() 0 20 4
A parseInt() 0 4 1
A parseFloat() 0 4 1
A parseRaw() 13 13 2
A parseCallback() 13 13 2
C parseBool() 0 25 7
B parseArray() 0 27 6
B parseObject() 9 34 6
C parseResource() 9 47 8
B parseDocument() 0 37 4
A parseQueryParams() 0 4 1
A preparePathSegment() 0 4 1
A initPathStack() 0 4 1
C parseNumeric() 0 24 7
B parseProperty() 0 22 4
C parsePropertyValue() 0 30 7
A parseObjectValue() 0 10 2
B parseArrayValue() 0 59 7
C parseScalarValue() 0 22 8

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like DataParser often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use DataParser, and based on these observations, apply Extract Interface, too.

1
<?php
2
/*
3
 * This file is part of the reva2/jsonapi.
4
 *
5
 * (c) Sergey Revenko <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Reva2\JsonApi\Decoders;
12
13
use Neomerx\JsonApi\Document\Error;
14
use Neomerx\JsonApi\Exceptions\JsonApiException;
15
use Reva2\JsonApi\Contracts\Decoders\DataParserInterface;
16
use Reva2\JsonApi\Contracts\Decoders\Mapping\DocumentMetadataInterface;
17
use Reva2\JsonApi\Contracts\Decoders\Mapping\Factory\MetadataFactoryInterface;
18
use Reva2\JsonApi\Contracts\Decoders\Mapping\ObjectMetadataInterface;
19
use Reva2\JsonApi\Contracts\Decoders\Mapping\PropertyMetadataInterface;
20
use Reva2\JsonApi\Contracts\Decoders\Mapping\ResourceMetadataInterface;
21
use Symfony\Component\PropertyAccess\PropertyAccess;
22
use Symfony\Component\PropertyAccess\PropertyAccessor;
23
24
/**
25
 * Data parser
26
 *
27
 * @package Reva2\JsonApi\Decoders
28
 * @author Sergey Revenko <[email protected]>
29
 */
30
class DataParser implements DataParserInterface
31
{
32
    const ERROR_CODE = 'ee2c1d49-ba40-4077-a6bb-b06baceb3e97';
33
34
    /**
35
     * Current path
36
     *
37
     * @var \SplStack
38
     */
39
    protected $path;
40
41
    /**
42
     * Resource decoders factory
43
     *
44
     * @var MetadataFactoryInterface
45
     */
46
    protected $factory;
47
48
    /**
49
     * @var PropertyAccessor
50
     */
51
    protected $accessor;
52
53
    /**
54
     * Constructor
55
     *
56
     * @param MetadataFactoryInterface $factory
57
     */
58 10
    public function __construct(MetadataFactoryInterface $factory)
59
    {
60 10
        $this->factory = $factory;
61 10
        $this->accessor = PropertyAccess::createPropertyAccessor();
62
        
63 10
        $this->initPathStack();
64 10
    }
65
66
    /**
67
     * @inheritdoc
68
     */
69 10
    public function setPath($path)
70
    {
71 10
        $this->path->push($this->preparePathSegment($path));
72
73 10
        return $this;
74
    }
75
76
    /**
77
     * @inheritdoc
78
     */
79 10
    public function restorePath()
80
    {
81 10
        $this->path->pop();
82
83 10
        return $this;
84
    }
85
86
    /**
87
     * @inheritdoc
88
     */
89 1
    public function getPath()
90
    {
91 1
        $segments = [];
92 1
        foreach ($this->path as $segment) {
93 1
            $segments[] = $segment;
94 1
        }
95
96 1
        return '/' . implode('/', array_reverse($segments));
97
    }
98
99
    /**
100
     * @inheritdoc
101
     */
102 10
    public function hasValue($data, $path)
103
    {
104 10
        return $this->accessor->isReadable($data, $path);
105
    }
106
107
    /**
108
     * @inheritdoc
109
     */
110 10
    public function getValue($data, $path)
111
    {
112 10
        return $this->accessor->getValue($data, $path);
113
    }
114
115
    /**
116
     * @inheritdoc
117
     */
118 6
    public function parseString($data, $path)
119
    {
120 6
        $this->setPath($path);
121
122 6
        $pathValue = null;
123 6
        if ($this->hasValue($data, $path)) {
124 6
            $value = $this->getValue($data, $path);
125 6
            if ((null === $value) || (is_string($value))) {
126 6
                $pathValue = $value;
127 6
            } else {
128 1
                throw new \InvalidArgumentException(
129 1
                    sprintf("Value expected to be a string, but %s given", gettype($value)),
130
                    400
131 1
                );
132
            }
133 6
        }
134 6
        $this->restorePath();
135
136 6
        return $pathValue;
137
    }
138
139
    /**
140
     * @inheritdoc
141
     */
142 2
    public function parseInt($data, $path)
143
    {
144 2
        return $this->parseNumeric($data, $path, 'int');
145
    }
146
147
    /**
148
     * @inheritdoc
149
     */
150 2
    public function parseFloat($data, $path)
151
    {
152 2
        return $this->parseNumeric($data, $path, 'float');
153
    }
154
155
    /**
156
     * @inheritdoc
157
     */
158 1 View Code Duplication
    public function parseRaw($data, $path)
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...
159
    {
160 1
        $this->setPath($path);
161
162 1
        $pathValue = null;
163 1
        if ($this->hasValue($data, $path)) {
164 1
            $pathValue = $this->getValue($data, $path);
165 1
        }
166
167 1
        $this->restorePath();
168
169 1
        return $pathValue;
170
    }
171
172
    /**
173
     * @inheritdoc
174
     */
175 1 View Code Duplication
    public function parseCallback($data, $path, $callback)
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...
176
    {
177 1
        $this->setPath($path);
178
179 1
        $pathValue = null;
180 1
        if ($this->hasValue($data, $path)) {
181 1
            $pathValue = call_user_func($callback, $this->getValue($data, $path));
182 1
        }
183
184 1
        $this->restorePath();
185
186 1
        return $pathValue;
187
    }
188
189
    /**
190
     * @inheritdoc
191
     */
192 2
    public function parseBool($data, $path)
193
    {
194 2
        $this->setPath($path);
195
196 2
        $pathValue = null;
197 2
        if ($this->hasValue($data, $path)) {
198 2
            $value = $this->getValue($data, $path);
199 2
            if ((null === $value) || (is_bool($value))) {
200 1
                $pathValue = $value;
201 2
            } elseif (is_string($value)) {
202 2
                $pathValue = (in_array($value, ['true', 'yes', 'y', 'on', 'enabled'])) ? true : false;
203 2
            } elseif (is_numeric($value)) {
204 1
                $pathValue = (bool) $value;
205 1
            } else {
206 1
                throw new \InvalidArgumentException(
207 1
                    sprintf("Value expected to be a boolean, but %s given", gettype($value)),
208
                    400
209 1
                );
210
            }
211 2
        }
212
213 2
        $this->restorePath();
214
215 2
        return $pathValue;
216
    }
217
218
    /**
219
     * @inheritdoc
220
     */
221 2
    public function parseDateTime($data, $path, $format = 'Y-m-d')
222
    {
223 2
        $this->setPath($path);
224
225 2
        $pathValue = null;
226 2
        if ($this->hasValue($data, $path)) {
227 2
            $value = $this->getValue($data, $path);
228 2
            if (null !== $value) {
229 2
                if (is_string($value)) {
230 2
                    $pathValue = \DateTimeImmutable::createFromFormat($format, $value);
231 2
                }
232
233 2
                if (!$pathValue instanceof \DateTimeImmutable) {
234 1
                    throw new \InvalidArgumentException(
235 1
                        sprintf("Value expected to be a date/time string in '%s' format", $format),
236
                        400
237 1
                    );
238
                }
239 2
            }
240 2
        }
241
242 2
        $this->restorePath();
243
244 2
        return $pathValue;
245
    }
246
247
    /**
248
     * @inheritdoc
249
     */
250 5
    public function parseArray($data, $path, \Closure $itemsParser)
251
    {
252 4
        $this->setPath($path);
253
254 4
        $pathValue = null;
255 4
        if ($this->hasValue($data, $path)) {
256 4
            $value = $this->getValue($data, $path);
257 4
            if ((null !== $value) && (false === is_array($value))) {
258 1
                throw new \InvalidArgumentException(
259 1
                    sprintf("Value expected to be an array, but %s given", gettype($value)),
260
                    400
261 1
                );
262 4
            } elseif (is_array($value)) {
263 4
                $pathValue = [];
264 4
                $keys = array_keys($value);
265 5
                foreach ($keys as $key) {
266 4
                    $arrayPath = sprintf("[%s]", $key);
267
268 4
                    $pathValue[$key] = $itemsParser($value, $arrayPath, $this);
269 3
                }
270 3
            }
271 3
        }
272
273 3
        $this->restorePath();
274
275 3
        return $pathValue;
276
    }
277
278
    /**
279
     * Parse data object value at specified path as object of specified class
280
     *
281
     * @param array|object $data
282
     * @param string $path
283
     * @param string $objType
284
     * @return null
285
     */
286 1
    public function parseObject($data, $path, $objType)
287
    {
288 1
        $this->setPath($path);
289
290 1
        $pathValue = null;
291 1
        if ((true === $this->hasValue($data, $path)) &&
292 1
            (null !== ($value = $this->getValue($data, $path)))
293 1
        ) {
294 1
            $metadata = $this->factory->getMetadataFor($objType);
295
            /* @var $metadata ObjectMetadataInterface */
296
297 1 View Code Duplication
            if (null !== ($discField = $metadata->getDiscriminatorField())) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
298 1
                $discValue = $this->parseString($value, $discField->getDataPath());
299 1
                $discClass = $metadata->getDiscriminatorClass($discValue);
300 1
                if ($discClass !== $objType) {
301 1
                    $this->restorePath();
302
303 1
                    return $this->parseObject($data, $path, $discClass);
304
                }
305
            }
306
307 1
            $objClass = $metadata->getClassName();
308 1
            $pathValue = new $objClass();
309
310 1
            $properties = $metadata->getProperties();
311 1
            foreach ($properties as $property) {
312 1
                $this->parseProperty($value, $pathValue, $property);
313 1
            }
314 1
        }
315
316 1
        $this->restorePath();
317
318 1
        return $pathValue;
319
    }
320
321
    /**
322
     * @inheritdoc
323
     */
324 3
    public function parseResource($data, $path, $resType)
325
    {
326 3
        $this->setPath($path);
327
328 3
        $pathValue = null;
329 3
        if ((true === $this->hasValue($data, $path)) &&
330 3
            (null !== ($value = $this->getValue($data, $path)))
331 3
        ) {
332 3
            $metadata = $this->factory->getMetadataFor($resType);
333
            /* @var $metadata ResourceMetadataInterface */
334
335 3 View Code Duplication
            if ((null !== ($discField = $metadata->getDiscriminatorField()))) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
336 3
                $discValue = $this->parseString($value, $discField->getDataPath());
337 3
                $discClass = $metadata->getDiscriminatorClass($discValue);
338 3
                if ($discClass !== $resType) {
339 3
                    $this->restorePath();
340
341 3
                    return $this->parseResource($data, $path, $discClass);
342
                }
343
            }
344
345 3
            $name = $this->parseString($value, 'type');
346 3
            if ($name !== $metadata->getName()) {
347 1
                throw new \InvalidArgumentException(
348 1
                    sprintf("Value must contain resource of type '%s'", $metadata->getName()),
349
                    409
350 1
                );
351
            }
352
353 3
            $objClass = $metadata->getClassName();
354 3
            $pathValue = new $objClass();
355
356 3
            $this->parseProperty($value, $pathValue, $metadata->getIdMetadata());
357
358 3
            foreach ($metadata->getAttributes() as $attribute) {
359 3
                $this->parseProperty($value, $pathValue, $attribute);
360 3
            }
361
362 3
            foreach ($metadata->getRelationships() as $relationship) {
363 3
                $this->parseProperty($value, $pathValue, $relationship);
364 2
            }
365 2
        }
366
367 2
        $this->restorePath();
368
369 2
        return $pathValue;
370
    }
371
372
    /**
373
     * @inheritdoc
374
     */
375 2
    public function parseDocument($data, $docType)
376
    {
377
        try {
378 2
            $this->initPathStack();
379
380 2
            $metadata = $this->factory->getMetadataFor($docType);
381
            /* @var $metadata DocumentMetadataInterface */
382
383 2
            $docClass = $metadata->getClassName();
384 2
            $doc = new $docClass();
385
386 2
            $this->parseProperty($data, $doc, $metadata->getContentMetadata());
387
388 1
            return $doc;
389 1
        } catch (JsonApiException $e) {
390
            throw $e;
391 1
        } catch (\Exception $e) {
392 1
            $status = $e->getCode();
393 1
            $message = 'Failed to parse document';
394 1
            if (empty($status)) {
395
                $message = 'Internal server error';
396
                $status = 500;
397
            }
398
399 1
            $error = new Error(
400 1
                rand(),
401 1
                null,
402 1
                $status,
403 1
                self::ERROR_CODE,
404 1
                $message,
405 1
                $e->getMessage(),
406 1
                ['pointer' => $this->getPath()]
407 1
            );
408
409 1
            throw new JsonApiException($error, $status, $e);
410
        }
411
    }
412
413
    /**
414
     * @inheritdoc
415
     */
416
    public function parseQueryParams($data, $paramsType)
417
    {
418
        throw new \RuntimeException('Not implemented');
419
    }
420
421
    /**
422
     * Prepare path segment
423
     *
424
     * @param string $path
425
     * @return string
426
     */
427 10
    protected function preparePathSegment($path)
428
    {
429 10
        return trim(preg_replace('~[\/]+~si', '/', str_replace(['.', '[', ']'], '/', (string) $path)), '/');
430
    }
431
432
    /**
433
     * Initialize stack that store current path
434
     */
435 10
    protected function initPathStack()
436
    {
437 10
        $this->path = new \SplStack();
438 10
    }
439
440
    /**
441
     * Parse numeric value
442
     *
443
     * @param mixed $data
444
     * @param string $path
445
     * @param string $type
446
     * @return float|int|null
447
     */
448 3
    protected function parseNumeric($data, $path, $type)
449
    {
450 3
        $this->setPath($path);
451
452 3
        $pathValue = null;
453 3
        if ($this->hasValue($data, $path)) {
454 3
            $value = $this->getValue($data, $path);
455 3
            $rightType = ('int' === $type) ? is_int($value) : is_float($value);
456 3
            if ($rightType) {
457 3
                $pathValue = $value;
458 3
            } elseif (is_numeric($value)) {
459 3
                $pathValue = ('int' === $type) ? (int) $value : (float) $value;
460 3
            } elseif (null !== $value) {
461 2
                throw new \InvalidArgumentException(
462 2
                    sprintf("Value expected to be %s, but %s given", $type, gettype($value)),
463
                    400
464 2
                );
465
            }
466 3
        }
467
468 3
        $this->restorePath();
469
470 3
        return $pathValue;
471
    }
472
473
    /**
474
     * Parse property of specified object
475
     *
476
     * @param object|array $data
477
     * @param object $obj
478
     * @param PropertyMetadataInterface $metadata
479
     */
480 4
    private function parseProperty($data, $obj, PropertyMetadataInterface $metadata)
481
    {
482 4
        $path = $metadata->getDataPath();
483
484 4
        if (false === $this->hasValue($data, $path)) {
485 2
            return;
486
        }
487
488 4
        if ('custom' === $metadata->getDataType()) {
489 1
            $value = $this->parseCallback($data, $path, [$obj, $metadata->getDataTypeParams()]);
490 1
        } else {
491 4
            $value = $this->parsePropertyValue($data, $path, $metadata);
492
        }
493
494 4
        $setter = $metadata->getSetter();
495 4
        if (null !== $setter) {
496 3
            $obj->{$setter}($value);
497 3
        } else {
498 4
            $setter = $metadata->getPropertyName();
499 4
            $obj->{$setter} = $value;
500
        }
501 4
    }
502
503
    /**
504
     * Parse value of specified property
505
     *
506
     * @param object|array $data
507
     * @param string $path
508
     * @param PropertyMetadataInterface $metadata
509
     * @return mixed|null
510
     */
511 4
    private function parsePropertyValue($data, $path, PropertyMetadataInterface $metadata)
512
    {
513 4
        switch ($metadata->getDataType()) {
514 4
            case 'scalar':
515 4
                return $this->parseScalarValue($data, $path, $metadata->getDataTypeParams());
0 ignored issues
show
Bug introduced by
It seems like $metadata->getDataTypeParams() targeting Reva2\JsonApi\Contracts\...ce::getDataTypeParams() can also be of type array; however, Reva2\JsonApi\Decoders\D...ser::parseScalarValue() does only seem to accept string, 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...
516
517 4
            case 'datetime':
518 1
                $format = $metadata->getDataTypeParams();
519 1
                if (empty($format)) {
520 1
                    $format = 'Y-m-d';
521 1
                }
522
523 1
                return $this->parseDateTime($data, $path, $format);
0 ignored issues
show
Bug introduced by
It seems like $format defined by $metadata->getDataTypeParams() on line 518 can also be of type array; however, Reva2\JsonApi\Decoders\DataParser::parseDateTime() does only seem to accept 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...
524
525 4
            case 'array':
526 3
                return $this->parseArrayValue($data, $path, $metadata->getDataTypeParams());
0 ignored issues
show
Bug introduced by
It seems like $metadata->getDataTypeParams() targeting Reva2\JsonApi\Contracts\...ce::getDataTypeParams() can also be of type string; however, Reva2\JsonApi\Decoders\D...rser::parseArrayValue() does only seem to accept array, 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...
527
528 4
            case 'object':
529 4
                return $this->parseObjectValue($data, $path, $metadata->getDataTypeParams());
0 ignored issues
show
Bug introduced by
It seems like $metadata->getDataTypeParams() targeting Reva2\JsonApi\Contracts\...ce::getDataTypeParams() can also be of type array; however, Reva2\JsonApi\Decoders\D...ser::parseObjectValue() does only seem to accept string, 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...
530
531 1
            case 'raw':
532 1
                return $this->parseRaw($data, $path);
533
534
            default:
535
                throw new \InvalidArgumentException(sprintf(
536
                    "Unsupported property data type '%s'",
537
                    $metadata->getDataType()
538
                ));
539
        }
540
    }
541
542
    /**
543
     * Parse value as JSON API resource or object
544
     *
545
     * @param object|array $data
546
     * @param string $path
547
     * @param string $objClass
548
     * @return mixed|null
549
     */
550 4
    public function parseObjectValue($data, $path, $objClass)
551
    {
552 4
        $metadata = $this->factory->getMetadataFor($objClass);
553
554 4
        if ($metadata instanceof ResourceMetadataInterface) {
555 3
            return $this->parseResource($data, $path, $objClass);
556
        } else {
557 1
            return $this->parseObject($data, $path, $objClass);
558
        }
559
    }
560
561
    /**
562
     * Parse value that contains array
563
     *
564
     * @param object|array $data
565
     * @param string $path
566
     * @param array $params
567
     * @return array|null
568
     */
569 3
    public function parseArrayValue($data, $path, array $params)
570
    {
571 3
        $type = $params[0];
572 3
        $typeParams = $params[1];
573
574
        switch ($type) {
575 3
            case 'scalar':
576 1
                return $this->parseArray(
577 1
                    $data,
578 1
                    $path,
579
                    function ($data, $path, DataParser $parser) use ($typeParams) {
580 1
                        return $parser->parseScalarValue($data, $path, $typeParams);
581
                    }
582 1
                );
583
584 3
            case 'datetime':
585 1
                $format = (!empty($typeParams)) ? $typeParams : 'Y-m-d';
586 1
                return $this->parseArray(
587 1
                    $data,
588 1
                    $path,
589
                    function ($data, $path, DataParser $parser) use ($format) {
590 1
                        return $parser->parseDateTime($data, $path, $format);
591
                    }
592 1
                );
593
594 3
            case 'object':
595 3
                return $this->parseArray(
596 3
                    $data,
597 3
                    $path,
598
                    function ($data, $path, DataParser $parser) use ($typeParams) {
599 3
                        return $parser->parseObjectValue($data, $path, $typeParams);
600
                    }
601 3
                );
602
603 1
            case 'array':
604 1
                return $this->parseArray(
605 1
                    $data,
606 1
                    $path,
607
                    function ($data, $path, DataParser $parser) use ($typeParams) {
608 1
                        return $parser->parseArrayValue($data, $path, $typeParams);
609
                    }
610 1
                );
611
612 1
            case 'raw':
613 1
                return $this->parseArray(
614 1
                    $data,
615 1
                    $path,
616 1
                    function ($data, $path, DataParser $parser) {
617 1
                        return $parser->parseRaw($data, $path);
618
                    }
619 1
                );
620
621
            default:
622
                throw new \InvalidArgumentException(sprintf(
623
                    "Unsupported array item type '%s' specified",
624
                    $type
625
                ));
626
        }
627
    }
628
629
    /**
630
     * Parse scalar value
631
     *
632
     * @param object|array $data
633
     * @param string $path
634
     * @param string $type
635
     * @return bool|float|int|null|string
636
     */
637 4
    public function parseScalarValue($data, $path, $type)
638
    {
639
        switch ($type) {
640 4
            case 'string':
641 4
                return $this->parseString($data, $path);
642
643 1
            case 'bool':
644 1
            case 'boolean':
645 1
                return $this->parseBool($data, $path);
646
647 1
            case 'int':
648 1
            case 'integer':
649 1
                return $this->parseInt($data, $path);
650
651 1
            case 'float':
652 1
            case 'double':
653 1
                return $this->parseFloat($data, $path);
654
655
            default:
656
                throw new \InvalidArgumentException(sprintf("Unsupported scalar type '%s' specified", $type));
657
        }
658
    }
659
}
660