Passed
Branch new_stuff (69e2c3)
by JHONATAN
03:08
created

Normalizer   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 109
Duplicated Lines 0 %

Test Coverage

Coverage 91.49%

Importance

Changes 0
Metric Value
wmc 22
dl 0
loc 109
ccs 43
cts 47
cp 0.9149
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A normalizeIfSupported() 0 11 3
A supportsNormalization() 0 3 2
C extractData() 0 52 13
A normalize() 0 9 2
A setNormalizer() 0 3 1
1
<?php
2
3
namespace Vox\Serializer;
4
5
use Metadata\MetadataFactoryInterface;
6
use RuntimeException;
7
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
8
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
9
use Vox\Data\Mapping\Bindings;
10
use Vox\Data\Mapping\Exclude;
11
use Vox\Metadata\ClassMetadata;
12
use Vox\Metadata\PropertyMetadata;
13
14
/**
15
 * A data normalized aimed to be used with symfony serializer component
16
 * 
17
 * @author Jhonatan Teixeira <[email protected]>
18
 */
19
class Normalizer implements NormalizerInterface, NormalizerAwareInterface
20
{
21
    /**
22
     * @var MetadataFactoryInterface
23
     */
24
    private $metadataFactory;
25
26
    /**
27
     * @var NormalizerInterface
28
     */
29
    private $normalizer;
30
31
    /**
32
     * @var \SplObjectStorage
33
     */
34
    private $storage;
35
    
36 22
    public function __construct(MetadataFactoryInterface $metadataFactory)
37
    {
38 22
        $this->metadataFactory = $metadataFactory;
39 22
        $this->storage = new \SplObjectStorage();
40 22
    }
41
    
42 5
    public function normalize($object, $format = null, array $context = [])
43
    {
44 5
        if ($this->storage->offsetExists($object)) {
45
            return $this->storage[$object];
46
        }
47
48 5
        $data = $this->extractData($object, $format, $context);
49
50 5
        return $data;
51
    }
52
53 5
    private function extractData($object, string $format = null, array $context = []): array
54
    {
55 5
        $objectMetadata = $this->metadataFactory->getMetadataForClass(get_class($object));
56
57 5
        if (!$objectMetadata instanceof ClassMetadata) {
58
            throw new RuntimeException('invalid metadata class');
59
        }
60
61 5
        $data = [];
62
63 5
        if ($objectMetadata->reflection->getParentClass()) {
64
            $data['type'] = get_class($object);
65
        }
66
67
        /* @var $propertyMetadata PropertyMetadata */
68 5
        foreach ($objectMetadata->propertyMetadata as $propertyMetadata) {
69 5
            $binding = $propertyMetadata->getAnnotation(Bindings::class);
70 5
            $value   = $propertyMetadata->getValue($object);
71
72 5
            if ($propertyMetadata->hasAnnotation(Exclude::class)
73 5
                && $propertyMetadata->getAnnotation(Exclude::class)->output) {
74
                continue;
75
            }
76
77 5
            if (is_array($value)
78 5
                && (preg_match('/\[\]$/', $propertyMetadata->type) || $propertyMetadata->type == 'array')) {
79 1
                $items = [];
80
81 1
                foreach ($value as $index => $item) {
82 1
                    $items[$index] = $this->normalizeIfSupported($item, $format, $context);
83
                }
84
85 1
                $value = $items;
86
            }
87
88 5
            if (is_object($value)) {
89 3
                $value = $this->normalizeIfSupported($value, $format, $context);
90
            }
91
92 5
            $target = $binding ? ($binding->target ?? $binding->source ?? null) : $propertyMetadata->name;
93
94 5
            if (preg_match('/\./', $target)) {
95 2
                $path = implode("']['", explode('.', sprintf("['%s']", $target)));
96 2
                eval("\$data$path = \$value;");
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
97
            } else {
98 5
                $data[$target] = $value;
99
            }
100
        }
101
102 5
        $this->storage[$object] = $data;
103
104 5
        return $data;
105
    }
106
    
107 3
    private function normalizeIfSupported($value, string $format = null, array $context = [])
108
    {
109 3
        if (isset($this->normalizer)) {
110 1
            return $this->normalizer->normalize($value, $format, $context);
111
        }
112
113 2
        if ($this->supportsNormalization($value)) {
114 2
            return $this->normalize($value, $format, $context);
115
        }
116
        
117 1
        return $value;
118
    }
119
120 5
    public function supportsNormalization($data, $format = null): bool
121
    {
122 5
        return is_object($data) && !$data instanceof \DateTime;
123
    }
124
125 20
    public function setNormalizer(NormalizerInterface $normalizer)
126
    {
127 20
        $this->normalizer = $normalizer;
128 20
    }
129
}
130