Completed
Push — master ( 67ea50...1c7f24 )
by Daniel
13:43
created

ApiNormalizer::getId()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 4
c 2
b 0
f 0
dl 0
loc 6
ccs 0
cts 1
cp 0
rs 10
cc 2
nc 2
nop 1
crap 6
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Silverback\ApiComponentBundle\Serializer;
6
7
use Silverback\ApiComponentBundle\DataTransformer\DataTransformerInterface;
8
use Silverback\ApiComponentBundle\Entity\Component\AbstractComponent;
9
use Silverback\ApiComponentBundle\Entity\Content\AbstractContent;
10
use Silverback\ApiComponentBundle\Entity\Content\Page\Dynamic\DynamicContent;
11
use Silverback\ApiComponentBundle\Security\RestrictedResourceVoter;
12
use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
13
use Symfony\Component\PropertyAccess\PropertyAccess;
14
use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface;
15
use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
16
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
17
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
18
19
class ApiNormalizer implements ContextAwareNormalizerInterface, NormalizerAwareInterface, CacheableSupportsMethodInterface
20
{
21
    use NormalizerAwareTrait;
22
23
    private const ALREADY_CALLED = 'API_COMPONENT_BUNDLE_NORMALIZER_ALREADY_CALLED';
24
25
    /** @var iterable|DataTransformerInterface[] */
26
    private $dataTransformers;
27
28
    /** @var DataTransformerInterface[] */
29
    private $supportedTransformers = [];
30
31
    private $propertyAccessor;
32
    private $restrictedResourceVoter;
33
34
    public function __construct(iterable $dataTransformers = [], RestrictedResourceVoter $restrictedResourceVoter)
35
    {
36
        $this->dataTransformers = $dataTransformers;
37
        $this->propertyAccessor = PropertyAccess::createPropertyAccessor();
38
        $this->restrictedResourceVoter = $restrictedResourceVoter;
39
    }
40
41
    private function getId($object)
42
    {
43
        try {
44
            return $this->propertyAccessor->getValue($object, 'id');
45
        } catch (NoSuchPropertyException $e) {
46
            return true;
47
        }
48
    }
49
50
    public function supportsNormalization($data, $format = null, array $context = []): bool
51
    {
52
        if (!isset($context[self::ALREADY_CALLED])) {
53
            $context[self::ALREADY_CALLED] = [];
54
        }
55
        $this->supportedTransformers = [];
56
        if (!is_object($data) || in_array($this->getId($data), $context[self::ALREADY_CALLED], true)) {
57
            return false;
58
        }
59
60
        foreach ($this->dataTransformers as $transformer) {
61
            if ($transformer->supportsTransformation($data)) {
62
                $this->supportedTransformers[] = $transformer;
63
            }
64
        }
65
66
        if ($data instanceof AbstractComponent) {
67
            return true;
68
        }
69
70
        if ($this->restrictedResourceVoter->isSupported($data)) {
71
            return true;
72
        }
73
74
        return !empty($this->supportedTransformers);
75
    }
76
77
    public function normalize($object, $format = null, array $context = [])
78
    {
79
        if (!$this->restrictedResourceVoter->vote($object)) {
80
            return null;
81
        }
82
        $context[self::ALREADY_CALLED][] = $this->getId($object);
83
        if ($object instanceof AbstractComponent || $object instanceof DynamicContent || $object instanceof AbstractContent) {
84
            $context['groups'] = array_map(static function($grp) {
85
                if (strpos($grp, 'route') === 0) {
86
                    return str_replace('route', 'component', $grp);
87
                }
88
                return $grp;
89
            }, $context['groups']);
90
        }
91
        foreach ($this->supportedTransformers as $transformer) {
92
            $transformer->transform($object, $context);
93
        }
94
        return $this->normalizer->normalize($object, $format, $context);
95
    }
96
97
    public function hasCacheableSupportsMethod(): bool
98
    {
99
        return false;
100
    }
101
}
102