Failed Conditions
Push — develop ( ba9041...24f682 )
by Guilherme
64:30
created

ClassMetadataFactory::initializeReflection()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 2
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ORM\Mapping;
6
7
use Doctrine\DBAL\Platforms;
8
use Doctrine\ORM\EntityManagerInterface;
9
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
10
use Doctrine\ORM\Event\OnClassMetadataNotFoundEventArgs;
11
use Doctrine\ORM\Events;
12
use Doctrine\ORM\ORMException;
13
use Doctrine\ORM\Reflection\ReflectionService;
14
use Doctrine\ORM\Sequencing;
15
use Doctrine\ORM\Sequencing\Planning\ColumnValueGeneratorExecutor;
16
use Doctrine\ORM\Sequencing\Planning\CompositeValueGenerationPlan;
17
use Doctrine\ORM\Sequencing\Planning\NoopValueGenerationPlan;
18
use Doctrine\ORM\Sequencing\Planning\SingleValueGenerationPlan;
19
use ReflectionException;
20
21
/**
22
 * The ClassMetadataFactory is used to create ClassMetadata objects that contain all the
23
 * metadata mapping information of a class which describes how a class should be mapped
24
 * to a relational database.
25
 *
26
 * @since   2.0
27
 * @author  Benjamin Eberlei <[email protected]>
28
 * @author  Guilherme Blanco <[email protected]>
29
 * @author  Jonathan Wage <[email protected]>
30
 * @author  Roman Borschel <[email protected]>
31
 */
32
class ClassMetadataFactory extends AbstractClassMetadataFactory
33
{
34
    /**
35
     * @var EntityManagerInterface|null
36
     */
37
    private $em;
38
39
    /**
40
     * @var \Doctrine\DBAL\Platforms\AbstractPlatform
41
     */
42
    private $targetPlatform;
43
44
    /**
45
     * @var Driver\MappingDriver
46
     */
47
    private $driver;
48
49
    /**
50
     * @var \Doctrine\Common\EventManager
51
     */
52
    private $evm;
53
54
    /**
55
     * {@inheritdoc}
56
     */
57
    protected function loadMetadata(string $name, ClassMetadataBuildingContext $metadataBuildingContext) : array
58
    {
59
        $loaded = parent::loadMetadata($name, $metadataBuildingContext);
60
61
        array_map([$this, 'resolveDiscriminatorValue'], $loaded);
62
63
        return $loaded;
64
    }
65
66
    /**
67
     * @param EntityManagerInterface $em
68
     */
69
    public function setEntityManager(EntityManagerInterface $em)
70
    {
71
        $this->em = $em;
72
    }
73
74
    /**
75 397
     * {@inheritdoc}
76
     *
77 397
     * @throws ORMException
78
     */
79 380
    protected function initialize() : void
80
    {
81 380
        $this->driver = $this->em->getConfiguration()->getMetadataDriverImpl();
82
        $this->evm = $this->em->getEventManager();
83
        $this->initialized = true;
84
    }
85
86
    /**
87 2292
     * {@inheritdoc}
88
     */
89 2292
    protected function onNotFoundMetadata(
90 2292
        string $className,
91
        ClassMetadataBuildingContext $metadataBuildingContext
92
    ) : ?ClassMetadata
93
    {
94
        if (! $this->evm->hasListeners(Events::onClassMetadataNotFound)) {
95 465
            return null;
96
        }
97 465
98 465
        $eventArgs = new OnClassMetadataNotFoundEventArgs($className, $metadataBuildingContext, $this->em);
0 ignored issues
show
Bug introduced by
It seems like $this->em can be null; however, __construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
99 465
100 465
        $this->evm->dispatchEvent(Events::onClassMetadataNotFound, $eventArgs);
101
102
        return $eventArgs->getFoundMetadata();
103
    }
104
105 2
    /**
106
     * {@inheritdoc}
107 2
     *
108
     * @throws MappingException
109
     * @throws ORMException
110
     */
111 2
    protected function doLoadMetadata(
112
        string $className,
113 2
        ?ClassMetadata $parent,
114
        ClassMetadataBuildingContext $metadataBuildingContext
115 2
    ) : ClassMetadata
116
    {
117
        $classMetadata = new ClassMetadata($className, $metadataBuildingContext);
118
119
        if ($parent) {
120
            $classMetadata->setParent($parent);
121 395
122
            if ($parent->inheritanceType === InheritanceType::SINGLE_TABLE) {
123
                $classMetadata->setTable($parent->table);
124
            }
125 395
126 108
            $this->addInheritedProperties($classMetadata, $parent);
127 29
128
            $classMetadata->setInheritanceType($parent->inheritanceType);
129
            $classMetadata->setIdentifier($parent->identifier);
130 108
131 108
            if ($parent->discriminatorColumn) {
132 107
                $classMetadata->setDiscriminatorColumn($parent->discriminatorColumn);
133
                $classMetadata->setDiscriminatorMap($parent->discriminatorMap);
134 107
            }
135 107
136 107
            $classMetadata->setLifecycleCallbacks($parent->lifecycleCallbacks);
137
            $classMetadata->setChangeTrackingPolicy($parent->changeTrackingPolicy);
138 107
139 4
            if ($parent->isMappedSuperclass && ! $classMetadata->getCustomRepositoryClassName()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $classMetadata->getCustomRepositoryClassName() of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
140
                $classMetadata->setCustomRepositoryClassName($parent->getCustomRepositoryClassName());
141
            }
142 107
        }
143 65
144 65
        // Invoke driver
145
        try {
146
            $this->driver->loadMetadataForClass($classMetadata->getClassName(), $classMetadata, $metadataBuildingContext);
147 107
        } catch (ReflectionException $e) {
148 107
            throw MappingException::reflectionFailure($classMetadata->getClassName(), $e);
149
        }
150 107
151 1
        $this->completeIdentifierGeneratorMappings($classMetadata);
152
153
        if ($parent) {
154 107
            if ($parent->inheritanceType === InheritanceType::SINGLE_TABLE) {
155 39
                $classMetadata->setTable($parent->table);
156
            }
157
158
            $this->addInheritedIndexes($classMetadata, $parent);
159
            $this->addInheritedNamedQueries($classMetadata, $parent);
160
161 395
            if ($parent->getCache()) {
162 2
                $classMetadata->setCache(clone $parent->getCache());
163
            }
164
165
            if ( ! empty($parent->namedNativeQueries)) {
166
                $this->addInheritedNamedNativeQueries($classMetadata, $parent);
167
            }
168
169 393
            if ( ! empty($parent->sqlResultSetMappings)) {
170 74
                $this->addInheritedSqlResultSetMappings($classMetadata, $parent);
171
            }
172 389
173
            if ( ! empty($parent->entityListeners) && empty($classMetadata->entityListeners)) {
174
                $classMetadata->entityListeners = $parent->entityListeners;
175
            }
176
        }
177
178
        if (! $classMetadata->discriminatorMap && $classMetadata->inheritanceType !== InheritanceType::NONE && $classMetadata->isRootEntity()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $classMetadata->discriminatorMap of type array 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...
179
            $this->addDefaultDiscriminatorMap($classMetadata);
180
        }
181
182
        $this->completeRuntimeMetadata($classMetadata, $parent);
183
184
        if ($this->evm->hasListeners(Events::loadClassMetadata)) {
185
            $eventArgs = new LoadClassMetadataEventArgs($classMetadata, $this->em);
0 ignored issues
show
Bug introduced by
It seems like $this->em can be null; however, __construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
186
187
            $this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs);
188
        }
189
190
        $this->buildValueGenerationPlan($classMetadata);
191
        $this->validateRuntimeMetadata($classMetadata, $parent);
192
193
        return $classMetadata;
194
    }
195
196
    /**
197
     * @param ClassMetadata      $class
198
     * @param ClassMetadata|null $parent
199
     *
200
     * @return void
201
     */
202
    protected function completeRuntimeMetadata(ClassMetadata $class, ClassMetadata $parent = null) : void
203
    {
204
        if (! $parent || ! $parent->isMappedSuperclass) {
205
            return;
206
        }
207
208
        if ($class->isMappedSuperclass) {
209 391
            return;
210 107
        }
211 29
212
        $tableName = $class->getTableName();
213
214 107
        // Resolve column table names
215
        foreach ($class->getDeclaredPropertiesIterator() as $property) {
216 107
            if ($property instanceof FieldMetadata) {
217 3
                $property->setTableName($property->getTableName() ?? $tableName);
218
219
                continue;
220 107
            }
221
222
            if (! ($property instanceof ToOneAssociationMetadata)) {
223
                continue;
224 107
            }
225 1
226
            // Resolve association join column table names
227
            foreach ($property->getJoinColumns() as $joinColumn) {
228 107
                /** @var JoinColumnMetadata $joinColumn */
229 8
                $joinColumn->setTableName($joinColumn->getTableName() ?? $tableName);
230
            }
231
        }
232 107
    }
233 8
234
    /**
235
     * Validate runtime metadata is correctly defined.
236 107
     *
237 11
     * @param ClassMetadata      $class
238
     * @param ClassMetadata|null $parent
239
     *
240
     * @return void
241 391
     *
242
     * @throws MappingException
243 391
     */
244 1
    protected function validateRuntimeMetadata(ClassMetadata $class, ClassMetadata $parent = null) : void
245
    {
246
        if (! $class->getReflectionClass()) {
247 391
            // only validate if there is a reflection class instance
248
            return;
249 391
        }
250 6
251
        $class->validateIdentifier();
252 6
        $class->validateAssociations();
253
        $class->validateLifecycleCallbacks($this->getReflectionService());
254
255 390
        // verify inheritance
256 385
        if ( ! $class->isMappedSuperclass && $class->inheritanceType !== InheritanceType::NONE) {
257
            if ( ! $parent) {
258
                if (count($class->discriminatorMap) === 0) {
259
                    throw MappingException::missingDiscriminatorMap($class->getClassName());
260
                }
261
262
                if ( ! $class->discriminatorColumn) {
263
                    throw MappingException::missingDiscriminatorColumn($class->getClassName());
264 391
                }
265
            }
266 391
        } else if ($class->isMappedSuperclass && $class->isRootEntity() && (count($class->discriminatorMap) || $class->discriminatorColumn)) {
267 387
            // second condition is necessary for mapped superclasses in the middle of an inheritance hierarchy
268
            throw MappingException::noInheritanceOnMappedSuperClass($class->getClassName());
269
        }
270 107
    }
271 74
272
    /**
273
     * {@inheritdoc}
274 39
     */
275 1
    protected function newClassMetadataBuildingContext() : ClassMetadataBuildingContext
276
    {
277
        return new ClassMetadataBuildingContext(
278 39
            $this,
279
            $this->getReflectionService(),
280
            $this->em->getConfiguration()->getNamingStrategy()
281 39
        );
282 39
    }
283
284
    /**
285
     * Populates the discriminator value of the given metadata (if not set) by iterating over discriminator
286 39
     * map classes and looking for a fitting one.
287 13
     *
288 10
     * @param ClassMetadata $metadata
289 13
     *
290
     * @return void
291
     *
292
     * @throws \InvalidArgumentException
293
     * @throws \ReflectionException
294
     * @throws MappingException
295
     */
296
    private function resolveDiscriminatorValue(ClassMetadata $metadata) : void
297
    {
298
        if ($metadata->discriminatorValue || ! $metadata->discriminatorMap || $metadata->isMappedSuperclass ||
0 ignored issues
show
Bug Best Practice introduced by
The expression $metadata->discriminatorMap of type array 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...
299
            ! $metadata->getReflectionClass() || $metadata->getReflectionClass()->isAbstract()) {
300 39
            return;
301
        }
302
303
        // minor optimization: avoid loading related metadata when not needed
304
        foreach ($metadata->discriminatorMap as $discriminatorValue => $discriminatorClass) {
305
            if ($discriminatorClass === $metadata->getClassName()) {
306
                $metadata->discriminatorValue = $discriminatorValue;
307
308
                return;
309
            }
310
        }
311
312 390
        // iterate over discriminator mappings and resolve actual referenced classes according to existing metadata
313
        foreach ($metadata->discriminatorMap as $discriminatorValue => $discriminatorClass) {
314 390
            if ($metadata->getClassName() === $this->getMetadataFor($discriminatorClass)->getClassName()) {
315
                $metadata->discriminatorValue = $discriminatorValue;
316 5
317
                return;
318
            }
319 385
        }
320 381
321 381
        throw MappingException::mappedClassNotPartOfDiscriminatorMap($metadata->getClassName(), $metadata->getRootClassName());
322
    }
323
324 381
    /**
325 67
     * Adds a default discriminator map if no one is given
326 63
     *
327
     * If an entity is of any inheritance type and does not contain a
328
     * discriminator map, then the map is generated automatically. This process
329
     * is expensive computation wise.
330 63
     *
331 67
     * The automatically generated discriminator map contains the lowercase short name of
332
     * each class as key.
333
     *
334 349
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
335
     *
336 1
     * @throws MappingException
337
     */
338 380
    private function addDefaultDiscriminatorMap(ClassMetadata $class) : void
339
    {
340
        $allClasses = $this->driver->getAllClassNames();
341
        $fqcn       = $class->getClassName();
342
        $map        = [$this->getShortName($fqcn) => $fqcn];
343 390
        $duplicates = [];
344
345 390
        foreach ($allClasses as $subClassCandidate) {
346
            if (is_subclass_of($subClassCandidate, $fqcn)) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if $fqcn can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
347
                $shortName = $this->getShortName($subClassCandidate);
348
349
                if (isset($map[$shortName])) {
350
                    $duplicates[] = $shortName;
351
                }
352
353
                $map[$shortName] = $class->fullyQualifiedClassName($subClassCandidate);
354
            }
355
        }
356
357
        if ($duplicates) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $duplicates of type array 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...
358 380
            throw MappingException::duplicateDiscriminatorEntry($class->getClassName(), $duplicates, $map);
359
        }
360 380
361 380
        $class->setDiscriminatorMap($map);
362 380
    }
363
364
    /**
365
     * Gets the lower-case short name of a class.
366 5
     *
367 5
     * @param string $className
368 3
     *
369
     * @return string
370 5
     */
371
    private function getShortName($className) : string
372
    {
373
        if (strpos($className, "\\") === false) {
374
            return strtolower($className);
375 2
        }
376 2
377 1
        $parts = explode("\\", $className);
378
379 2
        return strtolower(end($parts));
380
    }
381
382
    /**
383 1
     * Adds inherited fields to the subclass mapping.
384
     *
385
     * @param ClassMetadata $subClass
386
     * @param ClassMetadata $parentClass
387
     *
388
     * @return void
389
     *
390
     * @throws MappingException
391
     */
392
    private function addInheritedProperties(ClassMetadata $subClass, ClassMetadata $parentClass) : void
393
    {
394
        $isAbstract = $parentClass->isMappedSuperclass;
395
396
        foreach ($parentClass->getDeclaredPropertiesIterator() as $fieldName => $property) {
397
            if ($isAbstract && $property instanceof ToManyAssociationMetadata && ! $property->isOwningSide()) {
398
                throw MappingException::illegalToManyAssociationOnMappedSuperclass($parentClass->getClassName(), $fieldName);
399
            }
400 1
401
            $subClass->addInheritedProperty($property);
402 1
        }
403 1
    }
404 1
405 1
    /**
406
     * Copy the table indices from the parent class superclass to the child class
407 1
     *
408 1
     * @param ClassMetadata $subClass
409 1
     * @param ClassMetadata $parentClass
410
     *
411 1
     * @return void
412
     */
413
    private function addInheritedIndexes(ClassMetadata $subClass, ClassMetadata $parentClass) : void
414
    {
415 1
        if ( ! $parentClass->isMappedSuperclass) {
416
            return;
417
        }
418
419 1
        foreach ($parentClass->table->getIndexes() as $indexName => $index) {
420
            if ($subClass->table->hasIndex($indexName)) {
421
                continue;
422
            }
423 1
424 1
            $subClass->table->addIndex($index);
425
        }
426
427
        foreach ($parentClass->table->getUniqueConstraints() as $constraintName => $constraint) {
428
            if ($subClass->table->hasUniqueConstraint($constraintName)) {
429
                continue;
430
            }
431
432
            $subClass->table->addUniqueConstraint($constraint);
433 1
        }
434
    }
435 1
436
    /**
437
     * Adds inherited named queries to the subclass mapping.
438
     *
439 1
     * @since 2.2
440
     *
441 1
     * @param ClassMetadata $subClass
442
     * @param ClassMetadata $parentClass
443
     *
444
     * @return void
445
     *
446
     * @throws MappingException
447
     */
448
    private function addInheritedNamedQueries(ClassMetadata $subClass, ClassMetadata $parentClass) : void
449
    {
450
        foreach ($parentClass->getNamedQueries() as $name => $query) {
451
            if ($subClass->hasNamedQuery($name)) {
452 108
                continue;
453
            }
454 108
455 92
            $subClass->addNamedQuery($name, $query);
456
        }
457
    }
458 108
459 93
    /**
460
     * Adds inherited named native queries to the subclass mapping.
461 108
     *
462
     * @since 2.3
463
     *
464
     * @param ClassMetadata $subClass
465
     * @param ClassMetadata $parentClass
466
     *
467
     * @return void
468
     *
469
     * @throws MappingException
470
     */
471
    private function addInheritedNamedNativeQueries(ClassMetadata $subClass, ClassMetadata $parentClass) : void
472
    {
473 108
        foreach ($parentClass->namedNativeQueries as $name => $query) {
474
            if (isset($subClass->namedNativeQueries[$name])) {
475 108
                continue;
476
            }
477 108
478 40
            $subClass->addNamedNativeQuery(
479 6
                $name,
480 1
                $query['query'],
481
                [
482
                    'resultSetMapping' => $query['resultSetMapping'],
483 5
                    'resultClass'      => $query['resultClass'],
484
                ]
485
            );
486
        }
487 39
    }
488 34
489 34
    /**
490 34
     * Adds inherited sql result set mappings to the subclass mapping.
491
     *
492
     * @since 2.3
493
     *
494
     * @param ClassMetadata $subClass
495 39
     * @param ClassMetadata $parentClass
496 34
     *
497
     * @return void
498
     *
499 39
     * @throws MappingException
500
     */
501 107
    private function addInheritedSqlResultSetMappings(ClassMetadata $subClass, ClassMetadata $parentClass) : void
502
    {
503
        foreach ($parentClass->sqlResultSetMappings as $name => $mapping) {
504
            if (isset ($subClass->sqlResultSetMappings[$name])) {
505
                continue;
506
            }
507
508
            $entities = [];
509
510
            foreach ($mapping['entities'] as $entity) {
511 107
                $entities[] = [
512
                    'fields'              => $entity['fields'],
513
                    'discriminatorColumn' => $entity['discriminatorColumn'],
514
                    'entityClass'         => $entity['entityClass'],
515
                ];
516
            }
517
518
            $subClass->addSqlResultSetMapping(
519
                [
520
                    'name'     => $mapping['name'],
521
                    'columns'  => $mapping['columns'],
522
                    'entities' => $entities,
523
                ]
524 107
            );
525
        }
526
    }
527
528
    /**
529
     * Completes the ID generator mapping. If "auto" is specified we choose the generator
530
     * most appropriate for the targeted database platform.
531
     *
532
     * @param ClassMetadata $class
533
     *
534
     * @return void
535
     *
536
     * @throws ORMException
537
     */
538
    private function completeIdentifierGeneratorMappings(ClassMetadata $class) : void
539
    {
540
        foreach ($class->getDeclaredPropertiesIterator() as $property) {
541
            if ( ! $property instanceof FieldMetadata /*&& ! $property instanceof AssocationMetadata*/) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
45% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
542
                continue;
543
            }
544
545
            $this->completeFieldIdentifierGeneratorMapping($property);
546
        }
547
    }
548
549
    private function completeFieldIdentifierGeneratorMapping(FieldMetadata $field)
550
    {
551
        if (!$field->hasValueGenerator()) {
552
            return;
553
        }
554
555
        $platform  = $this->getTargetPlatform();
556
        $class     = $field->getDeclaringClass();
0 ignored issues
show
Unused Code introduced by
$class is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
557
        $generator = $field->getValueGenerator();
558
559
        if ($generator->getType() === GeneratorType::AUTO) {
560
            $generator = new ValueGeneratorMetadata(
561
                $platform->prefersSequences()
562 107
                    ? GeneratorType::SEQUENCE
563
                    : ($platform->prefersIdentityColumns()
564 107
                        ? GeneratorType::IDENTITY
565 74
                        : GeneratorType::TABLE
566
                ),
567
                $field->getValueGenerator()->getDefinition()
568 39
            );
569 39
            $field->setValueGenerator($generator);
570 38
        }
571
572
        // Validate generator definition and set defaults where needed
573 1
        switch ($generator->getType()) {
574 1
            case GeneratorType::SEQUENCE:
575
                // If there is no sequence definition yet, create a default definition
576
                if ($generator->getDefinition()) {
577
                    break;
578 1
                }
579
580
                // @todo guilhermeblanco Move sequence generation to DBAL
581 39
                $sequencePrefix = $platform->getSequencePrefix($field->getTableName(), $field->getSchemaName());
0 ignored issues
show
Bug introduced by
The method getSchemaName() does not seem to exist on object<Doctrine\ORM\Mapping\FieldMetadata>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
582
                $idSequenceName = sprintf('%s_%s_seq', $sequencePrefix, $field->getColumnName());
583
                $sequenceName   = $platform->fixSchemaElementName($idSequenceName);
584
585
                $field->setValueGenerator(
586
                    new ValueGeneratorMetadata(
587
                        $generator->getType(),
588
                        [
589
                            'sequenceName'   => $sequenceName,
590
                            'allocationSize' => 1,
591
                        ]
592
                    )
593 1
                );
594
595 1
                break;
596 1
597 1
            case GeneratorType::TABLE:
598
                throw new ORMException("TableGenerator not yet implemented.");
599
                break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
600 1
601 1
            case GeneratorType::CUSTOM:
602 1
                $definition = $generator->getDefinition();
603
                if ( ! isset($definition['class'])) {
604
                    throw new ORMException(sprintf('Cannot instantiate custom generator, no class has been defined'));
605 1
                }
606
                if ( ! class_exists($definition['class'])) {
607
                    throw new ORMException(sprintf('Cannot instantiate custom generator : %s', var_export($definition, true))); //$definition['class']));
0 ignored issues
show
Unused Code Comprehensibility introduced by
100% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
608
                }
609
610
                break;
611
612
            case GeneratorType::IDENTITY:
613
            case GeneratorType::NONE:
614
            case GeneratorType::UUID:
615
                break;
616
617 8
            default:
618
                throw new ORMException("Unknown generator type: " . $generator->getType());
619 8
        }
620 8
    }
621 4
622
    /**
623
     * {@inheritDoc}
624 8
     */
625 8
    protected function wakeupReflection(ClassMetadata $class, ReflectionService $reflService) : void
626 8
    {
627 8
        $class->wakeupReflection($reflService);
628 8
    }
629 8
630
    /**
631
     * {@inheritDoc}
632 8
     */
633
    protected function getFqcnFromAlias($namespaceAlias, $simpleClassName) : string
634
    {
635
        return $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;
636
    }
637
638
    /**
639
     * {@inheritDoc}
640
     */
641
    protected function getDriver() : Driver\MappingDriver
642
    {
643
        return $this->driver;
644 8
    }
645
646 8
    /**
647 8
     * {@inheritDoc}
648 4
     */
649
    protected function isEntity(ClassMetadata $class) : bool
650
    {
651 8
        return isset($class->isMappedSuperclass) && $class->isMappedSuperclass === false;
652
    }
653 8
654 8
    /**
655 8
     * @return Platforms\AbstractPlatform
656 8
     */
657 8
    private function getTargetPlatform() : Platforms\AbstractPlatform
658 8
    {
659
        if (!$this->targetPlatform) {
660
            $this->targetPlatform = $this->em->getConnection()->getDatabasePlatform();
661
        }
662 8
663 8
        return $this->targetPlatform;
664 8
    }
665 8
666
    /**
667
     * @param ClassMetadata $class
668 8
     *
669
     * @return void
670
     */
671
    private function buildValueGenerationPlan(ClassMetadata $class) : void
672
    {
673
        /** @var LocalColumnMetadata[] $generatedProperties */
674
        $generatedProperties = [];
675
676
        foreach ($class->getDeclaredPropertiesIterator() as $property) {
677
            if (! ($property instanceof LocalColumnMetadata && $property->hasValueGenerator())) {
678
                continue;
679
            }
680 389
681
            $generatedProperties[] = $property;
682 389
        }
683 389
684
        switch (count($generatedProperties)) {
685 389
            case 0:
686 282
                $class->setValueGenerationPlan(new NoopValueGenerationPlan());
687
                break;
688 282
689 282
            case 1:
690 282
                $property  = reset($generatedProperties);
691
                $executor  = new ColumnValueGeneratorExecutor($property, $this->createPropertyValueGenerator($class, $property));
0 ignored issues
show
Security Bug introduced by
It seems like $property defined by reset($generatedProperties) on line 690 can also be of type false; however, Doctrine\ORM\Mapping\Cla...ropertyValueGenerator() does only seem to accept object<Doctrine\ORM\Mapping\LocalColumnMetadata>, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
Security Bug introduced by
It seems like $property defined by reset($generatedProperties) on line 690 can also be of type false; however, Doctrine\ORM\Sequencing\...Executor::__construct() does only seem to accept object<Doctrine\ORM\Mapping\LocalColumnMetadata>, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
692
693 282
                $class->setValueGenerationPlan(new SingleValueGenerationPlan($class, $executor));
694
                break;
695
696
            default:
697 389
                $executors = [];
698 389
699 290
                foreach ($generatedProperties as $property) {
700 290
                    $executors[] = new ColumnValueGeneratorExecutor($property, $this->createPropertyValueGenerator($class, $property));
701
                }
702
703 290
                $class->setValueGenerationPlan(new CompositeValueGenerationPlan($class, $executors));
704
                break;
705
        }
706
    }
707
708
    /**
709
     * @param ClassMetadata $class
710 290
     * @param LocalColumnMetadata $property
711 1
     *
712 290
     * @return Sequencing\Generator
713
     */
714
    private function createPropertyValueGenerator(
715 290
        ClassMetadata $class,
716
        LocalColumnMetadata $property
717 290
    ) : Sequencing\Generator
718
    {
719 143
        $platform = $this->getTargetPlatform();
720
721 6
        switch ($property->getValueGenerator()->getType()) {
722
            case GeneratorType::IDENTITY:
723 6
                $sequenceName = null;
724
725
                // Platforms that do not have native IDENTITY support need a sequence to emulate this behaviour.
726
                if ($platform->usesSequenceEmulatedIdentityColumns()) {
727
                    $sequencePrefix = $platform->getSequencePrefix($class->getTableName(), $class->getSchemaName());
728
                    $idSequenceName = $platform->getIdentitySequenceName($sequencePrefix, $property->getColumnName());
729
                    $sequenceName   = $platform->quoteIdentifier($platform->fixSchemaElementName($idSequenceName));
730
                }
731
732
                return $property->getTypeName() === 'bigint'
733
                    ? new Sequencing\BigIntegerIdentityGenerator($sequenceName)
734
                    : new Sequencing\IdentityGenerator($sequenceName);
735 6
736 6
            case GeneratorType::SEQUENCE:
737
                $definition = $property->getValueGenerator()->getDefinition();
738 6
                return new Sequencing\SequenceGenerator(
739 6
                    $platform->quoteIdentifier($definition['sequenceName']),
740
                    $definition['allocationSize']
741 140
                );
742 134
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
743 134
744
            case GeneratorType::UUID:
745 6
                return new Sequencing\UuidGenerator();
746 2
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
747 2
748
            case GeneratorType::CUSTOM:
749 4
                $class = $property->getValueGenerator()->getDefinition()['class'];
750
                return new $class();
751
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
752
        }
753 4
    }
754
}
755