JMSAnnotationDriver::getMetadataForClass()   F
last analyzed

Complexity

Conditions 14
Paths 391

Size

Total Lines 53
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 28
CRAP Score 14.3828

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 14
eloc 32
c 1
b 0
f 0
nc 391
nop 1
dl 0
loc 53
ccs 28
cts 32
cp 0.875
crap 14.3828
rs 3.0458

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 Metadata\MergeableInterface;
12
use ReflectionClass;
13
14
/**
15
 * The annotation driver use JMS annotation
16
 *
17
 * Works only with php 7.2
18
 */
19
class JMSAnnotationDriver implements DriverInterface
20
{
21
    /**
22
     * @var JMSDriverInterface
23
     */
24
    private $driver;
25
26
    /**
27
     * AnnotationDriver constructor.
28
     *
29
     * @param JMSDriverInterface $driver
30
     */
31 4
    public function __construct(JMSDriverInterface $driver)
32
    {
33 4
        $this->driver = $driver;
34
    }
35
36
    /**
37
     * {@inheritDoc}
38
     */
39 4
    public function getMetadataForClass(ReflectionClass $class): ?ClassMetadata
40
    {
41 4
        $builder = new ClassMetadataBuilder($class);
42 4
        $jmsMetadata = $this->getJmsMetadata($class);
43
44 4
        if ($this->isJmsMetadataEmpty($jmsMetadata)) {
45 2
            return null;
46
        }
47
48 2
        if ($jmsMetadata instanceof JMSClassMetadata) {
49 2
            if (isset($jmsMetadata->postSerializeMethods[0])) {
50
                $builder->postDenormalization($jmsMetadata->postSerializeMethods[0]->name);
51
            }
52
        }
53
54
        /** @var JMSPropertyMetadata $metadata */
55 2
        foreach ($jmsMetadata->propertyMetadata as $property => $metadata) {
56 2
            if ($this->isPropertyStatic($metadata)) {
57 2
                continue;
58
            }
59
60 2
            $propertyBuilder = $builder->add($property);
61 2
            $propertyBuilder->alias($metadata->serializedName);
62 2
            $propertyBuilder->readOnly($metadata->readOnly);
63 2
            $propertyBuilder->inline($metadata->inline);
64
65 2
            if ($metadata->sinceVersion) {
66 2
                $propertyBuilder->since($metadata->sinceVersion);
67
            }
68 2
            if ($metadata->untilVersion) {
69 2
                $propertyBuilder->until($metadata->untilVersion);
70
            }
71 2
            if ($metadata->getter) {
72
                $propertyBuilder->readWith($metadata->getter);
73
            }
74 2
            if ($metadata->setter) {
75
                $propertyBuilder->writeWith($metadata->setter);
76
            }
77 2
            if ($metadata->groups) {
78 2
                $propertyBuilder->groups($metadata->groups);
79
            }
80 2
            if ($metadata->type) {
81 2
                if (JMSPropertyMetadata::isCollectionList($metadata->type)) {
82 2
                    $propertyBuilder->type($metadata->type['params'][0]['name'])->collection();
83 2
                } elseif (JMSPropertyMetadata::isCollectionMap($metadata->type)) {
84
                    $propertyBuilder->type($metadata->type['params'][1]['name'])->collection();
85
                } else {
86 2
                    $propertyBuilder->type($metadata->type['name']);
87
                }
88
            }
89
        }
90
91 2
        return $builder->build();
92
    }
93
94
    /**
95
     * Gets all the annotations from this class
96
     *
97
     * @param ReflectionClass $reflection
98
     *
99
     * @return JMSBaseClassMetadata|null
100
     */
101 4
    private function getJmsMetadata(ReflectionClass $reflection): ?JMSBaseClassMetadata
102
    {
103 4
        $metadata = null;
104
105
        do {
106 4
            $current = $this->driver->loadMetadataForClass($reflection);
107
108 4
            if ($metadata instanceof MergeableInterface && $current instanceof MergeableInterface) {
109 2
                $current->merge($metadata);
110
            }
111
112 4
            $metadata = $current;
113 4
            $reflection = $reflection->getParentClass();
114 4
        } while ($reflection);
115
116 4
        return $metadata;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $metadata could return the type Metadata\MergeableInterface which is incompatible with the type-hinted return Metadata\ClassMetadata|null. Consider adding an additional type-check to rule them out.
Loading history...
117
    }
118
119
    /**
120
     * Checks whether the property of this metadata is static.
121
     *
122
     * @param JMSPropertyMetadata $metadata
123
     *
124
     * @return bool
125
     */
126 2
    private function isPropertyStatic(JMSPropertyMetadata $metadata): bool
127
    {
128
        try {
129 2
            $reflection = new \ReflectionProperty($metadata->class, $metadata->name);
130
131 2
            return $reflection->isStatic();
132
        } catch (\ReflectionException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
133
        }
134
135
        return false;
136
    }
137
138
    /**
139
     * Check whether the jms metadata has been loaded by default
140
     *
141
     * @param JMSBaseClassMetadata|null $jmsMetadata
142
     *
143
     * @return bool
144
     * @psalm-assert-if-false !null $jmsMetadata
145
     */
146 4
    private function isJmsMetadataEmpty(?JMSBaseClassMetadata $jmsMetadata): bool
147
    {
148 4
        if (!$jmsMetadata) {
149
            return true;
150
        }
151
152 4
        foreach ($jmsMetadata->propertyMetadata as $metadata) {
153 4
            $class = get_class($metadata);
154 4
            $default = new $class($metadata->class, $metadata->name);
155 4
            $attributes = (array)$metadata;
156
157 4
            unset($attributes['serializedName']);
158
159 4
            foreach ($attributes as $attribute => $value) {
160 4
                if ($default->$attribute !== $value) {
161 2
                    return false;
162
                }
163
            }
164
        }
165
166 2
        return true;
167
    }
168
}
169