Failed Conditions
Push — new-parser-ast-metadata ( e8e091...17d881 )
by Michael
21s
created

bler/Assembler.php$0   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 217
Duplicated Lines 0 %

Test Coverage

Coverage 93.2%

Importance

Changes 0
Metric Value
wmc 25
dl 0
loc 217
ccs 96
cts 103
cp 0.932
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Annotations\Assembler;
6
7
use Doctrine\Annotations\Assembler\Acceptor\ReferenceAcceptor;
8
use Doctrine\Annotations\Assembler\Constant\ConstantResolver;
9
use Doctrine\Annotations\Constructor\Constructor;
10
use Doctrine\Annotations\Metadata\MetadataCollection;
11
use Doctrine\Annotations\Metadata\Reflection\ClassReflectionProvider;
12
use Doctrine\Annotations\Parser\Ast\Annotation;
13
use Doctrine\Annotations\Parser\Ast\Annotations;
14
use Doctrine\Annotations\Parser\Ast\ClassConstantFetch;
15
use Doctrine\Annotations\Parser\Ast\Collection\ListCollection;
16
use Doctrine\Annotations\Parser\Ast\Collection\MapCollection;
17
use Doctrine\Annotations\Parser\Ast\ConstantFetch;
18
use Doctrine\Annotations\Parser\Ast\Pair;
19
use Doctrine\Annotations\Parser\Ast\Parameter\NamedParameter;
20
use Doctrine\Annotations\Parser\Ast\Parameter\UnnamedParameter;
21
use Doctrine\Annotations\Parser\Ast\Parameters;
22
use Doctrine\Annotations\Parser\Ast\Reference;
23
use Doctrine\Annotations\Parser\Ast\Scalar\BooleanScalar;
24
use Doctrine\Annotations\Parser\Ast\Scalar\FloatScalar;
25
use Doctrine\Annotations\Parser\Ast\Scalar\Identifier;
26
use Doctrine\Annotations\Parser\Ast\Scalar\IntegerScalar;
27
use Doctrine\Annotations\Parser\Ast\Scalar\NullScalar;
28
use Doctrine\Annotations\Parser\Ast\Scalar\StringScalar;
29
use Doctrine\Annotations\Parser\Reference\ReferenceResolver;
30
use Doctrine\Annotations\Parser\Scope;
31
use Doctrine\Annotations\Parser\Visitor\Visitor;
32
use SplObjectStorage;
33
use SplStack;
34
use function array_key_exists;
35
use function assert;
36
use function strtolower;
37
38
final class Assembler
39
{
40
    /** @var MetadataCollection */
41
    private $metadataCollection;
42
43
    /** @var ReferenceResolver */
44
    private $referenceResolver;
45
46
    /** @var Constructor */
47
    private $constructor;
48
49
    /** @var ClassReflectionProvider */
50
    private $classReflectionProvider;
51
52
    /** @var ReferenceAcceptor */
53
    private $referenceAcceptor;
54
55
    /** @var ConstantResolver */
56
    private $constantResolver;
57
58 9
    public function __construct(
59
        MetadataCollection $metadataCollection,
60
        ReferenceResolver $referenceResolver,
61
        Constructor $constructor,
62
        ClassReflectionProvider $classReflectionProvider,
63
        ReferenceAcceptor $referenceAcceptor,
64
        ConstantResolver $constantResolver
65
    ) {
66 9
        $this->metadataCollection      = $metadataCollection;
67 9
        $this->referenceResolver       = $referenceResolver;
68 9
        $this->constructor             = $constructor;
69 9
        $this->classReflectionProvider = $classReflectionProvider;
70 9
        $this->referenceAcceptor       = $referenceAcceptor;
71 9
        $this->constantResolver        = $constantResolver;
72 9
    }
73
74
    /**
75
     * @return object[]
76
     */
77 9
    public function collect(Annotations $node, Scope $scope) : iterable
78
    {
79 9
        $storage = new SplObjectStorage();
80
81 9
        $node->dispatch($this->createInternalVisitor($storage, $scope));
82
83 9
        return yield from $storage;
0 ignored issues
show
Bug Best Practice introduced by
The expression YieldFromNode returns the type Generator which is incompatible with the documented return type array<mixed,object>.
Loading history...
84
    }
85
86
    private function createInternalVisitor(SplObjectStorage $storage, Scope $scope) : Visitor
87
    {
88
        return new class (
89
            $this->metadataCollection,
90
            $this->referenceResolver,
91
            $this->constructor,
92
            $this->classReflectionProvider,
93
            $this->referenceAcceptor,
94
            $this->constantResolver,
95
            $scope,
96
            $storage
97
        ) implements Visitor {
98
            /** @var MetadataCollection */
99
            private $metadataCollection;
100
101
            /** @var ReferenceResolver */
102
            private $referenceResolver;
103
104
            /** @var Constructor */
105
            private $constructor;
106
107
            /** @var ClassReflectionProvider */
108
            private $classReflectionProvider;
109
110
            /** @var ReferenceAcceptor */
111
            private $referenceAcceptor;
112
113
            /** @var ConstantResolver */
114
            private $constantResolver;
115
116
            /** @var Scope */
117
            private $scope;
118
119
            /** @var SplObjectStorage<object> */
120
            private $storage;
121
122
            /** @var SplStack<mixed> */
123
            private $stack;
124
125 9
            public function __construct(
126
                MetadataCollection $metadataCollection,
127
                ReferenceResolver $referenceResolver,
128
                Constructor $constructor,
129
                ClassReflectionProvider $classReflectionProvider,
130
                ReferenceAcceptor $referenceAcceptor,
131
                ConstantResolver $constantResolver,
132
                Scope $scope,
133
                SplObjectStorage $storage
134
            ) {
135 9
                $this->metadataCollection      = $metadataCollection;
136 9
                $this->referenceResolver       = $referenceResolver;
137 9
                $this->constructor             = $constructor;
138 9
                $this->classReflectionProvider = $classReflectionProvider;
139 9
                $this->referenceAcceptor       = $referenceAcceptor;
140 9
                $this->constantResolver        = $constantResolver;
141 9
                $this->scope                   = $scope;
142 9
                $this->storage                 = $storage;
143 9
                $this->stack                   = new SplStack();
144 9
            }
145
146 9
            public function visitAnnotations(Annotations $annotations) : void
147
            {
148 9
                foreach ($annotations as $annotation) {
149 9
                    $stackSize = $this->stack->count();
150
151 9
                    $annotation->dispatch($this);
152
153 9
                    if ($this->stack->count() === $stackSize) {
154 5
                        continue;
155
                    }
156
157 9
                    $this->storage->attach($this->stack->pop());
158
                }
159
160 9
                assert($this->stack->isEmpty());
161 9
            }
162
163 9
            public function visitAnnotation(Annotation $annotation) : void
164
            {
165 9
                if (! $this->referenceAcceptor->accepts($annotation->getName(), $this->scope)) {
166 5
                    return;
167
                }
168
169 9
                $this->scope->increaseNestingLevel();
170
171 9
                $annotation->getParameters()->dispatch($this);
172 9
                $annotation->getName()->dispatch($this);
173
174 9
                $this->stack->push(
175 9
                    $this->constructor->construct(
176 9
                        $this->metadataCollection[$this->stack->pop()],
177 9
                        $this->scope,
178 9
                        $this->stack->pop()
179
                    )
180
                );
181
182 9
                $this->scope->decreaseNestingLevel();
183 9
            }
184
185 9
            public function visitReference(Reference $reference) : void
186
            {
187 9
                $this->stack->push($this->referenceResolver->resolve($reference, $this->scope));
188 9
            }
189
190 9
            public function visitParameters(Parameters $parameters) : void
191
            {
192 9
                $new = [];
193
194 9
                foreach ($parameters as $parameter) {
195 9
                    $parameter->dispatch($this);
196
197 9
                    assert(! array_key_exists($this->stack->current(), $new));
198
199 9
                    $new[$this->stack->pop()] = $this->stack->pop();
200
                }
201
202 9
                $this->stack->push($new);
203 9
            }
204
205 6
            public function visitUnnamedParameter(UnnamedParameter $parameter) : void
206
            {
207 6
                $parameter->getValue()->dispatch($this);
208
209 6
                $this->stack->push($this->stack->pop());
210 6
                $this->stack->push(null);
211 6
            }
212
213 4
            public function visitNamedParameter(NamedParameter $parameter) : void
214
            {
215 4
                $parameter->getValue()->dispatch($this);
216 4
                $parameter->getName()->dispatch($this);
217
                // pass through
218 4
            }
219
220 4
            public function visitIdentifier(Identifier $identifier) : void
221
            {
222 4
                $this->stack->push($identifier->getValue());
223 4
            }
224
225 1
            public function visitPair(Pair $pair) : void
226
            {
227 1
                $pair->getValue()->dispatch($this);
228 1
                $pair->getKey()->dispatch($this);
229
                // pass through
230 1
            }
231
232 1
            public function visitBooleanScalar(BooleanScalar $booleanScalar) : void
233
            {
234 1
                $this->stack->push($booleanScalar->getValue());
235 1
            }
236
237 3
            public function visitIntegerScalar(IntegerScalar $integerScalar) : void
238
            {
239 3
                $this->stack->push($integerScalar->getValue());
240 3
            }
241
242 1
            public function visitFloatScalar(FloatScalar $floatScalar) : void
243
            {
244 1
                $this->stack->push($floatScalar->getValue());
245 1
            }
246
247 7
            public function visitStringScalar(StringScalar $stringScalar) : void
248
            {
249 7
                $this->stack->push($stringScalar->getValue());
250 7
            }
251
252 1
            public function visitNullScalar(NullScalar $nullScalar) : void
253
            {
254 1
                $this->stack->push($nullScalar->getValue());
0 ignored issues
show
Bug introduced by
Are you sure the usage of $nullScalar->getValue() targeting Doctrine\Annotations\Par...\NullScalar::getValue() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
255 1
            }
256
257 3
            public function visitListCollection(ListCollection $listCollection) : void
258
            {
259 3
                $list = [];
260
261 3
                foreach ($listCollection as $listItem) {
262 3
                    $listItem->dispatch($this);
263
264 3
                    $list[] = $this->stack->pop();
265
                }
266
267 3
                $this->stack->push($list);
268 3
            }
269
270 1
            public function visitMapCollection(MapCollection $mapCollection) : void
271
            {
272 1
                $map = [];
273
274 1
                foreach ($mapCollection as $mapItem) {
275 1
                    $mapItem->dispatch($this);
276 1
                    $map[$this->stack->pop()] = $this->stack->pop();
277
                }
278
279 1
                $this->stack->push($map);
280 1
            }
281
282
            public function visitConstantFetch(ConstantFetch $constantFetch) : void
283
            {
284
                $constantFetch->getName()->dispatch($this);
285
286
                $constantName = $this->stack->pop();
287
288
                $this->stack->push($this->constantResolver->resolveStandaloneConstant($constantName));
289
            }
290
291 1
            public function visitClassConstantFetch(ClassConstantFetch $classConstantFetch) : void
292
            {
293 1
                $classConstantFetch->getName()->dispatch($this);
294 1
                $classConstantFetch->getClass()->dispatch($this);
295
296 1
                $className    = $this->stack->pop();
297 1
                $constantName = $this->stack->pop();
298
299 1
                if (strtolower($constantName) === 'class') {
300
                    $this->stack->push($className);
301
                    return;
302
                }
303
304 1
                $this->stack->push($this->constantResolver->resolveClassOrInterfaceConstant($className, $constantName));
305 1
            }
306
        };
307
    }
308
}
309