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 ( 8f3a3d...7eb519 )
by Sergey
76:54 queued 51:47
created

DataParser::parseResourceOrObject()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 10
c 0
b 0
f 0
ccs 5
cts 5
cp 1
rs 9.9332
cc 2
nc 2
nop 3
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 4
    public function parseInt($data, $path)
181
    {
182 4
        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 2
    public function parseObject($data, $path, $objType)
325
    {
326 2
        $this->setPath($path);
327
328 2
        $pathValue = null;
329 2
        if ((true === $this->hasValue($data, $path)) &&
330 2
            (null !== ($value = $this->getValue($data, $path)))
331
        ) {
332 2
            $this->restorePath();
333
334 2
            $pathValue = $this->parseObjectValue($value, $objType);
335
        }
336
337 2
        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
            $docMetadata = $metadata->getMetadata();
422 2
            if ($docMetadata !== null) {
423 1
                $this->parseProperty($data, $doc, $metadata->getMetadata());
424
            }
425
426 2
            return $doc;
427 2
        } catch (JsonApiException $e) {
428
            throw $e;
429 2
        } catch (\Exception $e) {
430 2
            throw  $this->convertToApiException($e, 'document');
431
        }
432
    }
433
434
    /**
435
     * @inheritdoc
436
     */
437 3
    public function parseQueryParams($data, $paramsType)
438
    {
439
        try {
440 3
            $this->initPathStack();
441
442 3
            $query = $this->parseObjectValue($data, $paramsType);
443 3
            if (!$query instanceof EncodingParametersInterface) {
444
                throw new \InvalidArgumentException(sprintf(
445
                    "Query parameters object must implement interface %s",
446
                    EncodingParametersInterface::class
447
                ));
448
            }
449
450 3
            return $query;
451
        } catch (JsonApiException $e) {
452
            throw $e;
453
        } catch (\Exception $e) {
454
            throw  $this->convertToApiException($e, 'query');
455
        }
456
    }
457
458
    /**
459
     * Prepare path segment
460
     *
461
     * @param string $path
462
     * @return string
463
     */
464 14
    protected function preparePathSegment($path)
465
    {
466 14
        return trim(preg_replace('~[\/]+~si', '/', str_replace(['.', '[', ']'], '/', (string) $path)), '/');
467
    }
468
469
    /**
470
     * Initialize stack that store current path
471
     */
472 19
    protected function initPathStack()
473
    {
474 19
        $this->path = new \SplStack();
475 19
    }
476
477
    /**
478
     * Parse numeric value
479
     *
480
     * @param mixed $data
481
     * @param string $path
482
     * @param string $type
483
     * @return float|int|null
484
     */
485 5
    protected function parseNumeric($data, $path, $type)
486
    {
487 5
        $this->setPath($path);
488
489 5
        $pathValue = null;
490 5
        if ($this->hasValue($data, $path)) {
491 5
            $value = $this->getValue($data, $path);
492 5
            $rightType = ('int' === $type) ? is_int($value) : is_float($value);
493 5
            if ($rightType) {
494 4
                $pathValue = $value;
495 4
            } elseif (is_numeric($value)) {
496 4
                $pathValue = ('int' === $type) ? (int) $value : (float) $value;
497 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...
498 2
                throw new \InvalidArgumentException(
499 2
                    sprintf("Value expected to be %s, but %s given", $type, gettype($value)),
500 2
                    400
501
                );
502
            }
503
        }
504
505 5
        $this->restorePath();
506
507 5
        return $pathValue;
508
    }
509
510
    /**
511
     * Parse property of specified object
512
     *
513
     * @param object|array $data
514
     * @param object $obj
515
     * @param PropertyMetadataInterface $metadata
516
     */
517 7
    private function parseProperty($data, $obj, PropertyMetadataInterface $metadata)
518
    {
519 7
        $path = $metadata->getDataPath();
520
521 7
        if ((false === $this->hasValue($data, $path)) ||
522 7
            (true === $this->isExcludedProperty($metadata))
523
        ) {
524 6
            return;
525
        }
526
527 7
        if ('custom' === $metadata->getDataType()) {
528 4
            $value = $this->parseCallback($data, $path, [$obj, $metadata->getDataTypeParams()]);
529
        } else {
530 6
            $value = $this->parsePropertyValue($data, $path, $metadata);
531
        }
532
533 7
        if (null !== ($converter = $metadata->getConverter())) {
534 3
            $callback = $this->callbackResolver->resolveCallback($converter);
535
536 3
            $value = call_user_func($callback, $value);
537
        }
538
539 7
        $setter = $metadata->getSetter();
540 7
        if (null !== $setter) {
541 6
            $obj->{$setter}($value);
542
        } else {
543 5
            $setter = $metadata->getPropertyName();
544 5
            $obj->{$setter} = $value;
545
        }
546 7
    }
547
548
    /**
549
     * Parse value of specified property
550
     *
551
     * @param object|array $data
552
     * @param string $path
553
     * @param PropertyMetadataInterface $metadata
554
     * @return mixed|null
555
     */
556 6
    private function parsePropertyValue($data, $path, PropertyMetadataInterface $metadata)
557
    {
558 6
        switch ($metadata->getDataType()) {
559 6
            case 'scalar':
560 6
                return $this->parseScalarValue($data, $path, $metadata->getDataTypeParams());
561
562 5
            case 'datetime':
563 1
                $format = $metadata->getDataTypeParams();
564 1
                if (empty($format)) {
565 1
                    $format = 'Y-m-d';
566
                }
567
568 1
                return $this->parseDateTime($data, $path, $format);
569
570 5
            case 'array':
571 3
                return $this->parseArrayValue($data, $path, $metadata->getDataTypeParams());
572
573 5
            case 'object':
574 5
                return $this->parseResourceOrObject($data, $path, $metadata->getDataTypeParams());
575
576 1
            case 'raw':
577 1
                return $this->parseRaw($data, $path);
578
579
            default:
580
                throw new \InvalidArgumentException(sprintf(
581
                    "Unsupported property data type '%s'",
582
                    $metadata->getDataType()
583
                ));
584
        }
585
    }
586
587
    /**
588
     * Parse value as JSON API resource or object
589
     *
590
     * @param object|array $data
591
     * @param string $path
592
     * @param string $objClass
593
     * @return mixed|null
594
     */
595 5
    public function parseResourceOrObject($data, $path, $objClass)
596
    {
597 5
        $metadata = $this->factory->getMetadataFor($objClass);
598
599 5
        if ($metadata instanceof ResourceMetadataInterface) {
600 4
            return $this->parseResource($data, $path, $objClass);
601
        } else {
602 2
            return $this->parseObject($data, $path, $objClass);
603
        }
604
    }
605
606
    /**
607
     * Parse value that contains JSON API object
608
     *
609
     * @param object|array $data
610
     * @param string $objType
611
     * @return mixed
612
     */
613 5
    public function parseObjectValue($data, $objType)
614
    {
615 5
        $metadata = $this->factory->getMetadataFor($objType);
616 5
        if (!$metadata instanceof ObjectMetadataInterface) {
617
            throw new \InvalidArgumentException('Invalid object metadata');
618
        }
619
620 5
        $discClass = $this->getClassByDiscriminator($metadata, $data);
621 5
        if ((null !== $discClass) && ($discClass !== $objType)) {
622 1
            return $this->parseObjectValue($data, $discClass);
623
        }
624
625 5
        $objClass = $metadata->getClassName();
626 5
        $obj = new $objClass();
627
628 5
        $properties = $metadata->getProperties();
629 5
        foreach ($properties as $property) {
630 5
            $this->parseProperty($data, $obj, $property);
631
        }
632
633 5
        return $obj;
634
    }
635
636
    /**
637
     * Parse value that contains array
638
     *
639
     * @param object|array $data
640
     * @param string $path
641
     * @param array $params
642
     * @return array|null
643
     */
644 3
    public function parseArrayValue($data, $path, array $params)
645
    {
646 3
        $type = $params[0];
647 3
        $typeParams = $params[1];
648
649
        switch ($type) {
650 3
            case 'scalar':
651 1
                return $this->parseArray(
652 1
                    $data,
653 1
                    $path,
654 1
                    function ($data, $path, DataParser $parser) use ($typeParams) {
655 1
                        return $parser->parseScalarValue($data, $path, $typeParams);
656 1
                    }
657
                );
658
659 3
            case 'datetime':
660 1
                $format = (!empty($typeParams)) ? $typeParams : 'Y-m-d';
661 1
                return $this->parseArray(
662 1
                    $data,
663 1
                    $path,
664 1
                    function ($data, $path, DataParser $parser) use ($format) {
665 1
                        return $parser->parseDateTime($data, $path, $format);
666 1
                    }
667
                );
668
669 3
            case 'object':
670 3
                return $this->parseArray(
671 3
                    $data,
672 3
                    $path,
673 3
                    function ($data, $path, DataParser $parser) use ($typeParams) {
674 3
                        return $parser->parseResourceOrObject($data, $path, $typeParams);
675 3
                    }
676
                );
677
678 1
            case 'array':
679 1
                return $this->parseArray(
680 1
                    $data,
681 1
                    $path,
682 1
                    function ($data, $path, DataParser $parser) use ($typeParams) {
683 1
                        return $parser->parseArrayValue($data, $path, $typeParams);
684 1
                    }
685
                );
686
687 1
            case 'raw':
688 1
                return $this->parseArray(
689 1
                    $data,
690 1
                    $path,
691 1
                    function ($data, $path, DataParser $parser) {
692 1
                        return $parser->parseRaw($data, $path);
693 1
                    }
694
                );
695
696
            default:
697
                throw new \InvalidArgumentException(sprintf(
698
                    "Unsupported array item type '%s' specified",
699
                    $type
700
                ));
701
        }
702
    }
703
704
    /**
705
     * Parse scalar value
706
     *
707
     * @param object|array $data
708
     * @param string $path
709
     * @param string $type
710
     * @return bool|float|int|null|string
711
     */
712 6
    public function parseScalarValue($data, $path, $type)
713
    {
714
        switch ($type) {
715 6
            case 'string':
716 5
                return $this->parseString($data, $path);
717
718 3
            case 'bool':
719 3
            case 'boolean':
720 1
                return $this->parseBool($data, $path);
721
722 3
            case 'int':
723 3
            case 'integer':
724 3
                return $this->parseInt($data, $path);
725
726 1
            case 'float':
727 1
            case 'double':
728 1
                return $this->parseFloat($data, $path);
729
730
            default:
731
                throw new \InvalidArgumentException(sprintf("Unsupported scalar type '%s' specified", $type));
732
        }
733
    }
734
735
    /**
736
     * Convert any exception to JSON API exception
737
     *
738
     * @param \Exception $e
739
     * @param string $objType
740
     * @return JsonApiException
741
     */
742 2
    private function convertToApiException(\Exception $e, $objType)
743
    {
744 2
        $status = $e->getCode();
745 2
        $message = 'Failed to parse request';
746 2
        if (empty($status)) {
747 1
            $message = 'Internal server error';
748 1
            $status = 500;
749
        }
750
751 2
        $source = null;
752
        switch ($objType) {
753 2
            case 'document':
754 2
                $source = ['pointer' => $this->getPath()];
755 2
                break;
756
757
            case 'query':
758
                $source = ['parameter' => $this->getPath()];
759
                break;
760
        }
761
762 2
        $error = new Error(rand(), null, $status, self::ERROR_CODE, $message, $e->getMessage(), $source);
763
764 2
        return new JsonApiException($error, $status, $e);
765
    }
766
767
    /**
768
     * Returns appropriate discriminator class for specified data
769
     *
770
     * @param ClassMetadataInterface $metadata
771
     * @param array|object $data
772
     * @return string|null
773
     */
774 8
    private function getClassByDiscriminator(ClassMetadataInterface $metadata, $data)
775
    {
776 8
        if (null === ($discField = $metadata->getDiscriminatorField())) {
777 6
            return null;
778
        }
779
780 6
        $discValue = $this->parseString($data, $discField->getDataPath());
781 6
        if (empty($discValue)) {
782 1
            $this->setPath($discField->getDataPath());
783
784 1
            throw new \InvalidArgumentException("Field value required and can not be empty", 422);
785
        }
786
787 5
        return $metadata->getDiscriminatorClass($discValue);
788
    }
789
790
    /**
791
     * Check if specified property should be excluded
792
     *
793
     * @param PropertyMetadataInterface $metadata
794
     * @return bool
795
     */
796 7
    private function isExcludedProperty(PropertyMetadataInterface $metadata)
797
    {
798 7
        $propertyGroups = $metadata->getGroups();
799 7
        foreach ($propertyGroups as $group) {
800 7
            if (in_array($group, $this->serializationGroups)) {
801 7
                return false;
802
            }
803
        }
804
805
        return true;
806
    }
807
}
808