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 ( 0f07bb...d93f36 )
by Sergey
05:25
created

DataParser::preparePathSegment()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
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
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 3
    public function getPath()
128
    {
129 2
        $segments = [];
130 2
        foreach ($this->path as $segment) {
131 1
            $segments[] = $segment;
132 2
        }
133
134 3
        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 7
            $value = $this->getValue($data, $path);
163 7
            if ((null === $value) || (is_string($value))) {
164 7
                $pathValue = $value;
165 7
            } else {
166 1
                throw new \InvalidArgumentException(
167 1
                    sprintf("Value expected to be a string, but %s given", gettype($value)),
168
                    400
169 1
                );
170
            }
171 7
        }
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 1
        }
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 4
        }
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 2
            } elseif (is_numeric($value)) {
242 1
                $pathValue = (bool) $value;
243 1
            } 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
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 2
                }
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
                        400
275 1
                    );
276
                }
277 2
            }
278 2
        }
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
            if ((null !== $value) && (false === is_array($value))) {
296 1
                throw new \InvalidArgumentException(
297 1
                    sprintf("Value expected to be an array, but %s given", gettype($value)),
298
                    400
299 1
                );
300 4
            } elseif (is_array($value)) {
301 4
                $pathValue = [];
302 4
                $keys = array_keys($value);
303 4
                foreach ($keys as $key) {
304 4
                    $arrayPath = sprintf("[%s]", $key);
305
306 4
                    $pathValue[$key] = $itemsParser($value, $arrayPath, $this);
307 3
                }
308 3
            }
309 3
        }
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 1
        ) {
332 1
            $this->restorePath();
333
334 1
            $pathValue = $this->parseObjectValue($value, $objType);
335 1
        }
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 5
        ) {
351 5
            $metadata = $this->factory->getMetadataFor($resType);
352
            /* @var $metadata ResourceMetadataInterface */
353
354 5
            $discClass = $this->getClassByDiscriminator($metadata, $value);
355 4
            if ((null !== $discClass) && ($discClass !== $resType)) {
356 4
                $this->restorePath();
357
358 4
                return $this->parseResource($data, $path, $discClass);
359
            }
360
361 4
            $name = $this->parseString($value, 'type');
362 4
            if ($name !== $metadata->getName()) {
363 1
                throw new \InvalidArgumentException(
364 1
                    sprintf("Value must contain resource of type '%s'", $metadata->getName()),
365
                    409
366 1
                );
367
            }
368
369 4
            $pathValue = null;
370 4
            if ((null !== $metadata->getLoader()) && (true === $this->hasValue($value, 'id'))) {
371
                $callback = $this->callbackResolver->resolveCallback($metadata->getLoader());
372
                $pathValue = call_user_func($callback, $this->getValue($value, 'id'), $metadata);
373
            }
374
375 4
            if (null === $pathValue) {
376 4
                $objClass = $metadata->getClassName();
377 4
                $pathValue = new $objClass();
378
379 4
                if (null !== ($idMetadata = $metadata->getIdMetadata())) {
380 4
                    $this->parseProperty($value, $pathValue, $idMetadata);
381 4
                }
382 4
            }
383
384 4
            foreach ($metadata->getAttributes() as $attribute) {
385 4
                $this->parseProperty($value, $pathValue, $attribute);
386 4
            }
387
388 4
            foreach ($metadata->getRelationships() as $relationship) {
389 4
                $this->parseProperty($value, $pathValue, $relationship);
390 3
            }
391 3
        }
392
393 3
        $this->restorePath();
394
395 3
        return $pathValue;
396
    }
397
398
    /**
399
     * @inheritdoc
400
     */
401 4
    public function parseDocument($data, $docType)
402
    {
403
        try {
404 4
            $this->initPathStack();
405
406 4
            $metadata = $this->factory->getMetadataFor($docType);
407 4
            if (!$metadata instanceof DocumentMetadataInterface) {
408 1
                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 3
            $docClass = $metadata->getClassName();
414 3
            $doc = new $docClass();
415
416 3
            $this->parseProperty($data, $doc, $metadata->getContentMetadata());
417
418 2
            return $doc;
419 2
        } catch (JsonApiException $e) {
420
            throw $e;
421 2
        } catch (\Exception $e) {
422 2
            throw  $this->convertToApiException($e, 'document');
423
        }
424
    }
425
426
    /**
427
     * @inheritdoc
428
     */
429 3
    public function parseQueryParams($data, $paramsType)
430
    {
431
        try {
432 3
            $this->initPathStack();
433
434 3
            $query = $this->parseObjectValue($data, $paramsType);
435 3
            if (!$query instanceof EncodingParametersInterface) {
436
                throw new \InvalidArgumentException(sprintf(
437
                    "Query parameters object must implement interface %s",
438
                    EncodingParametersInterface::class
439
                ));
440
            }
441
442 3
            return $query;
443
        } catch (JsonApiException $e) {
444
            throw $e;
445
        } catch (\Exception $e) {
446
            throw  $this->convertToApiException($e, 'query');
447
        }
448
    }
449
450
    /**
451
     * Prepare path segment
452
     *
453
     * @param string $path
454
     * @return string
455
     */
456 14
    protected function preparePathSegment($path)
457
    {
458 14
        return trim(preg_replace('~[\/]+~si', '/', str_replace(['.', '[', ']'], '/', (string) $path)), '/');
459
    }
460
461
    /**
462
     * Initialize stack that store current path
463
     */
464 19
    protected function initPathStack()
465
    {
466 19
        $this->path = new \SplStack();
467 19
    }
468
469
    /**
470
     * Parse numeric value
471
     *
472
     * @param mixed $data
473
     * @param string $path
474
     * @param string $type
475
     * @return float|int|null
476
     */
477 4
    protected function parseNumeric($data, $path, $type)
478
    {
479 4
        $this->setPath($path);
480
481 4
        $pathValue = null;
482 4
        if ($this->hasValue($data, $path)) {
483 4
            $value = $this->getValue($data, $path);
484 4
            $rightType = ('int' === $type) ? is_int($value) : is_float($value);
485 4
            if ($rightType) {
486 3
                $pathValue = $value;
487 4
            } elseif (is_numeric($value)) {
488 4
                $pathValue = ('int' === $type) ? (int) $value : (float) $value;
489 4
            } elseif (null !== $value) {
490 2
                throw new \InvalidArgumentException(
491 2
                    sprintf("Value expected to be %s, but %s given", $type, gettype($value)),
492
                    400
493 2
                );
494
            }
495 4
        }
496
497 4
        $this->restorePath();
498
499 4
        return $pathValue;
500
    }
501
502
    /**
503
     * Parse property of specified object
504
     *
505
     * @param object|array $data
506
     * @param object $obj
507
     * @param PropertyMetadataInterface $metadata
508
     */
509 7
    private function parseProperty($data, $obj, PropertyMetadataInterface $metadata)
510
    {
511 7
        $path = $metadata->getDataPath();
512
513 7
        if ((false === $this->hasValue($data, $path)) ||
514 7
            (true === $this->isExcludedProperty($metadata))
515 7
        ) {
516 5
            return;
517
        }
518
519 7
        if ('custom' === $metadata->getDataType()) {
520 4
            $value = $this->parseCallback($data, $path, [$obj, $metadata->getDataTypeParams()]);
521 4
        } else {
522 6
            $value = $this->parsePropertyValue($data, $path, $metadata);
523
        }
524
525 7
        if (null !== ($converter = $metadata->getConverter())) {
526 3
            $callback = $this->callbackResolver->resolveCallback($converter);
527
528 3
            $value = call_user_func($callback, $value);
529 3
        }
530
531 7
        $setter = $metadata->getSetter();
532 7
        if (null !== $setter) {
533 6
            $obj->{$setter}($value);
534 6
        } else {
535 5
            $setter = $metadata->getPropertyName();
536 5
            $obj->{$setter} = $value;
537
        }
538 7
    }
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 6
    private function parsePropertyValue($data, $path, PropertyMetadataInterface $metadata)
549
    {
550 6
        switch ($metadata->getDataType()) {
551 6
            case 'scalar':
552 6
                return $this->parseScalarValue($data, $path, $metadata->getDataTypeParams());
553
554 5
            case 'datetime':
555 1
                $format = $metadata->getDataTypeParams();
556 1
                if (empty($format)) {
557 1
                    $format = 'Y-m-d';
558 1
                }
559
560 1
                return $this->parseDateTime($data, $path, $format);
561
562 5
            case 'array':
563 3
                return $this->parseArrayValue($data, $path, $metadata->getDataTypeParams());
564
565 5
            case 'object':
566 5
                return $this->parseResourceOrObject($data, $path, $metadata->getDataTypeParams());
567
568 1
            case 'raw':
569 1
                return $this->parseRaw($data, $path);
570
571
            default:
572
                throw new \InvalidArgumentException(sprintf(
573
                    "Unsupported property data type '%s'",
574
                    $metadata->getDataType()
575
                ));
576
        }
577
    }
578
579
    /**
580
     * Parse value as JSON API resource or object
581
     *
582
     * @param object|array $data
583
     * @param string $path
584
     * @param string $objClass
585
     * @return mixed|null
586
     */
587 5
    public function parseResourceOrObject($data, $path, $objClass)
588
    {
589 5
        $metadata = $this->factory->getMetadataFor($objClass);
590
591 5
        if ($metadata instanceof ResourceMetadataInterface) {
592 4
            return $this->parseResource($data, $path, $objClass);
593
        } else {
594 1
            return $this->parseObject($data, $path, $objClass);
595
        }
596
    }
597
598
    /**
599
     * Parse value that contains JSON API object
600
     *
601
     * @param object|array $data
602
     * @param string $objType
603
     * @return mixed
604
     */
605 4
    public function parseObjectValue($data, $objType)
606
    {
607 4
        $metadata = $this->factory->getMetadataFor($objType);
608 4
        if (!$metadata instanceof ObjectMetadataInterface) {
609
            throw new \InvalidArgumentException('Invalid object metadata');
610
        }
611
612 4
        $discClass = $this->getClassByDiscriminator($metadata, $data);
613 4
        if ((null !== $discClass) && ($discClass !== $objType)) {
614 1
            return $this->parseObjectValue($data, $discClass);
615
        }
616
617 4
        $objClass = $metadata->getClassName();
618 4
        $obj = new $objClass();
619
620 4
        $properties = $metadata->getProperties();
621 4
        foreach ($properties as $property) {
622 4
            $this->parseProperty($data, $obj, $property);
623 4
        }
624
625 4
        return $obj;
626
    }
627
628
    /**
629
     * Parse value that contains array
630
     *
631
     * @param object|array $data
632
     * @param string $path
633
     * @param array $params
634
     * @return array|null
635
     */
636 3
    public function parseArrayValue($data, $path, array $params)
637
    {
638 3
        $type = $params[0];
639 3
        $typeParams = $params[1];
640
641
        switch ($type) {
642 3
            case 'scalar':
643 1
                return $this->parseArray(
644 1
                    $data,
645 1
                    $path,
646
                    function ($data, $path, DataParser $parser) use ($typeParams) {
647 1
                        return $parser->parseScalarValue($data, $path, $typeParams);
648
                    }
649 1
                );
650
651 3
            case 'datetime':
652 1
                $format = (!empty($typeParams)) ? $typeParams : 'Y-m-d';
653 1
                return $this->parseArray(
654 1
                    $data,
655 1
                    $path,
656
                    function ($data, $path, DataParser $parser) use ($format) {
657 1
                        return $parser->parseDateTime($data, $path, $format);
658
                    }
659 1
                );
660
661 3
            case 'object':
662 3
                return $this->parseArray(
663 3
                    $data,
664 3
                    $path,
665
                    function ($data, $path, DataParser $parser) use ($typeParams) {
666 3
                        return $parser->parseResourceOrObject($data, $path, $typeParams);
667
                    }
668 3
                );
669
670 1
            case 'array':
671 1
                return $this->parseArray(
672 1
                    $data,
673 1
                    $path,
674
                    function ($data, $path, DataParser $parser) use ($typeParams) {
675 1
                        return $parser->parseArrayValue($data, $path, $typeParams);
676
                    }
677 1
                );
678
679 1
            case 'raw':
680 1
                return $this->parseArray(
681 1
                    $data,
682 1
                    $path,
683 1
                    function ($data, $path, DataParser $parser) {
684 1
                        return $parser->parseRaw($data, $path);
685
                    }
686 1
                );
687
688
            default:
689
                throw new \InvalidArgumentException(sprintf(
690
                    "Unsupported array item type '%s' specified",
691
                    $type
692
                ));
693
        }
694
    }
695
696
    /**
697
     * Parse scalar value
698
     *
699
     * @param object|array $data
700
     * @param string $path
701
     * @param string $type
702
     * @return bool|float|int|null|string
703
     */
704 6
    public function parseScalarValue($data, $path, $type)
705
    {
706
        switch ($type) {
707 6
            case 'string':
708 5
                return $this->parseString($data, $path);
709
710 2
            case 'bool':
711 2
            case 'boolean':
712 1
                return $this->parseBool($data, $path);
713
714 2
            case 'int':
715 2
            case 'integer':
716 2
                return $this->parseInt($data, $path);
717
718 1
            case 'float':
719 1
            case 'double':
720 1
                return $this->parseFloat($data, $path);
721
722
            default:
723
                throw new \InvalidArgumentException(sprintf("Unsupported scalar type '%s' specified", $type));
724
        }
725
    }
726
727
    /**
728
     * Convert any exception to JSON API exception
729
     *
730
     * @param \Exception $e
731
     * @param string $objType
732
     * @return JsonApiException
733
     */
734 2
    private function convertToApiException(\Exception $e, $objType)
735
    {
736 2
        $status = $e->getCode();
737 2
        $message = 'Failed to parse request';
738 2
        if (empty($status)) {
739 1
            $message = 'Internal server error';
740 1
            $status = 500;
741 1
        }
742
743 2
        $source = null;
744
        switch ($objType) {
745 2
            case 'document':
746 2
                $source = ['pointer' => $this->getPath()];
747 2
                break;
748
749
            case 'query':
750
                $source = ['parameter' => $this->getPath()];
751
                break;
752
        }
753
754 2
        $error = new Error(rand(), null, $status, self::ERROR_CODE, $message, $e->getMessage(), $source);
755
756 2
        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 8
    private function getClassByDiscriminator(ClassMetadataInterface $metadata, $data)
767
    {
768 8
        if (null === ($discField = $metadata->getDiscriminatorField())) {
769 7
            return null;
770
        }
771
772 6
        $discValue = $this->parseString($data, $discField->getDataPath());
773 6
        if (empty($discValue)) {
774 1
            $this->setPath($discField->getDataPath());
775
776 1
            throw new \InvalidArgumentException("Field value required and can not be empty", 422);
777
        }
778
779 5
        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 7
    private function isExcludedProperty(PropertyMetadataInterface $metadata)
789
    {
790 7
        $propertyGroups = $metadata->getGroups();
791 7
        foreach ($propertyGroups as $group) {
792 7
            if (in_array($group, $this->serializationGroups)) {
793 7
                return false;
794
            }
795
        }
796
797
        return true;
798
    }
799
}
800