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 ( 32f0eb...60a577 )
by Sergey
03:32
created

DataParser::setSerializationGroups()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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