Completed
Pull Request — master (#6151)
by Andy
09:42
created

ClassMetadataFactory::addInheritedRelations()   B

Complexity

Conditions 8
Paths 10

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 8

Importance

Changes 0
Metric Value
dl 0
loc 20
c 0
b 0
f 0
ccs 12
cts 12
cp 1
rs 7.7777
cc 8
eloc 11
nc 10
nop 2
crap 8
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ORM\Mapping;
21
22
use Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory;
23
use Doctrine\Common\Persistence\Mapping\ClassMetadata as ClassMetadataInterface;
24
use Doctrine\Common\Persistence\Mapping\ReflectionService;
25
use Doctrine\DBAL\Platforms;
26
use Doctrine\ORM\EntityManagerInterface;
27
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
28
use Doctrine\ORM\Event\OnClassMetadataNotFoundEventArgs;
29
use Doctrine\ORM\Events;
30
use Doctrine\ORM\Id\BigIntegerIdentityGenerator;
31
use Doctrine\ORM\Id\IdentityGenerator;
32
use Doctrine\ORM\ORMException;
33
use ReflectionException;
34
35
/**
36
 * The ClassMetadataFactory is used to create ClassMetadata objects that contain all the
37
 * metadata mapping information of a class which describes how a class should be mapped
38
 * to a relational database.
39
 *
40
 * @since   2.0
41
 * @author  Benjamin Eberlei <[email protected]>
42
 * @author  Guilherme Blanco <[email protected]>
43
 * @author  Jonathan Wage <[email protected]>
44
 * @author  Roman Borschel <[email protected]>
45
 */
46
class ClassMetadataFactory extends AbstractClassMetadataFactory
47
{
48
    /**
49
     * @var EntityManagerInterface|null
50
     */
51
    private $em;
52
53
    /**
54
     * @var \Doctrine\DBAL\Platforms\AbstractPlatform
55
     */
56
    private $targetPlatform;
57
58
    /**
59
     * @var \Doctrine\Common\Persistence\Mapping\Driver\MappingDriver
60
     */
61
    private $driver;
62
63
    /**
64
     * @var \Doctrine\Common\EventManager
65
     */
66
    private $evm;
67
68
    /**
69
     * @var array
70
     */
71
    private $embeddablesActiveNesting = array();
72
73
    /**
74
     * {@inheritDoc}
75
     */
76 438
    protected function loadMetadata($name)
77
    {
78 438
        $loaded = parent::loadMetadata($name);
79
80 420
        array_map([$this, 'resolveDiscriminatorValue'], array_map([$this, 'getMetadataFor'], $loaded));
81
82 420
        return $loaded;
83
    }
84
85
    /**
86
     * @param EntityManagerInterface $em
87
     */
88 2356
    public function setEntityManager(EntityManagerInterface $em)
89
    {
90 2356
        $this->em = $em;
91 2356
    }
92
93
    /**
94
     * {@inheritDoc}
95
     */
96 507
    protected function initialize()
97
    {
98 507
        $this->driver = $this->em->getConfiguration()->getMetadataDriverImpl();
99 507
        $this->evm = $this->em->getEventManager();
100 507
        $this->initialized = true;
101 507
    }
102
103
    /**
104
     * {@inheritDoc}
105
     */
106 2
    protected function onNotFoundMetadata($className)
107
    {
108 2
        if (! $this->evm->hasListeners(Events::onClassMetadataNotFound)) {
109
            return;
110
        }
111
112 2
        $eventArgs = new OnClassMetadataNotFoundEventArgs($className, $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...
113
114 2
        $this->evm->dispatchEvent(Events::onClassMetadataNotFound, $eventArgs);
115
116 2
        return $eventArgs->getFoundMetadata();
117
    }
118
119
    /**
120
     * {@inheritDoc}
121
     */
122 436
    protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonSuperclassParents)
123
    {
124
        /* @var $class ClassMetadata */
125
        /* @var $parent ClassMetadata */
126 436
        if ($parent) {
127 128
            $class->setInheritanceType($parent->inheritanceType);
128 128
            $class->setDiscriminatorColumn($parent->discriminatorColumn);
129 128
            $class->setIdGeneratorType($parent->generatorType);
130 128
            $this->addInheritedFields($class, $parent);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
131 128
            $this->addInheritedRelations($class, $parent);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
132 127
            $this->addInheritedEmbeddedClasses($class, $parent);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
133 127
            $class->setIdentifier($parent->identifier);
134 127
            $class->setVersioned($parent->isVersioned);
135 127
            $class->setVersionField($parent->versionField);
136 127
            $class->setDiscriminatorMap($parent->discriminatorMap);
137 127
            $class->setLifecycleCallbacks($parent->lifecycleCallbacks);
138 127
            $class->setChangeTrackingPolicy($parent->changeTrackingPolicy);
139
140 127
            if ( ! empty($parent->customGeneratorDefinition)) {
141 1
                $class->setCustomGeneratorDefinition($parent->customGeneratorDefinition);
142
            }
143
144 127
            if ($parent->isMappedSuperclass) {
145 51
                $class->setCustomRepositoryClass($parent->customRepositoryClassName);
146
            }
147
        }
148
149
        // Invoke driver
150
        try {
151 436
            $this->driver->loadMetadataForClass($class->getName(), $class);
152 2
        } catch (ReflectionException $e) {
153
            throw MappingException::reflectionFailure($class->getName(), $e);
154
        }
155
156
        // If this class has a parent the id generator strategy is inherited.
157
        // However this is only true if the hierarchy of parents contains the root entity,
158
        // if it consists of mapped superclasses these don't necessarily include the id field.
159 434
        if ($parent && $rootEntityFound) {
160 82
            $this->inheritIdGeneratorMapping($class, $parent);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadataInfo>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
161
        } else {
162 430
            $this->completeIdGeneratorMapping($class);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadataInfo>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
163
        }
164
165 432
        if (!$class->isMappedSuperclass) {
0 ignored issues
show
Bug introduced by
Accessing isMappedSuperclass on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
166 430
            foreach ($class->embeddedClasses as $property => $embeddableClass) {
0 ignored issues
show
Bug introduced by
Accessing embeddedClasses on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
167
168 13
                if (isset($embeddableClass['inherited'])) {
169 1
                    continue;
170
                }
171
172 13
                if ( ! (isset($embeddableClass['class']) && $embeddableClass['class'])) {
173 1
                    throw MappingException::missingEmbeddedClass($property);
174
                }
175
176 12
                if (isset($this->embeddablesActiveNesting[$embeddableClass['class']])) {
177 2
                    throw MappingException::infiniteEmbeddableNesting($class->name, $property);
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
178
                }
179
180 12
                $this->embeddablesActiveNesting[$class->name] = true;
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
181
182 12
                $embeddableMetadata = $this->getMetadataFor($embeddableClass['class']);
183
184 11
                if ($embeddableMetadata->isEmbeddedClass) {
0 ignored issues
show
Bug introduced by
Accessing isEmbeddedClass on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
185 11
                    $this->addNestedEmbeddedClasses($embeddableMetadata, $class, $property);
0 ignored issues
show
Compatibility introduced by
$embeddableMetadata of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
186
                }
187
188 11
                if ($embeddableClass['attributeOverrides']) {
189
                    foreach ($embeddableClass['attributeOverrides'] as $name => $attributeOverride) {
190
                        if ($attributeOverride) {
191
                            $embeddableMetadata->setAttributeOverride($name, $attributeOverride);
192
                        } else {
193
                            $embeddableMetadata->removeFieldMapping($name);
194
                        }
195
                    }
196
                }
197
198 11
                $identifier = $embeddableMetadata->getIdentifier();
199
200 11
                if (! empty($identifier)) {
201 5
                    $this->inheritIdGeneratorMapping($class, $embeddableMetadata);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadataInfo>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
Compatibility introduced by
$embeddableMetadata of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadataInfo>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
202
                }
203
204 11
                $class->inlineEmbeddable($property, $embeddableMetadata);
205
206 11
                unset($this->embeddablesActiveNesting[$class->name]);
207
            }
208
        }
209
210 429
        if ($parent) {
211 127
            if ($parent->isInheritanceTypeSingleTable()) {
212 33
                $class->setPrimaryTable($parent->table);
213
            }
214
215 127
            if ($parent) {
216 127
                $this->addInheritedIndexes($class, $parent);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
217
            }
218
219 127
            if ($parent->cache) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $parent->cache 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...
220 3
                $class->cache = $parent->cache;
0 ignored issues
show
Bug introduced by
Accessing cache on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
221
            }
222
223 127
            if ($parent->containsForeignIdentifier) {
224
                $class->containsForeignIdentifier = true;
0 ignored issues
show
Bug introduced by
Accessing containsForeignIdentifier on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
225
            }
226
227 127
            if ( ! empty($parent->namedQueries)) {
228 1
                $this->addInheritedNamedQueries($class, $parent);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
229
            }
230
231 127
            if ( ! empty($parent->namedNativeQueries)) {
232 9
                $this->addInheritedNamedNativeQueries($class, $parent);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
233
            }
234
235 127
            if ( ! empty($parent->sqlResultSetMappings)) {
236 9
                $this->addInheritedSqlResultSetMappings($class, $parent);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
237
            }
238
239 127
            if ( ! empty($parent->entityListeners) && empty($class->entityListeners)) {
0 ignored issues
show
Bug introduced by
Accessing entityListeners on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
240 15
                $class->entityListeners = $parent->entityListeners;
0 ignored issues
show
Bug introduced by
Accessing entityListeners on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
241
            }
242
        }
243
244 429
        $class->setParentClasses($nonSuperclassParents);
245
246 429
        if ($class->isRootEntity() && ! $class->isInheritanceTypeNone() && ! $class->discriminatorMap) {
0 ignored issues
show
Bug introduced by
Accessing discriminatorMap on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
247 1
            $this->addDefaultDiscriminatorMap($class);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
248
        }
249
250 429
        if ($this->evm->hasListeners(Events::loadClassMetadata)) {
251 6
            $eventArgs = new LoadClassMetadataEventArgs($class, $this->em);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
Documentation introduced by
$this->em is of type object<Doctrine\ORM\EntityManagerInterface>|null, but the function expects a object<Doctrine\ORM\EntityManager>.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
252 6
            $this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs);
253
        }
254
255 428
        $this->validateRuntimeMetadata($class, $parent);
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
256 427
    }
257
258
    /**
259
     * Validate runtime metadata is correctly defined.
260
     *
261
     * @param ClassMetadata               $class
262
     * @param ClassMetadataInterface|null $parent
263
     *
264
     * @return void
265
     *
266
     * @throws MappingException
267
     */
268 428
    protected function validateRuntimeMetadata($class, $parent)
269
    {
270 428
        if ( ! $class->reflClass ) {
271
            // only validate if there is a reflection class instance
272 8
            return;
273
        }
274
275 420
        $class->validateIdentifier();
276 420
        $class->validateAssociations();
277 420
        $class->validateLifecycleCallbacks($this->getReflectionService());
278
279
        // verify inheritance
280 420
        if ( ! $class->isMappedSuperclass && !$class->isInheritanceTypeNone()) {
281 75
            if ( ! $parent) {
282 71
                if (count($class->discriminatorMap) == 0) {
283
                    throw MappingException::missingDiscriminatorMap($class->name);
284
                }
285 71
                if ( ! $class->discriminatorColumn) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $class->discriminatorColumn 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...
286 75
                    throw MappingException::missingDiscriminatorColumn($class->name);
287
                }
288
            }
289 381
        } else if ($class->isMappedSuperclass && $class->name == $class->rootEntityName && (count($class->discriminatorMap) || $class->discriminatorColumn)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $class->discriminatorColumn 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...
290
            // second condition is necessary for mapped superclasses in the middle of an inheritance hierarchy
291 1
            throw MappingException::noInheritanceOnMappedSuperClass($class->name);
292
        }
293 419
    }
294
295
    /**
296
     * {@inheritDoc}
297
     */
298 431
    protected function newClassMetadataInstance($className)
299
    {
300 431
        return new ClassMetadata($className, $this->em->getConfiguration()->getNamingStrategy());
301
    }
302
303
    /**
304
     * Populates the discriminator value of the given metadata (if not set) by iterating over discriminator
305
     * map classes and looking for a fitting one.
306
     *
307
     * @param ClassMetadata $metadata
308
     *
309
     * @return void
310
     *
311
     * @throws MappingException
312
     */
313 420
    private function resolveDiscriminatorValue(ClassMetadata $metadata)
314
    {
315 420
        if ($metadata->discriminatorValue
316 403
            || ! $metadata->discriminatorMap
317 44
            || $metadata->isMappedSuperclass
318 43
            || ! $metadata->reflClass
319 420
            || $metadata->reflClass->isAbstract()
320
        ) {
321 420
            return;
322
        }
323
324
        // minor optimization: avoid loading related metadata when not needed
325 5
        foreach ($metadata->discriminatorMap as $discriminatorValue => $discriminatorClass) {
326 5
            if ($discriminatorClass === $metadata->name) {
327 3
                $metadata->discriminatorValue = $discriminatorValue;
328
329 5
                return;
330
            }
331
        }
332
333
        // iterate over discriminator mappings and resolve actual referenced classes according to existing metadata
334 2
        foreach ($metadata->discriminatorMap as $discriminatorValue => $discriminatorClass) {
335 2
            if ($metadata->name === $this->getMetadataFor($discriminatorClass)->getName()) {
336 1
                $metadata->discriminatorValue = $discriminatorValue;
337
338 2
                return;
339
            }
340
        }
341
342 1
        throw MappingException::mappedClassNotPartOfDiscriminatorMap($metadata->name, $metadata->rootEntityName);
343
    }
344
345
    /**
346
     * Adds a default discriminator map if no one is given
347
     *
348
     * If an entity is of any inheritance type and does not contain a
349
     * discriminator map, then the map is generated automatically. This process
350
     * is expensive computation wise.
351
     *
352
     * The automatically generated discriminator map contains the lowercase short name of
353
     * each class as key.
354
     *
355
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
356
     *
357
     * @throws MappingException
358
     */
359 1
    private function addDefaultDiscriminatorMap(ClassMetadata $class)
360
    {
361 1
        $allClasses = $this->driver->getAllClassNames();
362 1
        $fqcn = $class->getName();
363 1
        $map = array($this->getShortName($class->name) => $fqcn);
364
365 1
        $duplicates = array();
366 1
        foreach ($allClasses as $subClassCandidate) {
367 1
            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...
368 1
                $shortName = $this->getShortName($subClassCandidate);
369
370 1
                if (isset($map[$shortName])) {
371
                    $duplicates[] = $shortName;
372
                }
373
374 1
                $map[$shortName] = $subClassCandidate;
375
            }
376
        }
377
378 1
        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...
379
            throw MappingException::duplicateDiscriminatorEntry($class->name, $duplicates, $map);
380
        }
381
382 1
        $class->setDiscriminatorMap($map);
383 1
    }
384
385
    /**
386
     * Gets the lower-case short name of a class.
387
     *
388
     * @param string $className
389
     *
390
     * @return string
391
     */
392 1
    private function getShortName($className)
393
    {
394 1
        if (strpos($className, "\\") === false) {
395
            return strtolower($className);
396
        }
397
398 1
        $parts = explode("\\", $className);
399
400 1
        return strtolower(end($parts));
401
    }
402
403
    /**
404
     * Adds inherited fields to the subclass mapping.
405
     *
406
     * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass
407
     * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass
408
     *
409
     * @return void
410
     */
411 128
    private function addInheritedFields(ClassMetadata $subClass, ClassMetadata $parentClass)
412
    {
413 128
        foreach ($parentClass->fieldMappings as $mapping) {
414 112
            if ( ! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
415 82
                $mapping['inherited'] = $parentClass->name;
416
            }
417 112
            if ( ! isset($mapping['declared'])) {
418 112
                $mapping['declared'] = $parentClass->name;
419
            }
420 112
            $subClass->addInheritedFieldMapping($mapping);
421
        }
422 128
        foreach ($parentClass->reflFields as $name => $field) {
423 113
            $subClass->reflFields[$name] = $field;
424
        }
425 128
    }
426
427
    /**
428
     * Adds inherited association mappings to the subclass mapping.
429
     *
430
     * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass
431
     * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass
432
     *
433
     * @return void
434
     *
435
     * @throws MappingException
436
     */
437 128
    private function addInheritedRelations(ClassMetadata $subClass, ClassMetadata $parentClass)
438
    {
439 128
        foreach ($parentClass->associationMappings as $field => $mapping) {
440 49
            if ($parentClass->isMappedSuperclass) {
441 14
                if ($mapping['type'] & ClassMetadata::TO_MANY && !$mapping['isOwningSide']) {
442 1
                    throw MappingException::illegalToManyAssociationOnMappedSuperclass($parentClass->name, $field);
443
                }
444 13
                $mapping['sourceEntity'] = $subClass->name;
445
            }
446
447
            //$subclassMapping = $mapping;
448 48
            if ( ! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
449 35
                $mapping['inherited'] = $parentClass->name;
450
            }
451 48
            if ( ! isset($mapping['declared'])) {
452 48
                $mapping['declared'] = $parentClass->name;
453
            }
454 48
            $subClass->addInheritedAssociationMapping($mapping);
455
        }
456 127
    }
457
458 127
    private function addInheritedEmbeddedClasses(ClassMetadata $subClass, ClassMetadata $parentClass)
459
    {
460 127
        foreach ($parentClass->embeddedClasses as $field => $embeddedClass) {
461 2
            if ( ! isset($embeddedClass['inherited']) && ! $parentClass->isMappedSuperclass) {
462 1
                $embeddedClass['inherited'] = $parentClass->name;
463
            }
464 2
            if ( ! isset($embeddedClass['declared'])) {
465 2
                $embeddedClass['declared'] = $parentClass->name;
466
            }
467
468 2
            $subClass->embeddedClasses[$field] = $embeddedClass;
469
        }
470 127
    }
471
472
    /**
473
     * Adds nested embedded classes metadata to a parent class.
474
     *
475
     * @param ClassMetadata $subClass    Sub embedded class metadata to add nested embedded classes metadata from.
476
     * @param ClassMetadata $parentClass Parent class to add nested embedded classes metadata to.
477
     * @param string        $prefix      Embedded classes' prefix to use for nested embedded classes field names.
478
     */
479 11
    private function addNestedEmbeddedClasses(ClassMetadata $subClass, ClassMetadata $parentClass, $prefix)
480
    {
481 11
        foreach ($subClass->embeddedClasses as $property => $embeddableClass) {
482 4
            if (isset($embeddableClass['inherited'])) {
483
                continue;
484
            }
485
486 4
            $embeddableMetadata = $this->getMetadataFor($embeddableClass['class']);
487
488 4
            $parentClass->mapEmbedded(array(
489 4
                'fieldName' => $prefix . '.' . $property,
490 4
                'class' => $embeddableMetadata->name,
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
491 4
                'columnPrefix' => $embeddableClass['columnPrefix'],
492 4
                'declaredField' => $embeddableClass['declaredField']
493 1
                        ? $prefix . '.' . $embeddableClass['declaredField']
494 4
                        : $prefix,
495 4
                'originalField' => $embeddableClass['originalField'] ?: $property,
496
            ));
497
        }
498 11
    }
499
500
    /**
501
     * Copy the table indices from the parent class superclass to the child class
502
     *
503
     * @param ClassMetadata $subClass
504
     * @param ClassMetadata $parentClass
505
     *
506
     * @return void
507
     */
508 127
    private function addInheritedIndexes(ClassMetadata $subClass, ClassMetadata $parentClass)
509
    {
510 127
        if (! $parentClass->isMappedSuperclass) {
511 82
            return;
512
        }
513
514 51
        foreach (array('uniqueConstraints', 'indexes') as $indexType) {
515 51
            if (isset($parentClass->table[$indexType])) {
516 1
                foreach ($parentClass->table[$indexType] as $indexName => $index) {
517 1
                    if (isset($subClass->table[$indexType][$indexName])) {
518
                        continue; // Let the inheriting table override indices
519
                    }
520
521 51
                    $subClass->table[$indexType][$indexName] = $index;
522
                }
523
            }
524
        }
525 51
    }
526
527
    /**
528
     * Adds inherited named queries to the subclass mapping.
529
     *
530
     * @since 2.2
531
     *
532
     * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass
533
     * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass
534
     *
535
     * @return void
536
     */
537 1
    private function addInheritedNamedQueries(ClassMetadata $subClass, ClassMetadata $parentClass)
538
    {
539 1
        foreach ($parentClass->namedQueries as $name => $query) {
540 1
            if ( ! isset ($subClass->namedQueries[$name])) {
541 1
                $subClass->addNamedQuery(array(
542 1
                    'name'  => $query['name'],
543 1
                    'query' => $query['query']
544
                ));
545
            }
546
        }
547 1
    }
548
549
    /**
550
     * Adds inherited named native queries to the subclass mapping.
551
     *
552
     * @since 2.3
553
     *
554
     * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass
555
     * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass
556
     *
557
     * @return void
558
     */
559 9
    private function addInheritedNamedNativeQueries(ClassMetadata $subClass, ClassMetadata $parentClass)
560
    {
561 9
        foreach ($parentClass->namedNativeQueries as $name => $query) {
562 9
            if ( ! isset ($subClass->namedNativeQueries[$name])) {
563 9
                $subClass->addNamedNativeQuery(array(
564 9
                    'name'              => $query['name'],
565 9
                    'query'             => $query['query'],
566 9
                    'isSelfClass'       => $query['isSelfClass'],
567 9
                    'resultSetMapping'  => $query['resultSetMapping'],
568 9
                    'resultClass'       => $query['isSelfClass'] ? $subClass->name : $query['resultClass'],
569
                ));
570
            }
571
        }
572 9
    }
573
574
    /**
575
     * Adds inherited sql result set mappings to the subclass mapping.
576
     *
577
     * @since 2.3
578
     *
579
     * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass
580
     * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass
581
     *
582
     * @return void
583
     */
584 9
    private function addInheritedSqlResultSetMappings(ClassMetadata $subClass, ClassMetadata $parentClass)
585
    {
586 9
        foreach ($parentClass->sqlResultSetMappings as $name => $mapping) {
587 9
            if ( ! isset ($subClass->sqlResultSetMappings[$name])) {
588 9
                $entities = array();
589 9
                foreach ($mapping['entities'] as $entity) {
590 9
                    $entities[] = array(
591 9
                        'fields'                => $entity['fields'],
592 9
                        'isSelfClass'           => $entity['isSelfClass'],
593 9
                        'discriminatorColumn'   => $entity['discriminatorColumn'],
594 9
                        'entityClass'           => $entity['isSelfClass'] ? $subClass->name : $entity['entityClass'],
595
                    );
596
                }
597
598 9
                $subClass->addSqlResultSetMapping(array(
599 9
                    'name'          => $mapping['name'],
600 9
                    'columns'       => $mapping['columns'],
601 9
                    'entities'      => $entities,
602
                ));
603
            }
604
        }
605 9
    }
606
607
    /**
608
     * Completes the ID generator mapping. If "auto" is specified we choose the generator
609
     * most appropriate for the targeted database platform.
610
     *
611
     * @param ClassMetadataInfo $class
612
     *
613
     * @return void
614
     *
615
     * @throws ORMException
616
     */
617 430
    private function completeIdGeneratorMapping(ClassMetadataInfo $class)
618
    {
619 430
        $idGenType = $class->generatorType;
620 430
        if ($idGenType == ClassMetadata::GENERATOR_TYPE_AUTO) {
621 312
            if ($this->getTargetPlatform()->prefersSequences()) {
622
                $class->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_SEQUENCE);
623 312
            } else if ($this->getTargetPlatform()->prefersIdentityColumns()) {
624 312
                $class->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_IDENTITY);
625
            } else {
626
                $class->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_TABLE);
627
            }
628
        }
629
630
        // Create & assign an appropriate ID generator instance
631 430
        switch ($class->generatorType) {
632 430
            case ClassMetadata::GENERATOR_TYPE_IDENTITY:
633 324
                $sequenceName = null;
634 324
                $fieldName    = $class->identifier ? $class->getSingleIdentifierFieldName() : null;
635
636
                // Platforms that do not have native IDENTITY support need a sequence to emulate this behaviour.
637 324
                if ($this->getTargetPlatform()->usesSequenceEmulatedIdentityColumns()) {
638
                    $columnName     = $class->getSingleIdentifierColumnName();
639
                    $quoted         = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']);
640
                    $sequencePrefix = $class->getSequencePrefix($this->getTargetPlatform());
641
                    $sequenceName   = $this->getTargetPlatform()->getIdentitySequenceName($sequencePrefix, $columnName);
642
                    $definition     = array(
643
                        'sequenceName' => $this->getTargetPlatform()->fixSchemaElementName($sequenceName)
644
                    );
645
646
                    if ($quoted) {
647
                        $definition['quoted'] = true;
648
                    }
649
650
                    $sequenceName = $this
651
                        ->em
652
                        ->getConfiguration()
653
                        ->getQuoteStrategy()
654
                        ->getSequenceName($definition, $class, $this->getTargetPlatform());
655
                }
656
657 324
                $generator = ($fieldName && $class->fieldMappings[$fieldName]['type'] === 'bigint')
0 ignored issues
show
Bug Best Practice introduced by
The expression $fieldName of type string|null is loosely compared to true; 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...
658 1
                    ? new BigIntegerIdentityGenerator($sequenceName)
659 324
                    : new IdentityGenerator($sequenceName);
660
661 324
                $class->setIdGenerator($generator);
662
663 324
                break;
664
665 152
            case ClassMetadata::GENERATOR_TYPE_SEQUENCE:
666
                // If there is no sequence definition yet, create a default definition
667 6
                $definition = $class->sequenceGeneratorDefinition;
668
669 6
                if ( ! $definition) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $definition 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...
670
                    $fieldName      = $class->getSingleIdentifierFieldName();
671
                    $sequenceName   = $class->getSequenceName($this->getTargetPlatform());
672
                    $quoted         = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']);
673
674
                    $definition = array(
675
                        'sequenceName'      => $this->getTargetPlatform()->fixSchemaElementName($sequenceName),
676
                        'allocationSize'    => 1,
677
                        'initialValue'      => 1,
678
                    );
679
680
                    if ($quoted) {
681
                        $definition['quoted'] = true;
682
                    }
683
684
                    $class->setSequenceGeneratorDefinition($definition);
685
                }
686
687 6
                $sequenceGenerator = new \Doctrine\ORM\Id\SequenceGenerator(
688 6
                    $this->em->getConfiguration()->getQuoteStrategy()->getSequenceName($definition, $class, $this->getTargetPlatform()),
689 6
                    $definition['allocationSize']
690
                );
691 6
                $class->setIdGenerator($sequenceGenerator);
692 6
                break;
693
694 149
            case ClassMetadata::GENERATOR_TYPE_NONE:
695 145
                $class->setIdGenerator(new \Doctrine\ORM\Id\AssignedGenerator());
696 145
                break;
697
698 6
            case ClassMetadata::GENERATOR_TYPE_UUID:
699 2
                $class->setIdGenerator(new \Doctrine\ORM\Id\UuidGenerator());
700 2
                break;
701
702 4
            case ClassMetadata::GENERATOR_TYPE_TABLE:
703
                throw new ORMException("TableGenerator not yet implemented.");
704
                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...
705
706 4
            case ClassMetadata::GENERATOR_TYPE_CUSTOM:
707 4
                $definition = $class->customGeneratorDefinition;
708 4
                if ( ! class_exists($definition['class'])) {
709 2
                    throw new ORMException("Can't instantiate custom generator : " .
710 2
                        $definition['class']);
711
                }
712 2
                $class->setIdGenerator(new $definition['class']);
713 2
                break;
714
715
            default:
716
                throw new ORMException("Unknown generator type: " . $class->generatorType);
717
        }
718 428
    }
719
720
    /**
721
     * Inherits the ID generator mapping from a parent class.
722
     *
723
     * @param ClassMetadataInfo $class
724
     * @param ClassMetadataInfo $parent
725
     */
726 87
    private function inheritIdGeneratorMapping(ClassMetadataInfo $class, ClassMetadataInfo $parent)
727
    {
728 87
        if ($parent->isIdGeneratorSequence()) {
729 3
            $class->setSequenceGeneratorDefinition($parent->sequenceGeneratorDefinition);
730 84
        } elseif ($parent->isIdGeneratorTable()) {
731
            $class->tableGeneratorDefinition = $parent->tableGeneratorDefinition;
732
        }
733
734 87
        if ($parent->generatorType) {
735 87
            $class->setIdGeneratorType($parent->generatorType);
736
        }
737
738 87
        if ($parent->idGenerator) {
739 87
            $class->setIdGenerator($parent->idGenerator);
740
        }
741 87
    }
742
743
    /**
744
     * {@inheritDoc}
745
     */
746 2030
    protected function wakeupReflection(ClassMetadataInterface $class, ReflectionService $reflService)
747
    {
748
        /* @var $class ClassMetadata */
749 2030
        $class->wakeupReflection($reflService);
750 2030
    }
751
752
    /**
753
     * {@inheritDoc}
754
     */
755 436
    protected function initializeReflection(ClassMetadataInterface $class, ReflectionService $reflService)
756
    {
757
        /* @var $class ClassMetadata */
758 436
        $class->initializeReflection($reflService);
759 436
    }
760
761
    /**
762
     * {@inheritDoc}
763
     */
764 4
    protected function getFqcnFromAlias($namespaceAlias, $simpleClassName)
765
    {
766 4
        return $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;
767
    }
768
769
    /**
770
     * {@inheritDoc}
771
     */
772 237
    protected function getDriver()
773
    {
774 237
        return $this->driver;
775
    }
776
777
    /**
778
     * {@inheritDoc}
779
     */
780 427
    protected function isEntity(ClassMetadataInterface $class)
781
    {
782 427
        return isset($class->isMappedSuperclass) && $class->isMappedSuperclass === false;
0 ignored issues
show
Bug introduced by
Accessing isMappedSuperclass on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
783
    }
784
785
    /**
786
     * @return Platforms\AbstractPlatform
787
     */
788 330
    private function getTargetPlatform()
789
    {
790 330
        if (!$this->targetPlatform) {
791 330
            $this->targetPlatform = $this->em->getConnection()->getDatabasePlatform();
792
        }
793
794 330
        return $this->targetPlatform;
795
    }
796
}
797