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 ( 90cf5c...e17caf )
by Sergey
02:42
created

DataParser   F

Complexity

Total Complexity 105

Size/Duplication

Total Lines 711
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 11

Test Coverage

Coverage 93.84%

Importance

Changes 11
Bugs 4 Features 2
Metric Value
wmc 105
c 11
b 4
f 2
lcom 1
cbo 11
dl 0
loc 711
ccs 274
cts 292
cp 0.9384
rs 3.9999

29 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 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() 0 13 2
A parseCallback() 0 13 2
C parseBool() 0 25 7
B parseDateTime() 0 25 5
B parseArray() 0 27 6
A parseObject() 0 15 3
C parseResource() 0 46 9
B parseDocument() 0 24 4
A parseQueryParams() 0 20 4
A preparePathSegment() 0 4 1
A initPathStack() 0 4 1
C parseNumeric() 0 24 7
B parseProperty() 0 28 5
C parsePropertyValue() 0 30 7
A parseResourceOrObject() 0 10 2
B parseObjectValue() 0 22 5
B parseArrayValue() 0 59 7
C parseScalarValue() 0 22 8
B convertToApiException() 0 24 4
A getClassByDiscriminator() 0 15 3

How to fix   Complexity   

Complex Class

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