Failed Conditions
Push — mixed-collections ( 23b545...27e0f6 )
by Michael
02:15
created

Assembler.php$0 ➔ visitCollectionNamedEntry()   A

Complexity

Conditions 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
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\Collection;
16
use Doctrine\Annotations\Parser\Ast\Collection\NamedEntry;
17
use Doctrine\Annotations\Parser\Ast\Collection\PositionalEntry;
18
use Doctrine\Annotations\Parser\Ast\ConstantFetch;
19
use Doctrine\Annotations\Parser\Ast\Pair;
20
use Doctrine\Annotations\Parser\Ast\Parameter\NamedParameter;
21
use Doctrine\Annotations\Parser\Ast\Parameter\UnnamedParameter;
22
use Doctrine\Annotations\Parser\Ast\Parameters;
23
use Doctrine\Annotations\Parser\Ast\Reference;
24
use Doctrine\Annotations\Parser\Ast\Scalar\BooleanScalar;
25
use Doctrine\Annotations\Parser\Ast\Scalar\FloatScalar;
26
use Doctrine\Annotations\Parser\Ast\Scalar\Identifier;
27
use Doctrine\Annotations\Parser\Ast\Scalar\IntegerScalar;
28
use Doctrine\Annotations\Parser\Ast\Scalar\NullScalar;
29
use Doctrine\Annotations\Parser\Ast\Scalar\StringScalar;
30
use Doctrine\Annotations\Parser\Reference\ReferenceResolver;
31
use Doctrine\Annotations\Parser\Scope;
32
use Doctrine\Annotations\Parser\Visitor\Visitor;
33
use SplObjectStorage;
34
use SplStack;
35
use function array_key_exists;
36
use function assert;
37
use function strtolower;
38
39
final class Assembler
40
{
41
    /** @var MetadataCollection */
42
    private $metadataCollection;
43
44
    /** @var ReferenceResolver */
45
    private $referenceResolver;
46
47
    /** @var Constructor */
48
    private $constructor;
49
50
    /** @var ClassReflectionProvider */
51
    private $classReflectionProvider;
52
53
    /** @var ReferenceAcceptor */
54
    private $referenceAcceptor;
55
56
    /** @var ConstantResolver */
57
    private $constantResolver;
58
59
    public function __construct(
60
        MetadataCollection $metadataCollection,
61
        ReferenceResolver $referenceResolver,
62
        Constructor $constructor,
63
        ClassReflectionProvider $classReflectionProvider,
64
        ReferenceAcceptor $referenceAcceptor,
65
        ConstantResolver $constantResolver
66
    ) {
67
        $this->metadataCollection      = $metadataCollection;
68
        $this->referenceResolver       = $referenceResolver;
69
        $this->constructor             = $constructor;
70
        $this->classReflectionProvider = $classReflectionProvider;
71
        $this->referenceAcceptor       = $referenceAcceptor;
72
        $this->constantResolver        = $constantResolver;
73
    }
74
75
    /**
76
     * @return object[]
77
     */
78
    public function collect(Annotations $node, Scope $scope) : iterable
79
    {
80
        $storage = new SplObjectStorage();
81
82
        $node->dispatch($this->createInternalVisitor($storage, $scope));
83
84
        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...
85
    }
86
87
    private function createInternalVisitor(SplObjectStorage $storage, Scope $scope) : Visitor
88
    {
89
        return new class (
90
            $this->metadataCollection,
91
            $this->referenceResolver,
92
            $this->constructor,
93
            $this->classReflectionProvider,
94
            $this->referenceAcceptor,
95
            $this->constantResolver,
96
            $scope,
97
            $storage
98
        ) implements Visitor {
99
            /** @var MetadataCollection */
100
            private $metadataCollection;
101
102
            /** @var ReferenceResolver */
103
            private $referenceResolver;
104
105
            /** @var Constructor */
106
            private $constructor;
107
108
            /** @var ClassReflectionProvider */
109
            private $classReflectionProvider;
110
111
            /** @var ReferenceAcceptor */
112
            private $referenceAcceptor;
113
114
            /** @var ConstantResolver */
115
            private $constantResolver;
116
117
            /** @var Scope */
118
            private $scope;
119
120
            /** @var SplObjectStorage<object> */
121
            private $storage;
122
123
            /** @var SplStack<mixed> */
124
            private $stack;
125
126
            public function __construct(
127
                MetadataCollection $metadataCollection,
128
                ReferenceResolver $referenceResolver,
129
                Constructor $constructor,
130
                ClassReflectionProvider $classReflectionProvider,
131
                ReferenceAcceptor $referenceAcceptor,
132
                ConstantResolver $constantResolver,
133
                Scope $scope,
134
                SplObjectStorage $storage
135
            ) {
136
                $this->metadataCollection      = $metadataCollection;
137
                $this->referenceResolver       = $referenceResolver;
138
                $this->constructor             = $constructor;
139
                $this->classReflectionProvider = $classReflectionProvider;
140
                $this->referenceAcceptor       = $referenceAcceptor;
141
                $this->constantResolver        = $constantResolver;
142
                $this->scope                   = $scope;
143
                $this->storage                 = $storage;
144
                $this->stack                   = new SplStack();
145
            }
146
147
            public function visitAnnotations(Annotations $annotations) : void
148
            {
149
                foreach ($annotations as $annotation) {
150
                    $stackSize = $this->stack->count();
151
152
                    $annotation->dispatch($this);
153
154
                    if ($this->stack->count() === $stackSize) {
155
                        continue;
156
                    }
157
158
                    $this->storage->attach($this->stack->pop());
159
                }
160
161
                assert($this->stack->isEmpty());
162
            }
163
164
            public function visitAnnotation(Annotation $annotation) : void
165
            {
166
                if (! $this->referenceAcceptor->accepts($annotation->getName(), $this->scope)) {
167
                    return;
168
                }
169
170
                $this->scope->increaseNestingLevel();
171
172
                $annotation->getParameters()->dispatch($this);
173
                $annotation->getName()->dispatch($this);
174
175
                $this->stack->push(
176
                    $this->constructor->construct(
177
                        $this->metadataCollection[$this->stack->pop()],
178
                        $this->scope,
179
                        $this->stack->pop()
180
                    )
181
                );
182
183
                $this->scope->decreaseNestingLevel();
184
            }
185
186
            public function visitReference(Reference $reference) : void
187
            {
188
                $this->stack->push($this->referenceResolver->resolve($reference, $this->scope));
189
            }
190
191
            public function visitParameters(Parameters $parameters) : void
192
            {
193
                $new = [];
194
195
                foreach ($parameters as $parameter) {
196
                    $parameter->dispatch($this);
197
198
                    assert(! array_key_exists($this->stack->current(), $new));
199
200
                    $new[$this->stack->pop()] = $this->stack->pop();
201
                }
202
203
                $this->stack->push($new);
204
            }
205
206
            public function visitUnnamedParameter(UnnamedParameter $parameter) : void
207
            {
208
                $parameter->getValue()->dispatch($this);
209
210
                $this->stack->push($this->stack->pop());
211
                $this->stack->push(null);
212
            }
213
214
            public function visitNamedParameter(NamedParameter $parameter) : void
215
            {
216
                $parameter->getValue()->dispatch($this);
217
                $parameter->getName()->dispatch($this);
218
                // pass through
219
            }
220
221
            public function visitIdentifier(Identifier $identifier) : void
222
            {
223
                $this->stack->push($identifier->getValue());
224
            }
225
226
            public function visitPair(Pair $pair) : void
227
            {
228
                $pair->getValue()->dispatch($this);
229
                $pair->getKey()->dispatch($this);
230
                // pass through
231
            }
232
233
            public function visitBooleanScalar(BooleanScalar $booleanScalar) : void
234
            {
235
                $this->stack->push($booleanScalar->getValue());
236
            }
237
238
            public function visitIntegerScalar(IntegerScalar $integerScalar) : void
239
            {
240
                $this->stack->push($integerScalar->getValue());
241
            }
242
243
            public function visitFloatScalar(FloatScalar $floatScalar) : void
244
            {
245
                $this->stack->push($floatScalar->getValue());
246
            }
247
248
            public function visitStringScalar(StringScalar $stringScalar) : void
249
            {
250
                $this->stack->push($stringScalar->getValue());
251
            }
252
253
            public function visitNullScalar(NullScalar $nullScalar) : void
254
            {
255
                $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...
256
            }
257
258
            public function visitCollection(Collection $collection) : void
259
            {
260
                $array = [];
261
262
                foreach ($collection as $item) {
263
                    $item->dispatch($this);
264
265
                    if ($item instanceof PositionalEntry) {
266
                        $array[] = $this->stack->pop();
267
                        continue;
268
                    }
269
270
                    assert($item instanceof NamedEntry);
271
272
                    [$value, $key] = [$this->stack->pop(), $this->stack->pop()];
273
274
                    $array[$key] = $value;
275
                }
276
277
                $this->stack->push($array);
278
            }
279
280
            public function visitCollectionPositionalEntry(PositionalEntry $entry) : void
281
            {
282
                $entry->getValue()->dispatch($this);
283
            }
284
285
            public function visitCollectionNamedEntry(NamedEntry $entry) : void
286
            {
287
                $entry->getKey()->dispatch($this);
288
                $entry->getValue()->dispatch($this);
289
            }
290
291
            public function visitConstantFetch(ConstantFetch $constantFetch) : void
292
            {
293
                $constantFetch->getName()->dispatch($this);
294
295
                $constantName = $this->stack->pop();
296
297
                $this->stack->push($this->constantResolver->resolveStandaloneConstant($constantName));
298
            }
299
300
            public function visitClassConstantFetch(ClassConstantFetch $classConstantFetch) : void
301
            {
302
                $classConstantFetch->getName()->dispatch($this);
303
                $classConstantFetch->getClass()->dispatch($this);
304
305
                $className    = $this->stack->pop();
306
                $constantName = $this->stack->pop();
307
308
                if (strtolower($constantName) === 'class') {
309
                    $this->stack->push($className);
310
                    return;
311
                }
312
313
                $this->stack->push($this->constantResolver->resolveClassOrInterfaceConstant($className, $constantName));
314
            }
315
        };
316
    }
317
}
318