Passed
Push — master ( f65755...df5a12 )
by Sébastien
11:13
created

JMSAnnotationDriver::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
1
<?php
2
3
namespace Bdf\Serializer\Metadata\Driver;
4
5
use Bdf\Serializer\Metadata\Builder\ClassMetadataBuilder;
6
use Bdf\Serializer\Metadata\ClassMetadata;
7
use JMS\Serializer\Metadata\ClassMetadata as JMSClassMetadata;
8
use JMS\Serializer\Metadata\PropertyMetadata as JMSPropertyMetadata;
9
use Metadata\ClassMetadata as JMSBaseClassMetadata;
10
use Metadata\Driver\DriverInterface as JMSDriverInterface;
11
use ReflectionClass;
12
13
/**
14
 * The annotation driver use JMS annotation
15
 *
16
 * Works only with php 7.2
17
 */
18
class JMSAnnotationDriver implements DriverInterface
19
{
20
    /**
21
     * @var JMSDriverInterface
22
     */
23
    private $driver;
24
25
    /**
26
     * AnnotationDriver constructor.
27
     *
28
     * @param JMSDriverInterface $driver
29
     */
30
    public function __construct(JMSDriverInterface $driver)
31
    {
32
        $this->driver = $driver;
33
    }
34
35
    /**
36
     * {@inheritDoc}
37
     */
38
    public function getMetadataForClass(ReflectionClass $class): ?ClassMetadata
39
    {
40
        $builder = new ClassMetadataBuilder($class);
41
        $jmsMetadata = $this->getJmsMetadata($class);
42
43
        if ($this->isJmsMetadataEmpty($jmsMetadata)) {
44
            return null;
45
        }
46
47
        if ($jmsMetadata instanceof JMSClassMetadata) {
48
            if (isset($jmsMetadata->postSerializeMethods[0])) {
49
                $builder->postDenormalization($jmsMetadata->postSerializeMethods[0]->name);
50
            }
51
        }
52
53
        /** @var JMSPropertyMetadata $metadata */
54
        foreach ($jmsMetadata->propertyMetadata as $property => $metadata) {
55
            if ($this->isPropertyStatic($metadata)) {
56
                continue;
57
            }
58
59
            $propertyBuilder = $builder->add($property);
60
            $propertyBuilder->alias($metadata->serializedName);
61
            $propertyBuilder->readOnly($metadata->readOnly);
62
            $propertyBuilder->inline($metadata->inline);
63
64
            if ($metadata->sinceVersion) {
65
                $propertyBuilder->since($metadata->sinceVersion);
66
            }
67
            if ($metadata->untilVersion) {
68
                $propertyBuilder->until($metadata->untilVersion);
69
            }
70
            if ($metadata->getter) {
71
                $propertyBuilder->readWith($metadata->getter);
72
            }
73
            if ($metadata->setter) {
74
                $propertyBuilder->writeWith($metadata->setter);
75
            }
76
            if ($metadata->groups) {
77
                $propertyBuilder->groups($metadata->groups);
78
            }
79
            if ($metadata->type) {
80
                if (JMSPropertyMetadata::isCollectionList($metadata->type)) {
0 ignored issues
show
Bug introduced by
The method isCollectionList() does not exist on JMS\Serializer\Metadata\PropertyMetadata. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

80
                if (JMSPropertyMetadata::/** @scrutinizer ignore-call */ isCollectionList($metadata->type)) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
81
                    $propertyBuilder->type($metadata->type['params'][0]['name'])->collection();
82
                } elseif (JMSPropertyMetadata::isCollectionMap($metadata->type)) {
0 ignored issues
show
Bug introduced by
The method isCollectionMap() does not exist on JMS\Serializer\Metadata\PropertyMetadata. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

82
                } elseif (JMSPropertyMetadata::/** @scrutinizer ignore-call */ isCollectionMap($metadata->type)) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
83
                    $propertyBuilder->type($metadata->type['params'][1]['name'])->collection();
84
                } else {
85
                    $propertyBuilder->type($metadata->type['name']);
86
                }
87
            }
88
        }
89
90
        return $builder->build();
91
    }
92
93
    /**
94
     * Gets all the annotations from this class
95
     *
96
     * @param ReflectionClass $reflection
97
     *
98
     * @return JMSBaseClassMetadata|null
99
     */
100
    private function getJmsMetadata(ReflectionClass $reflection): ?JMSBaseClassMetadata
101
    {
102
        $metadata = null;
103
104
        do {
105
            $current = $this->driver->loadMetadataForClass($reflection);
106
107
            if ($metadata && $current) {
108
                $current->merge($metadata);
0 ignored issues
show
Bug introduced by
The method merge() does not exist on Metadata\ClassMetadata. It seems like you code against a sub-type of Metadata\ClassMetadata such as Metadata\MergeableClassMetadata. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

108
                $current->/** @scrutinizer ignore-call */ 
109
                          merge($metadata);
Loading history...
109
            }
110
111
            $metadata = $current;
112
            $reflection = $reflection->getParentClass();
113
        } while ($reflection);
114
115
        return $metadata;
116
    }
117
118
    /**
119
     * Checks whether the property of this metadata is static.
120
     *
121
     * @param JMSPropertyMetadata $metadata
122
     *
123
     * @return bool
124
     */
125
    private function isPropertyStatic(JMSPropertyMetadata $metadata): bool
126
    {
127
        try {
128
            $reflection = new \ReflectionProperty($metadata->class, $metadata->name);
129
130
            return $reflection->isStatic();
131
        } catch (\ReflectionException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
132
        }
133
134
        return false;
135
    }
136
137
    /**
138
     * Check whether the jms metadata has been loaded by default
139
     *
140
     * @param JMSBaseClassMetadata|null $jmsMetadata
141
     *
142
     * @return bool
143
     */
144
    private function isJmsMetadataEmpty(?JMSBaseClassMetadata $jmsMetadata): bool
145
    {
146
        if (!$jmsMetadata) {
147
            return true;
148
        }
149
150
        foreach ($jmsMetadata->propertyMetadata as $metadata) {
151
            $class = get_class($metadata);
152
            $default = new $class($metadata->class, $metadata->name);
153
            $attributes = (array)$metadata;
154
155
            unset($attributes['serializedName']);
156
157
            foreach ($attributes as $attribute => $value) {
158
                if ($default->$attribute !== $value) {
159
                    return false;
160
                }
161
            }
162
        }
163
164
        return true;
165
    }
166
}
167