AnnotationDriver::attachPropertyOverrides()   C
last analyzed

Complexity

Conditions 13
Paths 11

Size

Total Lines 105
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 47
CRAP Score 13.0365

Importance

Changes 0
Metric Value
cc 13
eloc 53
c 0
b 0
f 0
nc 11
nop 4
dl 0
loc 105
ccs 47
cts 50
cp 0.94
crap 13.0365
rs 6.6166

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 /** @noinspection ALL */
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ORM\Mapping\Driver;
6
7
use Doctrine\Common\Annotations\AnnotationReader;
8
use Doctrine\Common\Annotations\Reader;
9
use Doctrine\ORM\Annotation;
10
use Doctrine\ORM\Cache\Exception\CacheException;
11
use Doctrine\ORM\Events;
12
use Doctrine\ORM\Mapping;
13
use Doctrine\ORM\Mapping\Builder;
14
use FilesystemIterator;
15
use RecursiveDirectoryIterator;
16
use RecursiveIteratorIterator;
17
use RecursiveRegexIterator;
18
use ReflectionClass;
19
use ReflectionException;
20
use ReflectionMethod;
21
use ReflectionProperty;
22
use RegexIterator;
23
use RuntimeException;
24
use UnexpectedValueException;
25
use function array_merge;
26
use function array_unique;
27
use function class_exists;
28
use function constant;
29
use function get_class;
30
use function get_declared_classes;
31
use function in_array;
32
use function is_dir;
33
use function is_numeric;
34
use function preg_match;
35
use function preg_quote;
36
use function realpath;
37
use function str_replace;
38
use function strpos;
39
40
/**
41
 * The AnnotationDriver reads the mapping metadata from docblock annotations.
42
 */
43
class AnnotationDriver implements MappingDriver
44
{
45
    /** @var int[] */
46
    protected $entityAnnotationClasses = [
47
        Annotation\Entity::class           => 1,
48
        Annotation\MappedSuperclass::class => 2,
49
    ];
50
51
    /**
52
     * The AnnotationReader.
53
     *
54
     * @var AnnotationReader
55
     */
56
    protected $reader;
57
58
    /**
59
     * The paths where to look for mapping files.
60
     *
61
     * @var string[]
62
     */
63
    protected $paths = [];
64
65
    /**
66
     * The paths excluded from path where to look for mapping files.
67
     *
68
     * @var string[]
69
     */
70
    protected $excludePaths = [];
71
72
    /**
73
     * The file extension of mapping documents.
74
     *
75
     * @var string
76
     */
77
    protected $fileExtension = '.php';
78
79
    /**
80
     * Cache for AnnotationDriver#getAllClassNames().
81
     *
82
     * @var string[]|null
83
     */
84
    protected $classNames;
85
86
    /**
87
     * Initializes a new AnnotationDriver that uses the given AnnotationReader for reading
88
     * docblock annotations.
89
     *
90
     * @param Reader               $reader The AnnotationReader to use, duck-typed.
91
     * @param string|string[]|null $paths  One or multiple paths where mapping classes can be found.
92
     */
93 2302
    public function __construct(Reader $reader, $paths = null)
94
    {
95 2302
        $this->reader = $reader;
0 ignored issues
show
Documentation Bug introduced by
$reader is of type Doctrine\Common\Annotations\Reader, but the property $reader was declared to be of type Doctrine\Common\Annotations\AnnotationReader. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
96
97 2302
        if ($paths) {
98 2216
            $this->addPaths((array) $paths);
99
        }
100 2302
    }
101
102
    /**
103
     * Appends lookup paths to metadata driver.
104
     *
105
     * @param string[] $paths
106
     */
107 2220
    public function addPaths(array $paths)
108
    {
109 2220
        $this->paths = array_unique(array_merge($this->paths, $paths));
110 2220
    }
111
112
    /**
113
     * Retrieves the defined metadata lookup paths.
114
     *
115
     * @return string[]
116
     */
117
    public function getPaths()
118
    {
119
        return $this->paths;
120
    }
121
122
    /**
123
     * Append exclude lookup paths to metadata driver.
124
     *
125
     * @param string[] $paths
126
     */
127
    public function addExcludePaths(array $paths)
128
    {
129
        $this->excludePaths = array_unique(array_merge($this->excludePaths, $paths));
130
    }
131
132
    /**
133
     * Retrieve the defined metadata lookup exclude paths.
134
     *
135
     * @return string[]
136
     */
137
    public function getExcludePaths()
138
    {
139
        return $this->excludePaths;
140
    }
141
142
    /**
143
     * Retrieve the current annotation reader
144
     *
145
     * @return Reader
146
     */
147 1
    public function getReader()
148
    {
149 1
        return $this->reader;
150
    }
151
152
    /**
153
     * Gets the file extension used to look for mapping files under.
154
     *
155
     * @return string
156
     */
157
    public function getFileExtension()
158
    {
159
        return $this->fileExtension;
160
    }
161
162
    /**
163
     * Sets the file extension used to look for mapping files under.
164
     *
165
     * @param string $fileExtension The file extension to set.
166
     */
167
    public function setFileExtension($fileExtension)
168
    {
169
        $this->fileExtension = $fileExtension;
170
    }
171
172
    /**
173
     * Returns whether the class with the specified name is transient. Only non-transient
174
     * classes, that is entities and mapped superclasses, should have their metadata loaded.
175
     *
176
     * A class is non-transient if it is annotated with an annotation
177
     * from the {@see AnnotationDriver::entityAnnotationClasses}.
178
     *
179
     * @param string $className
180
     *
181
     * @throws ReflectionException
182
     */
183 194
    public function isTransient($className) : bool
184
    {
185 194
        $classAnnotations = $this->reader->getClassAnnotations(new ReflectionClass($className));
186
187 194
        foreach ($classAnnotations as $annotation) {
188 189
            if (isset($this->entityAnnotationClasses[get_class($annotation)])) {
189 189
                return false;
190
            }
191
        }
192
193 12
        return true;
194
    }
195
196
    /**
197
     * {@inheritdoc}
198
     *
199
     * @throws ReflectionException
200
     */
201 60
    public function getAllClassNames() : array
202
    {
203 60
        if ($this->classNames !== null) {
204 45
            return $this->classNames;
205
        }
206
207 60
        if (! $this->paths) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->paths of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
208
            throw Mapping\MappingException::pathRequired();
209
        }
210
211 60
        $classes       = [];
212 60
        $includedFiles = [];
213
214 60
        foreach ($this->paths as $path) {
215 60
            if (! is_dir($path)) {
216
                throw Mapping\MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path);
217
            }
218
219 60
            $iterator = new RegexIterator(
220 60
                new RecursiveIteratorIterator(
221 60
                    new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS),
222 60
                    RecursiveIteratorIterator::LEAVES_ONLY
223
                ),
224 60
                '/^.+' . preg_quote($this->fileExtension) . '$/i',
225 60
                RecursiveRegexIterator::GET_MATCH
226
            );
227
228 60
            foreach ($iterator as $file) {
229 60
                $sourceFile = $file[0];
230
231 60
                if (! preg_match('(^phar:)i', $sourceFile)) {
232 60
                    $sourceFile = realpath($sourceFile);
233
                }
234
235 60
                foreach ($this->excludePaths as $excludePath) {
236
                    $exclude = str_replace('\\', '/', realpath($excludePath));
237
                    $current = str_replace('\\', '/', $sourceFile);
238
239
                    if (strpos($current, $exclude) !== false) {
240
                        continue 2;
241
                    }
242
                }
243
244 60
                require_once $sourceFile;
245
246 60
                $includedFiles[] = $sourceFile;
247
            }
248
        }
249
250 60
        $declared = get_declared_classes();
251
252 60
        foreach ($declared as $className) {
253 60
            $reflectionClass = new ReflectionClass($className);
254 60
            $sourceFile      = $reflectionClass->getFileName();
255
256 60
            if (in_array($sourceFile, $includedFiles, true) && ! $this->isTransient($className)) {
257 60
                $classes[] = $className;
258
            }
259
        }
260
261 60
        $this->classNames = $classes;
262
263 60
        return $classes;
264
    }
265
266
    /**
267
     * {@inheritDoc}
268
     *
269
     * @throws CacheException
270
     * @throws Mapping\MappingException
271
     * @throws ReflectionException
272
     * @throws RuntimeException
273
     * @throws UnexpectedValueException
274
     */
275 380
    public function loadMetadataForClass(
276
        string $className,
277
        ?Mapping\ComponentMetadata $parent,
278
        Mapping\ClassMetadataBuildingContext $metadataBuildingContext
279
    ) : Mapping\ComponentMetadata {
280 380
        $reflectionClass  = new ReflectionClass($className);
281 380
        $classAnnotations = $this->getClassAnnotations($reflectionClass);
282 380
        $classBuilder     = new Builder\ClassMetadataBuilder($metadataBuildingContext);
283
        $classMetadata    = $classBuilder
284 380
            ->withClassName($reflectionClass->getName())
285 380
            ->withParentMetadata($parent)
286 380
            ->withEntityAnnotation($classAnnotations[Annotation\Entity::class] ?? null)
287 380
            ->withMappedSuperclassAnnotation($classAnnotations[Annotation\MappedSuperclass::class] ?? null)
288 380
            ->withEmbeddableAnnotation($classAnnotations[Annotation\Embeddable::class] ?? null)
289 380
            ->withTableAnnotation($classAnnotations[Annotation\Table::class] ?? null)
290 380
            ->withInheritanceTypeAnnotation($classAnnotations[Annotation\InheritanceType::class] ?? null)
291 380
            ->withDiscriminatorColumnAnnotation($classAnnotations[Annotation\DiscriminatorColumn::class] ?? null)
292 380
            ->withDiscriminatorMapAnnotation($classAnnotations[Annotation\DiscriminatorMap::class] ?? null)
293 380
            ->withChangeTrackingPolicyAnnotation($classAnnotations[Annotation\ChangeTrackingPolicy::class] ?? null)
294 380
            ->withCacheAnnotation($classAnnotations[Annotation\Cache::class] ?? null)
295 380
            ->build();
296
297 374
        if (! $classMetadata->isEmbeddedClass) {
298 374
            $this->attachLifecycleCallbacks($classAnnotations, $reflectionClass, $classMetadata);
299 374
            $this->attachEntityListeners($classAnnotations, $classMetadata);
300
        }
301
302 374
        $this->attachProperties($classAnnotations, $reflectionClass, $classMetadata, $metadataBuildingContext);
303 371
        $this->attachPropertyOverrides($classAnnotations, $reflectionClass, $classMetadata, $metadataBuildingContext);
304
305 371
        return $classMetadata;
306
    }
307
308
    /**
309
     * @param Annotation\Annotation[] $classAnnotations
310
     */
311 374
    private function attachLifecycleCallbacks(
312
        array $classAnnotations,
313
        ReflectionClass $reflectionClass,
314
        Mapping\ClassMetadata $metadata
315
    ) : void {
316
        // Evaluate @HasLifecycleCallbacks annotation
317 374
        if (isset($classAnnotations[Annotation\HasLifecycleCallbacks::class])) {
318
            $eventMap = [
319 14
                Events::prePersist  => Annotation\PrePersist::class,
320 14
                Events::postPersist => Annotation\PostPersist::class,
321 14
                Events::preUpdate   => Annotation\PreUpdate::class,
322 14
                Events::postUpdate  => Annotation\PostUpdate::class,
323 14
                Events::preRemove   => Annotation\PreRemove::class,
324 14
                Events::postRemove  => Annotation\PostRemove::class,
325 14
                Events::postLoad    => Annotation\PostLoad::class,
326 14
                Events::preFlush    => Annotation\PreFlush::class,
327
            ];
328
329
            /** @var ReflectionMethod $reflectionMethod */
330 14
            foreach ($reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC) as $reflectionMethod) {
331 13
                $annotations = $this->getMethodAnnotations($reflectionMethod);
332
333 13
                foreach ($eventMap as $eventName => $annotationClassName) {
334 13
                    if (isset($annotations[$annotationClassName])) {
335 12
                        $metadata->addLifecycleCallback($eventName, $reflectionMethod->getName());
336
                    }
337
                }
338
            }
339
        }
340 374
    }
341
342
    /**
343
     * @param Annotation\Annotation[] $classAnnotations
344
     *
345
     * @throws ReflectionException
346
     * @throws Mapping\MappingException
347
     */
348 374
    private function attachEntityListeners(
349
        array $classAnnotations,
350
        Mapping\ClassMetadata $metadata
351
    ) : void {
352
        // Evaluate @EntityListeners annotation
353 374
        if (isset($classAnnotations[Annotation\EntityListeners::class])) {
354
            /** @var Annotation\EntityListeners $entityListenersAnnot */
355 8
            $entityListenersAnnot = $classAnnotations[Annotation\EntityListeners::class];
356
            $eventMap             = [
357 8
                Events::prePersist  => Annotation\PrePersist::class,
358 8
                Events::postPersist => Annotation\PostPersist::class,
359 8
                Events::preUpdate   => Annotation\PreUpdate::class,
360 8
                Events::postUpdate  => Annotation\PostUpdate::class,
361 8
                Events::preRemove   => Annotation\PreRemove::class,
362 8
                Events::postRemove  => Annotation\PostRemove::class,
363 8
                Events::postLoad    => Annotation\PostLoad::class,
364 8
                Events::preFlush    => Annotation\PreFlush::class,
365
            ];
366
367 8
            foreach ($entityListenersAnnot->value as $listenerClassName) {
368 8
                if (! class_exists($listenerClassName)) {
369
                    throw Mapping\MappingException::entityListenerClassNotFound(
370
                        $listenerClassName,
371
                        $metadata->getClassName()
372
                    );
373
                }
374
375 8
                $listenerClass = new ReflectionClass($listenerClassName);
376
377
                /** @var ReflectionMethod $reflectionMethod */
378 8
                foreach ($listenerClass->getMethods(ReflectionMethod::IS_PUBLIC) as $reflectionMethod) {
379 8
                    $annotations = $this->getMethodAnnotations($reflectionMethod);
380
381 8
                    foreach ($eventMap as $eventName => $annotationClassName) {
382 8
                        if (isset($annotations[$annotationClassName])) {
383 6
                            $metadata->addEntityListener($eventName, $listenerClassName, $reflectionMethod->getName());
384
                        }
385
                    }
386
                }
387
            }
388
        }
389 374
    }
390
391
    /**
392
     * @param Annotation\Annotation[] $classAnnotations
393
     *
394
     * @throws Mapping\MappingException
395
     */
396 374
    private function attachProperties(
397
        array $classAnnotations,
0 ignored issues
show
Unused Code introduced by
The parameter $classAnnotations is not used and could be removed. ( Ignorable by Annotation )

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

397
        /** @scrutinizer ignore-unused */ array $classAnnotations,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
398
        ReflectionClass $reflectionClass,
399
        Mapping\ClassMetadata $metadata,
400
        Mapping\ClassMetadataBuildingContext $metadataBuildingContext
401
    ) : void {
402
        // Evaluate annotations on properties/fields
403 374
        $propertyBuilder = new Builder\PropertyMetadataBuilder($metadataBuildingContext);
404
405
        /** @var ReflectionProperty $reflProperty */
406 374
        foreach ($reflectionClass->getProperties() as $reflectionProperty) {
407 374
            if ($reflectionProperty->getDeclaringClass()->getName() !== $reflectionClass->getName()) {
408 75
                continue;
409
            }
410
411 374
            $propertyAnnotations = $this->getPropertyAnnotations($reflectionProperty);
412
            $propertyMetadata    = $propertyBuilder
413 373
                ->withComponentMetadata($metadata)
414 373
                ->withFieldName($reflectionProperty->getName())
415 373
                ->withIdAnnotation($propertyAnnotations[Annotation\Id::class] ?? null)
416 373
                ->withCacheAnnotation($propertyAnnotations[Annotation\Cache::class] ?? null)
417 373
                ->withColumnAnnotation($propertyAnnotations[Annotation\Column::class] ?? null)
418 373
                ->withEmbeddedAnnotation($propertyAnnotations[Annotation\Embedded::class] ?? null)
419 373
                ->withOneToOneAnnotation($propertyAnnotations[Annotation\OneToOne::class] ?? null)
420 373
                ->withManyToOneAnnotation($propertyAnnotations[Annotation\ManyToOne::class] ?? null)
421 373
                ->withOneToManyAnnotation($propertyAnnotations[Annotation\OneToMany::class] ?? null)
422 373
                ->withManyToManyAnnotation($propertyAnnotations[Annotation\ManyToMany::class] ?? null)
423 373
                ->withJoinTableAnnotation($propertyAnnotations[Annotation\JoinTable::class] ?? null)
424 373
                ->withJoinColumnsAnnotation($propertyAnnotations[Annotation\JoinColumns::class] ?? null)
425 373
                ->withJoinColumnAnnotation($propertyAnnotations[Annotation\JoinColumn::class] ?? null)
426 373
                ->withOrderByAnnotation($propertyAnnotations[Annotation\OrderBy::class] ?? null)
427 373
                ->withVersionAnnotation($propertyAnnotations[Annotation\Version::class] ?? null)
428 373
                ->withGeneratedValueAnnotation($propertyAnnotations[Annotation\GeneratedValue::class] ?? null)
429 373
                ->withSequenceGeneratorAnnotation($propertyAnnotations[Annotation\SequenceGenerator::class] ?? null)
430 373
                ->withCustomIdGeneratorAnnotation($propertyAnnotations[Annotation\CustomIdGenerator::class] ?? null)
431 373
                ->build();
432
433 371
            $metadata->addProperty($propertyMetadata);
434
        }
435 371
    }
436
437
    /**
438
     * @param Annotation\Annotation[] $classAnnotations
439
     *
440
     * @throws Mapping\MappingException
441
     */
442 371
    private function attachPropertyOverrides(
443
        array $classAnnotations,
444
        ReflectionClass $reflectionClass,
0 ignored issues
show
Unused Code introduced by
The parameter $reflectionClass is not used and could be removed. ( Ignorable by Annotation )

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

444
        /** @scrutinizer ignore-unused */ ReflectionClass $reflectionClass,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
445
        Mapping\ClassMetadata $metadata,
446
        Mapping\ClassMetadataBuildingContext $metadataBuildingContext
447
    ) : void {
448
        // Evaluate AssociationOverrides annotation
449 371
        if (isset($classAnnotations[Annotation\AssociationOverrides::class])) {
450 5
            $associationOverridesAnnot = $classAnnotations[Annotation\AssociationOverrides::class];
451
452 5
            foreach ($associationOverridesAnnot->value as $associationOverrideAnnotation) {
0 ignored issues
show
Bug introduced by
Accessing value on the interface Doctrine\ORM\Annotation\Annotation suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
453 5
                $fieldName = $associationOverrideAnnotation->name;
454 5
                $property  = $metadata->getProperty($fieldName);
455
456 5
                if (! $property) {
457
                    throw Mapping\MappingException::invalidOverrideFieldName($metadata->getClassName(), $fieldName);
458
                }
459
460 5
                $override = clone $property;
461
462
                // Check for JoinColumn/JoinColumns annotations
463 5
                if ($associationOverrideAnnotation->joinColumns) {
464 3
                    $joinColumnBuilder = new Builder\JoinColumnMetadataBuilder($metadataBuildingContext);
465
466
                    $joinColumnBuilder
467 3
                        ->withComponentMetadata($metadata)
468 3
                        ->withFieldName($fieldName);
469
470 3
                    $joinColumns = [];
471
472 3
                    foreach ($associationOverrideAnnotation->joinColumns as $joinColumnAnnotation) {
473 3
                        $joinColumnBuilder->withJoinColumnAnnotation($joinColumnAnnotation);
474
475 3
                        $joinColumnMetadata = $joinColumnBuilder->build();
476 3
                        $columnName         = $joinColumnMetadata->getColumnName();
0 ignored issues
show
Unused Code introduced by
The assignment to $columnName is dead and can be removed.
Loading history...
477
478
                        // @todo guilhermeblanco Open an issue to discuss making this scenario impossible.
479
                        //if ($metadata->checkPropertyDuplication($columnName)) {
480
                        //    throw Mapping\MappingException::duplicateColumnName($metadata->getClassName(), $columnName);
481
                        //}
482
483 3
                        $joinColumns[] = $joinColumnMetadata;
484
                    }
485
486 3
                    $override->setJoinColumns($joinColumns);
0 ignored issues
show
Bug introduced by
The method setJoinColumns() does not exist on Doctrine\ORM\Mapping\Property. It seems like you code against a sub-type of Doctrine\ORM\Mapping\Property such as Doctrine\ORM\Mapping\ToOneAssociationMetadata. ( Ignorable by Annotation )

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

486
                    $override->/** @scrutinizer ignore-call */ 
487
                               setJoinColumns($joinColumns);
Loading history...
487
                }
488
489
                // Check for JoinTable annotations
490 5
                if ($associationOverrideAnnotation->joinTable) {
491 2
                    $joinTableBuilder = new Builder\JoinTableMetadataBuilder($metadataBuildingContext);
492
493
                    $joinTableBuilder
494 2
                        ->withComponentMetadata($metadata)
495 2
                        ->withFieldName($fieldName)
496 2
                        ->withTargetEntity($property->getTargetEntity())
0 ignored issues
show
Bug introduced by
The method getTargetEntity() does not exist on Doctrine\ORM\Mapping\Property. It seems like you code against a sub-type of Doctrine\ORM\Mapping\Property such as Doctrine\ORM\Mapping\EmbeddedMetadata or Doctrine\ORM\Mapping\AssociationMetadata. ( Ignorable by Annotation )

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

496
                        ->withTargetEntity($property->/** @scrutinizer ignore-call */ getTargetEntity())
Loading history...
497 2
                        ->withJoinTableAnnotation($associationOverrideAnnotation->joinTable);
498
499 2
                    $override->setJoinTable($joinTableBuilder->build());
0 ignored issues
show
Bug introduced by
The method setJoinTable() does not exist on Doctrine\ORM\Mapping\Property. It seems like you code against a sub-type of Doctrine\ORM\Mapping\Property such as Doctrine\ORM\Mapping\ManyToManyAssociationMetadata. ( Ignorable by Annotation )

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

499
                    $override->/** @scrutinizer ignore-call */ 
500
                               setJoinTable($joinTableBuilder->build());
Loading history...
500
                }
501
502
                // Check for inversedBy
503 5
                if ($associationOverrideAnnotation->inversedBy) {
504 1
                    $override->setInversedBy($associationOverrideAnnotation->inversedBy);
0 ignored issues
show
Bug introduced by
The method setInversedBy() does not exist on Doctrine\ORM\Mapping\Property. It seems like you code against a sub-type of Doctrine\ORM\Mapping\Property such as Doctrine\ORM\Mapping\AssociationMetadata. ( Ignorable by Annotation )

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

504
                    $override->/** @scrutinizer ignore-call */ 
505
                               setInversedBy($associationOverrideAnnotation->inversedBy);
Loading history...
505
                }
506
507
                // Check for fetch
508 5
                if ($associationOverrideAnnotation->fetch) {
509 1
                    $override->setFetchMode(constant(Mapping\FetchMode::class . '::' . $associationOverrideAnnotation->fetch));
0 ignored issues
show
Bug introduced by
The method setFetchMode() does not exist on Doctrine\ORM\Mapping\Property. It seems like you code against a sub-type of Doctrine\ORM\Mapping\Property such as Doctrine\ORM\Mapping\AssociationMetadata. ( Ignorable by Annotation )

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

509
                    $override->/** @scrutinizer ignore-call */ 
510
                               setFetchMode(constant(Mapping\FetchMode::class . '::' . $associationOverrideAnnotation->fetch));
Loading history...
510
                }
511
512 5
                $metadata->setPropertyOverride($override);
513
            }
514
        }
515
516
        // Evaluate AttributeOverrides annotation
517 371
        if (isset($classAnnotations[Annotation\AttributeOverrides::class])) {
518 3
            $attributeOverridesAnnot = $classAnnotations[Annotation\AttributeOverrides::class];
519 3
            $fieldBuilder            = new Builder\FieldMetadataBuilder($metadataBuildingContext);
520
521
            $fieldBuilder
522 3
                ->withComponentMetadata($metadata)
523 3
                ->withIdAnnotation(null)
524 3
                ->withVersionAnnotation(null);
525
526 3
            foreach ($attributeOverridesAnnot->value as $attributeOverrideAnnotation) {
527 3
                $fieldName = $attributeOverrideAnnotation->name;
528 3
                $property  = $metadata->getProperty($fieldName);
529
530 3
                if (! $property) {
531
                    throw Mapping\MappingException::invalidOverrideFieldName($metadata->getClassName(), $fieldName);
532
                }
533
534
                $fieldBuilder
535 3
                    ->withFieldName($fieldName)
536 3
                    ->withColumnAnnotation($attributeOverrideAnnotation->column);
537
538 3
                $fieldMetadata = $fieldBuilder->build();
539 3
                $columnName    = $fieldMetadata->getColumnName();
540
541
                // Prevent column duplication
542 3
                if ($metadata->checkPropertyDuplication($columnName)) {
0 ignored issues
show
Bug introduced by
It seems like $columnName can also be of type null; however, parameter $columnName of Doctrine\ORM\Mapping\Cla...ckPropertyDuplication() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

542
                if ($metadata->checkPropertyDuplication(/** @scrutinizer ignore-type */ $columnName)) {
Loading history...
543
                    throw Mapping\MappingException::duplicateColumnName($metadata->getClassName(), $columnName);
544
                }
545
546 3
                $metadata->setPropertyOverride($fieldMetadata);
547
            }
548
        }
549 371
    }
550
551
    /**
552
     * @return Annotation\Annotation[]
553
     */
554 380
    private function getClassAnnotations(ReflectionClass $reflectionClass) : array
555
    {
556 380
        $classAnnotations = $this->reader->getClassAnnotations($reflectionClass);
557
558 380
        foreach ($classAnnotations as $key => $annot) {
559 374
            if (! is_numeric($key)) {
560
                continue;
561
            }
562
563 374
            $classAnnotations[get_class($annot)] = $annot;
564
        }
565
566 380
        return $classAnnotations;
567
    }
568
569
    /**
570
     * @return Annotation\Annotation[]
571
     */
572 374
    private function getPropertyAnnotations(ReflectionProperty $reflectionProperty) : array
573
    {
574 374
        $propertyAnnotations = $this->reader->getPropertyAnnotations($reflectionProperty);
575
576 373
        foreach ($propertyAnnotations as $key => $annot) {
577 373
            if (! is_numeric($key)) {
578
                continue;
579
            }
580
581 373
            $propertyAnnotations[get_class($annot)] = $annot;
582
        }
583
584 373
        return $propertyAnnotations;
585
    }
586
587
    /**
588
     * @return Annotation\Annotation[]
589
     */
590 21
    private function getMethodAnnotations(ReflectionMethod $reflectionMethod) : array
591
    {
592 21
        $methodAnnotations = $this->reader->getMethodAnnotations($reflectionMethod);
593
594 21
        foreach ($methodAnnotations as $key => $annot) {
595 18
            if (! is_numeric($key)) {
596
                continue;
597
            }
598
599 18
            $methodAnnotations[get_class($annot)] = $annot;
600
        }
601
602 21
        return $methodAnnotations;
603
    }
604
}
605