Completed
Push — standalone ( f309de...aaef72 )
by Philip
05:10
created

AnnotationDriver   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 184
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 88.76%

Importance

Changes 0
Metric Value
wmc 33
lcom 1
cbo 8
dl 0
loc 184
ccs 79
cts 89
cp 0.8876
rs 9.3999
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
F loadMetadataForClass() 0 137 26
A methodToPropertyName() 0 17 4
A parseIncludable() 0 9 2
1
<?php
2
namespace Dontdrinkandroot\RestBundle\Metadata\Driver;
3
4
use Doctrine\Common\Annotations\Reader;
5
use Dontdrinkandroot\RestBundle\Metadata\Annotation\Excluded;
6
use Dontdrinkandroot\RestBundle\Metadata\Annotation\Includable;
7
use Dontdrinkandroot\RestBundle\Metadata\Annotation\Postable;
8
use Dontdrinkandroot\RestBundle\Metadata\Annotation\Puttable;
9
use Dontdrinkandroot\RestBundle\Metadata\Annotation\RootResource;
10
use Dontdrinkandroot\RestBundle\Metadata\Annotation\SubResource;
11
use Dontdrinkandroot\RestBundle\Metadata\Annotation\Virtual;
12
use Dontdrinkandroot\RestBundle\Metadata\ClassMetadata;
13
use Dontdrinkandroot\RestBundle\Metadata\PropertyMetadata;
14
use Metadata\Driver\DriverInterface;
15
16
class AnnotationDriver implements DriverInterface
17
{
18
    private $reader;
19
20
    /**
21
     * @var DriverInterface
22
     */
23
    private $doctrineDriver;
24
25 76
    public function __construct(Reader $reader, DriverInterface $doctrineDriver)
26
    {
27 76
        $this->reader = $reader;
28 76
        $this->doctrineDriver = $doctrineDriver;
29 76
    }
30
31
    /**
32
     * {@inheritdoc}
33
     */
34 70
    public function loadMetadataForClass(\ReflectionClass $class)
35
    {
36
        /** @var ClassMetadata $ddrRestClassMetadata */
37 70
        $ddrRestClassMetadata = $this->doctrineDriver->loadMetadataForClass($class);
38 70
        if (null === $ddrRestClassMetadata) {
39
            $ddrRestClassMetadata = new ClassMetadata($class->getName());
40
        }
41
42
        /** @var RootResource $restResourceAnnotation */
43 70
        $restResourceAnnotation = $this->reader->getClassAnnotation($class, RootResource::class);
44 70
        if (null !== $restResourceAnnotation) {
45
46 68
            $ddrRestClassMetadata->setRestResource(true);
47
48 68
            if (null !== $restResourceAnnotation->namePrefix) {
49
                $ddrRestClassMetadata->setNamePrefix($restResourceAnnotation->namePrefix);
50
            }
51
52 68
            if (null !== $restResourceAnnotation->pathPrefix) {
53 38
                $ddrRestClassMetadata->setPathPrefix($restResourceAnnotation->pathPrefix);
54
            }
55
56 68
            if (null !== $restResourceAnnotation->service) {
57
                $ddrRestClassMetadata->setService($restResourceAnnotation->service);
58
            }
59
60 68
            if (null !== $restResourceAnnotation->controller) {
61
                $ddrRestClassMetadata->setController($restResourceAnnotation->controller);
62
            }
63
64 68
            $ddrRestClassMetadata->idField = $restResourceAnnotation->idField;
65
66 68
            if (null !== $restResourceAnnotation->methods) {
67 68
                $methods = [];
68 68
                $methodAnnotations = $restResourceAnnotation->methods;
69 68
                foreach ($methodAnnotations as $methodAnnotation) {
70 68
                    $methods[$methodAnnotation->name] = $methodAnnotation;
71
                }
72 68
                $ddrRestClassMetadata->setMethods($methods);
73
            }
74
75 68
            if (null !== $restResourceAnnotation->methods) {
76 68
                $ddrRestClassMetadata->setMethods($restResourceAnnotation->methods);
0 ignored issues
show
Documentation introduced by
$restResourceAnnotation->methods is of type array<integer,object<Don...ata\Annotation\Method>>, but the function expects a array<integer,string>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
77
            }
78
        }
79
80 70
        foreach ($class->getProperties() as $reflectionProperty) {
81
82 70
            $propertyMetadata = $ddrRestClassMetadata->getPropertyMetadata($reflectionProperty->getName());
83 70
            if (null === $propertyMetadata) {
84 44
                $propertyMetadata = new PropertyMetadata($class->getName(), $reflectionProperty->getName());
85
            }
86
87
            /** @var Puttable $puttableAnnotation */
88 70
            if (null !== $puttableAnnotation = $this->reader->getPropertyAnnotation(
89
                    $reflectionProperty,
90 70
                    Puttable::class
91
                )
92
            ) {
93 48
                $propertyMetadata->setPuttable(true);
94 48
                if (null !== $puttableAnnotation->right) {
95 16
                    $propertyMetadata->setPuttableRight($puttableAnnotation->right);
96
                }
97
            }
98
99
            /** @Var Postable $postableAnnotation */
100 70
            if (null !== $postableAnnotation = $this->reader->getPropertyAnnotation(
101
                    $reflectionProperty,
102 70
                    Postable::class
103
                )
104
            ) {
105 48
                $propertyMetadata->setPostable(true);
106 48
                if (null !== $postableAnnotation->right) {
107 16
                    $propertyMetadata->setPostableRight($postableAnnotation->right);
108
                }
109
            }
110
111 70
            $includableAnnotation = $this->reader->getPropertyAnnotation($reflectionProperty, Includable::class);
112 70
            if (null !== $includableAnnotation) {
113 58
                $this->parseIncludable($propertyMetadata, $includableAnnotation);
114
            }
115
116 70
            $excludedAnnotation = $this->reader->getPropertyAnnotation($reflectionProperty, Excluded::class);
117 70
            if (null !== $excludedAnnotation) {
118 58
                $propertyMetadata->setExcluded(true);
119
            }
120
121
            /** @var SubResource $subResourceAnnotation */
122 70
            $subResourceAnnotation = $this->reader->getPropertyAnnotation($reflectionProperty, SubResource::class);
123 70
            if (null !== $subResourceAnnotation) {
124
125 56
                $propertyMetadata->setSubResource(true);
126
127 56
                if (null !== $subResourceAnnotation->path) {
128
                    $propertyMetadata->setSubResourcePath($subResourceAnnotation->path);
129
                }
130
131 56
                if (null !== $subResourceAnnotation->methods) {
132 56
                    $methods = [];
133 56
                    $methodAnnotations = $subResourceAnnotation->methods;
134 56
                    foreach ($methodAnnotations as $methodAnnotation) {
135 56
                        $methods[$methodAnnotation->name] = $methodAnnotation;
136
                    }
137 56
                    $propertyMetadata->setMethods($methods);
138
                }
139
            }
140
141 70
            $ddrRestClassMetadata->addPropertyMetadata($propertyMetadata);
142
        }
143
144 70
        foreach ($class->getMethods() as $reflectionMethod) {
145 70
            $virtualAnnotation = $this->reader->getMethodAnnotation($reflectionMethod, Virtual::class);
146 70
            if (null !== $virtualAnnotation) {
147
148 24
                $name = $this->methodToPropertyName($reflectionMethod);
149
150 24
                $propertyMetadata = $ddrRestClassMetadata->getPropertyMetadata($name);
151 24
                if (null === $propertyMetadata) {
152 24
                    $propertyMetadata = new PropertyMetadata($class->getName(), $name);
153
                }
154 24
                $propertyMetadata->setVirtual(true);
155
156
                /** @var Includable|null $includableAnnotation */
157 24
                if (null !== $includableAnnotation = $this->reader->getMethodAnnotation(
158
                        $reflectionMethod,
159 24
                        Includable::class
160
                    )
161
                ) {
162 24
                    $this->parseIncludable($propertyMetadata, $includableAnnotation);
163
                }
164
165 70
                $ddrRestClassMetadata->addPropertyMetadata($propertyMetadata);
166
            }
167
        }
168
169 70
        return $ddrRestClassMetadata;
170
    }
171
172 24
    private function methodToPropertyName(\ReflectionMethod $reflectionMethod): string
173
    {
174 24
        $name = $reflectionMethod->getName();
1 ignored issue
show
Bug introduced by
Consider using $reflectionMethod->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
175 24
        if (0 === strpos($name, 'get')) {
176 24
            return lcfirst(substr($name, 3));
177
        }
178
179
        if (0 === strpos($name, 'is')) {
180
            return lcfirst(substr($name, 2));
181
        }
182
183
        if (0 === strpos($name, 'has')) {
184
            return lcfirst(substr($name, 3));
185
        }
186
187
        return $name;
188
    }
189
190 58
    public function parseIncludable(PropertyMetadata $propertyMetadata, Includable $includableAnnotation): void
191
    {
192 58
        $paths = $includableAnnotation->paths;
193 58
        if (null === $paths) {
194 56
            $paths = [$propertyMetadata->name];
195
        }
196 58
        $propertyMetadata->setIncludable(true);
197 58
        $propertyMetadata->setIncludablePaths($paths);
0 ignored issues
show
Documentation introduced by
$paths is of type array<integer,string>, but the function expects a null|array<integer,object<string>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
198 58
    }
199
}
200