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 ( 28df83...572572 )
by Sergey
04:37 queued 02:17
created

DataParser::parseRaw()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 13
c 0
b 0
f 0
ccs 7
cts 7
cp 1
rs 9.8333
cc 2
nc 2
nop 2
crap 2
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\Contracts\Encoder\Parameters\EncodingParametersInterface;
14
use Neomerx\JsonApi\Document\Error;
15
use Neomerx\JsonApi\Exceptions\JsonApiException;
16
use Reva2\JsonApi\Contracts\Decoders\CallbackResolverInterface;
17
use Reva2\JsonApi\Contracts\Decoders\DataParserInterface;
18
use Reva2\JsonApi\Contracts\Decoders\Mapping\ClassMetadataInterface;
19
use Reva2\JsonApi\Contracts\Decoders\Mapping\DocumentMetadataInterface;
20
use Reva2\JsonApi\Contracts\Decoders\Mapping\Factory\MetadataFactoryInterface;
21
use Reva2\JsonApi\Contracts\Decoders\Mapping\ObjectMetadataInterface;
22
use Reva2\JsonApi\Contracts\Decoders\Mapping\PropertyMetadataInterface;
23
use Reva2\JsonApi\Contracts\Decoders\Mapping\ResourceMetadataInterface;
24
use Symfony\Component\PropertyAccess\PropertyAccess;
25
use Symfony\Component\PropertyAccess\PropertyAccessor;
26
27
/**
28
 * Data parser
29
 *
30
 * @package Reva2\JsonApi\Decoders
31
 * @author Sergey Revenko <[email protected]>
32
 */
33
class DataParser implements DataParserInterface
34
{
35
    const ERROR_CODE = 'ee2c1d49-ba40-4077-a6bb-b06baceb3e97';
36
37
    /**
38
     * Current path
39
     *
40
     * @var \SplStack
41
     */
42
    protected $path;
43
44
    /**
45
     * Resource decoders factory
46
     *
47
     * @var MetadataFactoryInterface
48
     */
49
    protected $factory;
50
51
    /**
52
     * @var PropertyAccessor
53
     */
54
    protected $accessor;
55
56
    /**
57
     * @var CallbackResolverInterface
58
     */
59
    protected $callbackResolver;
60
61
    /**
62
     * Serialization groups
63
     *
64
     * @var string[]
65
     */
66
    protected $serializationGroups = ['Default'];
67
68
    /**
69
     * Constructor
70
     *
71
     * @param MetadataFactoryInterface $factory
72
     * @param CallbackResolverInterface $callbackResolver
73
     */
74 19
    public function __construct(MetadataFactoryInterface $factory, CallbackResolverInterface $callbackResolver)
75
    {
76 19
        $this->factory = $factory;
77 19
        $this->callbackResolver = $callbackResolver;
78 19
        $this->accessor = PropertyAccess::createPropertyAccessorBuilder()
79 19
            ->enableExceptionOnInvalidIndex()
80 19
            ->getPropertyAccessor();
81
        
82 19
        $this->initPathStack();
83 19
    }
84
85
    /**
86
     * @inheritdoc
87
     */
88 14
    public function setPath($path)
89
    {
90 14
        $this->path->push($this->preparePathSegment($path));
91
92 14
        return $this;
93
    }
94
95
    /**
96
     * @inheritdoc
97
     */
98 14
    public function restorePath()
99
    {
100 14
        $this->path->pop();
101
102 14
        return $this;
103
    }
104
105
    /**
106
     * @return string[]
107
     */
108 3
    public function getSerializationGroups()
109
    {
110 3
        return $this->serializationGroups;
111
    }
112
113
    /**
114
     * @param string[] $serializationGroups
115
     * @return $this
116
     */
117 3
    public function setSerializationGroups(array $serializationGroups)
118
    {
119 3
        $this->serializationGroups = $serializationGroups;
120
121 3
        return $this;
122
    }
123
124
    /**
125
     * @inheritdoc
126
     */
127 2
    public function getPath()
128
    {
129 2
        $segments = [];
130 2
        foreach ($this->path as $segment) {
131 1
            $segments[] = $segment;
132
        }
133
134 2
        return '/' . implode('/', array_reverse($segments));
135
    }
136
137
    /**
138
     * @inheritdoc
139
     */
140 14
    public function hasValue($data, $path)
141
    {
142 14
        return $this->accessor->isReadable($data, $path);
143
    }
144
145
    /**
146
     * @inheritdoc
147
     */
148 14
    public function getValue($data, $path)
149
    {
150 14
        return $this->accessor->getValue($data, $path);
151
    }
152
153
    /**
154
     * @inheritdoc
155
     */
156 8
    public function parseString($data, $path)
157
    {
158 8
        $this->setPath($path);
159
160 8
        $pathValue = null;
161 8
        if ($this->hasValue($data, $path)) {
162 8
            $value = $this->getValue($data, $path);
163 8
            if ((null === $value) || (is_string($value))) {
164 8
                $pathValue = $value;
165
            } else {
166 1
                throw new \InvalidArgumentException(
167 1
                    sprintf("Value expected to be a string, but %s given", gettype($value)),
168 1
                    400
169
                );
170
            }
171
        }
172 8
        $this->restorePath();
173
174 8
        return $pathValue;
175
    }
176
177
    /**
178
     * @inheritdoc
179
     */
180 3
    public function parseInt($data, $path)
181
    {
182 3
        return $this->parseNumeric($data, $path, 'int');
183
    }
184
185
    /**
186
     * @inheritdoc
187
     */
188 2
    public function parseFloat($data, $path)
189
    {
190 2
        return $this->parseNumeric($data, $path, 'float');
191
    }
192
193
    /**
194
     * @inheritdoc
195
     */
196 1
    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...
197
    {
198 1
        $this->setPath($path);
199
200 1
        $pathValue = null;
201 1
        if ($this->hasValue($data, $path)) {
202 1
            $pathValue = $this->getValue($data, $path);
203
        }
204
205 1
        $this->restorePath();
206
207 1
        return $pathValue;
208
    }
209
210
    /**
211
     * @inheritdoc
212
     */
213 4
    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...
214
    {
215 4
        $this->setPath($path);
216
217 4
        $pathValue = null;
218 4
        if ($this->hasValue($data, $path)) {
219 4
            $pathValue = call_user_func($callback, $this->getValue($data, $path));
220
        }
221
222 4
        $this->restorePath();
223
224 4
        return $pathValue;
225
    }
226
227
    /**
228
     * @inheritdoc
229
     */
230 2
    public function parseBool($data, $path)
231
    {
232 2
        $this->setPath($path);
233
234 2
        $pathValue = null;
235 2
        if ($this->hasValue($data, $path)) {
236 2
            $value = $this->getValue($data, $path);
237 2
            if ((null === $value) || (is_bool($value))) {
238 1
                $pathValue = $value;
239 2
            } elseif (is_string($value)) {
240 2
                $pathValue = (in_array($value, ['true', 'yes', 'y', 'on', 'enabled'])) ? true : false;
241 1
            } elseif (is_numeric($value)) {
242 1
                $pathValue = (bool) $value;
243
            } else {
244 1
                throw new \InvalidArgumentException(
245 1
                    sprintf("Value expected to be a boolean, but %s given", gettype($value)),
246 1
                    400
247
                );
248
            }
249
        }
250
251 2
        $this->restorePath();
252
253 2
        return $pathValue;
254
    }
255
256
    /**
257
     * @inheritdoc
258
     */
259 2
    public function parseDateTime($data, $path, $format = 'Y-m-d')
260
    {
261 2
        $this->setPath($path);
262
263 2
        $pathValue = null;
264 2
        if ($this->hasValue($data, $path)) {
265 2
            $value = $this->getValue($data, $path);
266 2
            if (null !== $value) {
267 2
                if (is_string($value)) {
268 2
                    $pathValue = \DateTimeImmutable::createFromFormat($format, $value);
269
                }
270
271 2
                if (!$pathValue instanceof \DateTimeImmutable) {
272 1
                    throw new \InvalidArgumentException(
273 1
                        sprintf("Value expected to be a date/time string in '%s' format", $format),
274 1
                        400
275
                    );
276
                }
277
            }
278
        }
279
280 2
        $this->restorePath();
281
282 2
        return $pathValue;
283
    }
284
285
    /**
286
     * @inheritdoc
287
     */
288 4
    public function parseArray($data, $path, \Closure $itemsParser)
289
    {
290 4
        $this->setPath($path);
291
292 4
        $pathValue = null;
293 4
        if ($this->hasValue($data, $path)) {
294 4
            $value = $this->getValue($data, $path);
295 4 View Code Duplication
            if (false === is_array($value)) {
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...
296 1
                throw new \InvalidArgumentException(
297 1
                    sprintf("Value expected to be an array, but %s given", gettype($value)),
298 1
                    400
299
                );
300
            }
301
302 4
            $pathValue = [];
303 4
            $keys = array_keys($value);
304 4
            foreach ($keys as $key) {
305 4
                $arrayPath = sprintf("[%s]", $key);
306
307 4
                $pathValue[$key] = $itemsParser($value, $arrayPath, $this);
308
            }
309
        }
310
311 3
        $this->restorePath();
312
313 3
        return $pathValue;
314
    }
315
316
    /**
317
     * Parse data object value at specified path as object of specified class
318
     *
319
     * @param array|object $data
320
     * @param string $path
321
     * @param string $objType
322
     * @return null
323
     */
324 1
    public function parseObject($data, $path, $objType)
325
    {
326 1
        $this->setPath($path);
327
328 1
        $pathValue = null;
329 1
        if ((true === $this->hasValue($data, $path)) &&
330 1
            (null !== ($value = $this->getValue($data, $path)))
331
        ) {
332 1
            $this->restorePath();
333
334 1
            $pathValue = $this->parseObjectValue($value, $objType);
335
        }
336
337 1
        return $pathValue;
338
    }
339
340
    /**
341
     * @inheritdoc
342
     */
343 5
    public function parseResource($data, $path, $resType)
344
    {
345 5
        $this->setPath($path);
346
347 5
        $pathValue = null;
348 5
        if ((true === $this->hasValue($data, $path)) &&
349 5
            (null !== ($value = $this->getValue($data, $path)))
350
        ) {
351 5
            $metadata = $this->factory->getMetadataFor($resType);
352
            /* @var $metadata ResourceMetadataInterface */
353
354 5
            $name = $this->parseString($value, 'type');
355 5
            if ($name !== $metadata->getName()) {
356 1
                throw new \InvalidArgumentException(
357 1
                    sprintf("Value must contain resource of type '%s'", $metadata->getName()),
358 1
                    409
359
                );
360
            }
361
362 5
            $pathValue = null;
363 5
            if ((null !== $metadata->getLoader()) && (true === $this->hasValue($value, 'id'))) {
364
                $callback = $this->callbackResolver->resolveCallback($metadata->getLoader());
365
                $pathValue = call_user_func($callback, $this->getValue($value, 'id'), $metadata);
366
            }
367
368 5
            if (null === $pathValue) {
369 5
                $discClass = $this->getClassByDiscriminator($metadata, $value);
370 4
                if ((null !== $discClass) && ($discClass !== $resType)) {
371 4
                    $metadata = $this->factory->getMetadataFor($discClass);
372
                }
373
374 4
                $objClass = $metadata->getClassName();
375 4
                $pathValue = new $objClass();
376
377 4
                if (null !== ($idMetadata = $metadata->getIdMetadata())) {
378 4
                    $this->parseProperty($value, $pathValue, $idMetadata);
379
                }
380
            } else {
381
                $valueClass = get_class($pathValue);
382
                if ($valueClass !== $resType) {
383
                    $metadata = $this->factory->getMetadataFor($valueClass);
384
                }
385
            }
386
387 4
            foreach ($metadata->getAttributes() as $attribute) {
388 4
                $this->parseProperty($value, $pathValue, $attribute);
389
            }
390
391 4
            foreach ($metadata->getRelationships() as $relationship) {
392 4
                $this->parseProperty($value, $pathValue, $relationship);
393
            }
394
        }
395
396 3
        $this->restorePath();
397
398 3
        return $pathValue;
399
    }
400
401
    /**
402
     * @inheritdoc
403
     */
404 4
    public function parseDocument($data, $docType)
405
    {
406
        try {
407 4
            $this->initPathStack();
408
409 4
            $metadata = $this->factory->getMetadataFor($docType);
410 4
            if (!$metadata instanceof DocumentMetadataInterface) {
411 1
                throw new \InvalidArgumentException(sprintf("Failed to parse %s as JSON API document", $docType));
412
            }
413
414
            /* @var $metadata \Reva2\JsonApi\Contracts\Decoders\Mapping\DocumentMetadataInterface */
415
416 3
            $docClass = $metadata->getClassName();
417 3
            $doc = new $docClass();
418
419 3
            $this->parseProperty($data, $doc, $metadata->getContentMetadata());
420
421 2
            return $doc;
422 2
        } catch (JsonApiException $e) {
423
            throw $e;
424 2
        } catch (\Exception $e) {
425 2
            throw  $this->convertToApiException($e, 'document');
426
        }
427
    }
428
429
    /**
430
     * @inheritdoc
431
     */
432 3
    public function parseQueryParams($data, $paramsType)
433
    {
434
        try {
435 3
            $this->initPathStack();
436
437 3
            $query = $this->parseObjectValue($data, $paramsType);
438 3
            if (!$query instanceof EncodingParametersInterface) {
439
                throw new \InvalidArgumentException(sprintf(
440
                    "Query parameters object must implement interface %s",
441
                    EncodingParametersInterface::class
442
                ));
443
            }
444
445 3
            return $query;
446
        } catch (JsonApiException $e) {
447
            throw $e;
448
        } catch (\Exception $e) {
449
            throw  $this->convertToApiException($e, 'query');
450
        }
451
    }
452
453
    /**
454
     * Prepare path segment
455
     *
456
     * @param string $path
457
     * @return string
458
     */
459 14
    protected function preparePathSegment($path)
460
    {
461 14
        return trim(preg_replace('~[\/]+~si', '/', str_replace(['.', '[', ']'], '/', (string) $path)), '/');
462
    }
463
464
    /**
465
     * Initialize stack that store current path
466
     */
467 19
    protected function initPathStack()
468
    {
469 19
        $this->path = new \SplStack();
470 19
    }
471
472
    /**
473
     * Parse numeric value
474
     *
475
     * @param mixed $data
476
     * @param string $path
477
     * @param string $type
478
     * @return float|int|null
479
     */
480 4
    protected function parseNumeric($data, $path, $type)
481
    {
482 4
        $this->setPath($path);
483
484 4
        $pathValue = null;
485 4
        if ($this->hasValue($data, $path)) {
486 4
            $value = $this->getValue($data, $path);
487 4
            $rightType = ('int' === $type) ? is_int($value) : is_float($value);
488 4
            if ($rightType) {
489 3
                $pathValue = $value;
490 4
            } elseif (is_numeric($value)) {
491 4
                $pathValue = ('int' === $type) ? (int) $value : (float) $value;
492 2 View Code Duplication
            } elseif (null !== $value) {
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...
493 2
                throw new \InvalidArgumentException(
494 2
                    sprintf("Value expected to be %s, but %s given", $type, gettype($value)),
495 2
                    400
496
                );
497
            }
498
        }
499
500 4
        $this->restorePath();
501
502 4
        return $pathValue;
503
    }
504
505
    /**
506
     * Parse property of specified object
507
     *
508
     * @param object|array $data
509
     * @param object $obj
510
     * @param PropertyMetadataInterface $metadata
511
     */
512 7
    private function parseProperty($data, $obj, PropertyMetadataInterface $metadata)
513
    {
514 7
        $path = $metadata->getDataPath();
515
516 7
        if ((false === $this->hasValue($data, $path)) ||
517 7
            (true === $this->isExcludedProperty($metadata))
518
        ) {
519 6
            return;
520
        }
521
522 7
        if ('custom' === $metadata->getDataType()) {
523 4
            $value = $this->parseCallback($data, $path, [$obj, $metadata->getDataTypeParams()]);
524
        } else {
525 6
            $value = $this->parsePropertyValue($data, $path, $metadata);
526
        }
527
528 7
        if (null !== ($converter = $metadata->getConverter())) {
529 3
            $callback = $this->callbackResolver->resolveCallback($converter);
530
531 3
            $value = call_user_func($callback, $value);
532
        }
533
534 7
        $setter = $metadata->getSetter();
535 7
        if (null !== $setter) {
536 6
            $obj->{$setter}($value);
537
        } else {
538 5
            $setter = $metadata->getPropertyName();
539 5
            $obj->{$setter} = $value;
540
        }
541 7
    }
542
543
    /**
544
     * Parse value of specified property
545
     *
546
     * @param object|array $data
547
     * @param string $path
548
     * @param PropertyMetadataInterface $metadata
549
     * @return mixed|null
550
     */
551 6
    private function parsePropertyValue($data, $path, PropertyMetadataInterface $metadata)
552
    {
553 6
        switch ($metadata->getDataType()) {
554 6
            case 'scalar':
555 6
                return $this->parseScalarValue($data, $path, $metadata->getDataTypeParams());
556
557 5
            case 'datetime':
558 1
                $format = $metadata->getDataTypeParams();
559 1
                if (empty($format)) {
560 1
                    $format = 'Y-m-d';
561
                }
562
563 1
                return $this->parseDateTime($data, $path, $format);
564
565 5
            case 'array':
566 3
                return $this->parseArrayValue($data, $path, $metadata->getDataTypeParams());
567
568 5
            case 'object':
569 5
                return $this->parseResourceOrObject($data, $path, $metadata->getDataTypeParams());
570
571 1
            case 'raw':
572 1
                return $this->parseRaw($data, $path);
573
574
            default:
575
                throw new \InvalidArgumentException(sprintf(
576
                    "Unsupported property data type '%s'",
577
                    $metadata->getDataType()
578
                ));
579
        }
580
    }
581
582
    /**
583
     * Parse value as JSON API resource or object
584
     *
585
     * @param object|array $data
586
     * @param string $path
587
     * @param string $objClass
588
     * @return mixed|null
589
     */
590 5
    public function parseResourceOrObject($data, $path, $objClass)
591
    {
592 5
        $metadata = $this->factory->getMetadataFor($objClass);
593
594 5
        if ($metadata instanceof ResourceMetadataInterface) {
595 4
            return $this->parseResource($data, $path, $objClass);
596
        } else {
597 1
            return $this->parseObject($data, $path, $objClass);
598
        }
599
    }
600
601
    /**
602
     * Parse value that contains JSON API object
603
     *
604
     * @param object|array $data
605
     * @param string $objType
606
     * @return mixed
607
     */
608 4
    public function parseObjectValue($data, $objType)
609
    {
610 4
        $metadata = $this->factory->getMetadataFor($objType);
611 4
        if (!$metadata instanceof ObjectMetadataInterface) {
612
            throw new \InvalidArgumentException('Invalid object metadata');
613
        }
614
615 4
        $discClass = $this->getClassByDiscriminator($metadata, $data);
616 4
        if ((null !== $discClass) && ($discClass !== $objType)) {
617 1
            return $this->parseObjectValue($data, $discClass);
618
        }
619
620 4
        $objClass = $metadata->getClassName();
621 4
        $obj = new $objClass();
622
623 4
        $properties = $metadata->getProperties();
624 4
        foreach ($properties as $property) {
625 4
            $this->parseProperty($data, $obj, $property);
626
        }
627
628 4
        return $obj;
629
    }
630
631
    /**
632
     * Parse value that contains array
633
     *
634
     * @param object|array $data
635
     * @param string $path
636
     * @param array $params
637
     * @return array|null
638
     */
639 3
    public function parseArrayValue($data, $path, array $params)
640
    {
641 3
        $type = $params[0];
642 3
        $typeParams = $params[1];
643
644
        switch ($type) {
645 3
            case 'scalar':
646 1
                return $this->parseArray(
647 1
                    $data,
648 1
                    $path,
649 1
                    function ($data, $path, DataParser $parser) use ($typeParams) {
650 1
                        return $parser->parseScalarValue($data, $path, $typeParams);
651 1
                    }
652
                );
653
654 3
            case 'datetime':
655 1
                $format = (!empty($typeParams)) ? $typeParams : 'Y-m-d';
656 1
                return $this->parseArray(
657 1
                    $data,
658 1
                    $path,
659 1
                    function ($data, $path, DataParser $parser) use ($format) {
660 1
                        return $parser->parseDateTime($data, $path, $format);
661 1
                    }
662
                );
663
664 3
            case 'object':
665 3
                return $this->parseArray(
666 3
                    $data,
667 3
                    $path,
668 3
                    function ($data, $path, DataParser $parser) use ($typeParams) {
669 3
                        return $parser->parseResourceOrObject($data, $path, $typeParams);
670 3
                    }
671
                );
672
673 1
            case 'array':
674 1
                return $this->parseArray(
675 1
                    $data,
676 1
                    $path,
677 1
                    function ($data, $path, DataParser $parser) use ($typeParams) {
678 1
                        return $parser->parseArrayValue($data, $path, $typeParams);
679 1
                    }
680
                );
681
682 1
            case 'raw':
683 1
                return $this->parseArray(
684 1
                    $data,
685 1
                    $path,
686 1
                    function ($data, $path, DataParser $parser) {
687 1
                        return $parser->parseRaw($data, $path);
688 1
                    }
689
                );
690
691
            default:
692
                throw new \InvalidArgumentException(sprintf(
693
                    "Unsupported array item type '%s' specified",
694
                    $type
695
                ));
696
        }
697
    }
698
699
    /**
700
     * Parse scalar value
701
     *
702
     * @param object|array $data
703
     * @param string $path
704
     * @param string $type
705
     * @return bool|float|int|null|string
706
     */
707 6
    public function parseScalarValue($data, $path, $type)
708
    {
709
        switch ($type) {
710 6
            case 'string':
711 5
                return $this->parseString($data, $path);
712
713 2
            case 'bool':
714 2
            case 'boolean':
715 1
                return $this->parseBool($data, $path);
716
717 2
            case 'int':
718 2
            case 'integer':
719 2
                return $this->parseInt($data, $path);
720
721 1
            case 'float':
722 1
            case 'double':
723 1
                return $this->parseFloat($data, $path);
724
725
            default:
726
                throw new \InvalidArgumentException(sprintf("Unsupported scalar type '%s' specified", $type));
727
        }
728
    }
729
730
    /**
731
     * Convert any exception to JSON API exception
732
     *
733
     * @param \Exception $e
734
     * @param string $objType
735
     * @return JsonApiException
736
     */
737 2
    private function convertToApiException(\Exception $e, $objType)
738
    {
739 2
        $status = $e->getCode();
740 2
        $message = 'Failed to parse request';
741 2
        if (empty($status)) {
742 1
            $message = 'Internal server error';
743 1
            $status = 500;
744
        }
745
746 2
        $source = null;
747
        switch ($objType) {
748 2
            case 'document':
749 2
                $source = ['pointer' => $this->getPath()];
750 2
                break;
751
752
            case 'query':
753
                $source = ['parameter' => $this->getPath()];
754
                break;
755
        }
756
757 2
        $error = new Error(rand(), null, $status, self::ERROR_CODE, $message, $e->getMessage(), $source);
758
759 2
        return new JsonApiException($error, $status, $e);
760
    }
761
762
    /**
763
     * Returns appropriate discriminator class for specified data
764
     *
765
     * @param ClassMetadataInterface $metadata
766
     * @param array|object $data
767
     * @return string|null
768
     */
769 8
    private function getClassByDiscriminator(ClassMetadataInterface $metadata, $data)
770
    {
771 8
        if (null === ($discField = $metadata->getDiscriminatorField())) {
772 6
            return null;
773
        }
774
775 6
        $discValue = $this->parseString($data, $discField->getDataPath());
776 6
        if (empty($discValue)) {
777 1
            $this->setPath($discField->getDataPath());
778
779 1
            throw new \InvalidArgumentException("Field value required and can not be empty", 422);
780
        }
781
782 5
        return $metadata->getDiscriminatorClass($discValue);
783
    }
784
785
    /**
786
     * Check if specified property should be excluded
787
     *
788
     * @param PropertyMetadataInterface $metadata
789
     * @return bool
790
     */
791 7
    private function isExcludedProperty(PropertyMetadataInterface $metadata)
792
    {
793 7
        $propertyGroups = $metadata->getGroups();
794 7
        foreach ($propertyGroups as $group) {
795 7
            if (in_array($group, $this->serializationGroups)) {
796 7
                return false;
797
            }
798
        }
799
800
        return true;
801
    }
802
}
803