Completed
Pull Request — master (#5586)
by Mihai
11:08
created

ClassMetadataFactory::initializeReflection()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1
Metric Value
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 9.4286
cc 1
eloc 2
nc 1
nop 2
crap 1
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 426
    protected function loadMetadata($name)
77
    {
78 426
        $loaded = parent::loadMetadata($name);
79
80 373
        array_map([$this, 'resolveDiscriminatorValue'], array_map([$this, 'getMetadataFor'], $loaded));
81
82 373
        return $loaded;
83
    }
84
85
    /**
86
     * @param EntityManagerInterface $em
87
     */
88 2315
    public function setEntityManager(EntityManagerInterface $em)
89
    {
90 2315
        $this->em = $em;
91 2315
    }
92
93
    /**
94
     * {@inheritDoc}
95
     */
96 492
    protected function initialize()
97
    {
98 492
        $this->driver = $this->em->getConfiguration()->getMetadataDriverImpl();
99 492
        $this->evm = $this->em->getEventManager();
100 492
        $this->initialized = true;
101 492
    }
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 424
    protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonSuperclassParents)
123
    {
124
        /* @var $class ClassMetadata */
125
        /* @var $parent ClassMetadata */
126 424
        if ($parent) {
127 100
            $class->setInheritanceType($parent->inheritanceType);
128 100
            $class->setDiscriminatorColumn($parent->discriminatorColumn);
129 100
            $class->setIdGeneratorType($parent->generatorType);
130 100
            $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 100
            $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 100
            $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 100
            $class->setIdentifier($parent->identifier);
134 100
            $class->setVersioned($parent->isVersioned);
135 100
            $class->setVersionField($parent->versionField);
136 100
            $class->setDiscriminatorMap($parent->discriminatorMap);
137 100
            $class->setLifecycleCallbacks($parent->lifecycleCallbacks);
138 100
            $class->setChangeTrackingPolicy($parent->changeTrackingPolicy);
139
140 100
            if ( ! empty($parent->customGeneratorDefinition)) {
141 1
                $class->setCustomGeneratorDefinition($parent->customGeneratorDefinition);
142
            }
143
144 100
            if ($parent->isMappedSuperclass) {
145 22
                $class->setCustomRepositoryClass($parent->customRepositoryClassName);
146 22
                $class->setCustomPersisterClass($parent->customPersisterClassName);
147
            }
148
        }
149
150
        // Invoke driver
151
        try {
152 424
            $this->driver->loadMetadataForClass($class->getName(), $class);
153 48
        } catch (ReflectionException $e) {
154
            throw MappingException::reflectionFailure($class->getName(), $e);
155
        }
156
157
        // If this class has a parent the id generator strategy is inherited.
158
        // However this is only true if the hierarchy of parents contains the root entity,
159
        // if it consists of mapped superclasses these don't necessarily include the id field.
160 387
        if ($parent && $rootEntityFound) {
161 74
            $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...
162
        } else {
163 383
            $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...
164
        }
165
166 385
        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...
167 385
            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...
168
169 12
                if (isset($embeddableClass['inherited'])) {
170 1
                    continue;
171
                }
172
173 12
                if ( ! (isset($embeddableClass['class']) && $embeddableClass['class'])) {
174 1
                    throw MappingException::missingEmbeddedClass($property);
175
                }
176
177 11
                if (isset($this->embeddablesActiveNesting[$embeddableClass['class']])) {
178 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...
179
                }
180
181 11
                $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...
182
183 11
                $embeddableMetadata = $this->getMetadataFor($embeddableClass['class']);
184
185 10
                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...
186 10
                    $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...
187
                }
188
189 10
                $identifier = $embeddableMetadata->getIdentifier();
190
191 10
                if (! empty($identifier)) {
192 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...
193
                }
194
195 10
                $class->inlineEmbeddable($property, $embeddableMetadata);
196
197 10
                unset($this->embeddablesActiveNesting[$class->name]);
198
            }
199
        }
200
201 382
        if ($parent) {
202 96
            if ($parent->isInheritanceTypeSingleTable()) {
203 30
                $class->setPrimaryTable($parent->table);
204
            }
205
206 96
            if ($parent) {
207 96
                $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...
208
            }
209
210 96
            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...
211 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...
212
            }
213
214 96
            if ($parent->containsForeignIdentifier) {
215
                $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...
216
            }
217
218 96
            if ( ! empty($parent->namedQueries)) {
219
                $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...
220
            }
221
222 96
            if ( ! empty($parent->namedNativeQueries)) {
223 8
                $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...
224
            }
225
226 96
            if ( ! empty($parent->sqlResultSetMappings)) {
227 8
                $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...
228
            }
229
230 96
            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...
231 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...
232
            }
233
        }
234
235 382
        $class->setParentClasses($nonSuperclassParents);
236
237 382
        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...
238 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...
239
        }
240
241 382
        if ($this->evm->hasListeners(Events::loadClassMetadata)) {
242 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...
243 6
            $this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs);
244
        }
245
246 381
        $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...
247 381
    }
248
249
    /**
250
     * Validate runtime metadata is correctly defined.
251
     *
252
     * @param ClassMetadata               $class
253
     * @param ClassMetadataInterface|null $parent
254
     *
255
     * @return void
256
     *
257
     * @throws MappingException
258
     */
259 381
    protected function validateRuntimeMetadata($class, $parent)
260
    {
261 381
        if ( ! $class->reflClass ) {
262
            // only validate if there is a reflection class instance
263 8
            return;
264
        }
265
266 373
        $class->validateIdentifier();
267 373
        $class->validateAssociations();
268 373
        $class->validateLifecycleCallbacks($this->getReflectionService());
269
270
        // verify inheritance
271 373
        if ( ! $class->isMappedSuperclass && !$class->isInheritanceTypeNone()) {
272 71
            if ( ! $parent) {
273 67
                if (count($class->discriminatorMap) == 0) {
274
                    throw MappingException::missingDiscriminatorMap($class->name);
275
                }
276 67
                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...
277 71
                    throw MappingException::missingDiscriminatorColumn($class->name);
278
                }
279
            }
280 333
        } 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...
281
            // second condition is necessary for mapped superclasses in the middle of an inheritance hierarchy
282
            throw MappingException::noInheritanceOnMappedSuperClass($class->name);
283
        }
284 373
    }
285
286
    /**
287
     * {@inheritDoc}
288
     */
289 419
    protected function newClassMetadataInstance($className)
290
    {
291 419
        return new ClassMetadata($className, $this->em->getConfiguration()->getNamingStrategy());
292
    }
293
294
    /**
295
     * Populates the discriminator value of the given metadata (if not set) by iterating over discriminator
296
     * map classes and looking for a fitting one.
297
     *
298
     * @param ClassMetadata $metadata
299
     *
300
     * @return void
301
     *
302
     * @throws MappingException
303
     */
304 373
    private function resolveDiscriminatorValue(ClassMetadata $metadata)
305
    {
306 373
        if ($metadata->discriminatorValue
307 359
            || ! $metadata->discriminatorMap
308 40
            || $metadata->isMappedSuperclass
309 40
            || ! $metadata->reflClass
310 373
            || $metadata->reflClass->isAbstract()
311
        ) {
312 373
            return;
313
        }
314
315
        // minor optimization: avoid loading related metadata when not needed
316 5
        foreach ($metadata->discriminatorMap as $discriminatorValue => $discriminatorClass) {
317 5
            if ($discriminatorClass === $metadata->name) {
318 3
                $metadata->discriminatorValue = $discriminatorValue;
319
320 5
                return;
321
            }
322
        }
323
324
        // iterate over discriminator mappings and resolve actual referenced classes according to existing metadata
325 2
        foreach ($metadata->discriminatorMap as $discriminatorValue => $discriminatorClass) {
326 2
            if ($metadata->name === $this->getMetadataFor($discriminatorClass)->getName()) {
327 1
                $metadata->discriminatorValue = $discriminatorValue;
328
329 2
                return;
330
            }
331
        }
332
333
        throw MappingException::mappedClassNotPartOfDiscriminatorMap($metadata->name, $metadata->rootEntityName);
334
    }
335
336
    /**
337
     * Adds a default discriminator map if no one is given
338
     *
339
     * If an entity is of any inheritance type and does not contain a
340
     * discriminator map, then the map is generated automatically. This process
341
     * is expensive computation wise.
342
     *
343
     * The automatically generated discriminator map contains the lowercase short name of
344
     * each class as key.
345
     *
346
     * @param \Doctrine\ORM\Mapping\ClassMetadata $class
347
     *
348
     * @throws MappingException
349
     */
350 1
    private function addDefaultDiscriminatorMap(ClassMetadata $class)
351
    {
352 1
        $allClasses = $this->driver->getAllClassNames();
353 1
        $fqcn = $class->getName();
354 1
        $map = array($this->getShortName($class->name) => $fqcn);
355
356 1
        $duplicates = array();
357 1
        foreach ($allClasses as $subClassCandidate) {
358 1
            if (is_subclass_of($subClassCandidate, $fqcn)) {
359 1
                $shortName = $this->getShortName($subClassCandidate);
360
361 1
                if (isset($map[$shortName])) {
362
                    $duplicates[] = $shortName;
363
                }
364
365 1
                $map[$shortName] = $subClassCandidate;
366
            }
367
        }
368
369 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...
370
            throw MappingException::duplicateDiscriminatorEntry($class->name, $duplicates, $map);
371
        }
372
373 1
        $class->setDiscriminatorMap($map);
374 1
    }
375
376
    /**
377
     * Gets the lower-case short name of a class.
378
     *
379
     * @param string $className
380
     *
381
     * @return string
382
     */
383 1
    private function getShortName($className)
384
    {
385 1
        if (strpos($className, "\\") === false) {
386
            return strtolower($className);
387
        }
388
389 1
        $parts = explode("\\", $className);
390
391 1
        return strtolower(end($parts));
392
    }
393
394
    /**
395
     * Adds inherited fields to the subclass mapping.
396
     *
397
     * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass
398
     * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass
399
     *
400
     * @return void
401
     */
402 100
    private function addInheritedFields(ClassMetadata $subClass, ClassMetadata $parentClass)
403
    {
404 100
        foreach ($parentClass->fieldMappings as $mapping) {
405 100
            if ( ! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
406 78
                $mapping['inherited'] = $parentClass->name;
407
            }
408 100
            if ( ! isset($mapping['declared'])) {
409 100
                $mapping['declared'] = $parentClass->name;
410
            }
411 100
            $subClass->addInheritedFieldMapping($mapping);
412
        }
413 100
        foreach ($parentClass->reflFields as $name => $field) {
414 100
            $subClass->reflFields[$name] = $field;
415
        }
416 100
    }
417
418
    /**
419
     * Adds inherited association mappings to the subclass mapping.
420
     *
421
     * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass
422
     * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass
423
     *
424
     * @return void
425
     *
426
     * @throws MappingException
427
     */
428 100
    private function addInheritedRelations(ClassMetadata $subClass, ClassMetadata $parentClass)
429
    {
430 100
        foreach ($parentClass->associationMappings as $field => $mapping) {
431 45
            if ($parentClass->isMappedSuperclass) {
432 11
                if ($mapping['type'] & ClassMetadata::TO_MANY && !$mapping['isOwningSide']) {
433
                    throw MappingException::illegalToManyAssociationOnMappedSuperclass($parentClass->name, $field);
434
                }
435 11
                $mapping['sourceEntity'] = $subClass->name;
436
            }
437
438
            //$subclassMapping = $mapping;
439 45
            if ( ! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) {
440 34
                $mapping['inherited'] = $parentClass->name;
441
            }
442 45
            if ( ! isset($mapping['declared'])) {
443 45
                $mapping['declared'] = $parentClass->name;
444
            }
445 45
            $subClass->addInheritedAssociationMapping($mapping);
446
        }
447 100
    }
448
449 100
    private function addInheritedEmbeddedClasses(ClassMetadata $subClass, ClassMetadata $parentClass)
450
    {
451 100
        foreach ($parentClass->embeddedClasses as $field => $embeddedClass) {
452 1
            if ( ! isset($embeddedClass['inherited']) && ! $parentClass->isMappedSuperclass) {
453 1
                $embeddedClass['inherited'] = $parentClass->name;
454
            }
455 1
            if ( ! isset($embeddedClass['declared'])) {
456 1
                $embeddedClass['declared'] = $parentClass->name;
457
            }
458
459 1
            $subClass->embeddedClasses[$field] = $embeddedClass;
460
        }
461 100
    }
462
463
    /**
464
     * Adds nested embedded classes metadata to a parent class.
465
     *
466
     * @param ClassMetadata $subClass    Sub embedded class metadata to add nested embedded classes metadata from.
467
     * @param ClassMetadata $parentClass Parent class to add nested embedded classes metadata to.
468
     * @param string        $prefix      Embedded classes' prefix to use for nested embedded classes field names.
469
     */
470 10
    private function addNestedEmbeddedClasses(ClassMetadata $subClass, ClassMetadata $parentClass, $prefix)
471
    {
472 10
        foreach ($subClass->embeddedClasses as $property => $embeddableClass) {
473 4
            if (isset($embeddableClass['inherited'])) {
474
                continue;
475
            }
476
477 4
            $embeddableMetadata = $this->getMetadataFor($embeddableClass['class']);
478
479 4
            $parentClass->mapEmbedded(array(
480 4
                'fieldName' => $prefix . '.' . $property,
481 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...
482 4
                'columnPrefix' => $embeddableClass['columnPrefix'],
483 4
                'declaredField' => $embeddableClass['declaredField']
484 1
                        ? $prefix . '.' . $embeddableClass['declaredField']
485 4
                        : $prefix,
486 4
                'originalField' => $embeddableClass['originalField'] ?: $property,
487
            ));
488
        }
489 10
    }
490
491
    /**
492
     * Copy the table indices from the parent class superclass to the child class
493
     *
494
     * @param ClassMetadata $subClass
495
     * @param ClassMetadata $parentClass
496
     *
497
     * @return void
498
     */
499 96
    private function addInheritedIndexes(ClassMetadata $subClass, ClassMetadata $parentClass)
500
    {
501 96
        if (! $parentClass->isMappedSuperclass) {
502 74
            return;
503
        }
504
505 22
        foreach (array('uniqueConstraints', 'indexes') as $indexType) {
506 22
            if (isset($parentClass->table[$indexType])) {
507
                foreach ($parentClass->table[$indexType] as $indexName => $index) {
508
                    if (isset($subClass->table[$indexType][$indexName])) {
509
                        continue; // Let the inheriting table override indices
510
                    }
511
512 22
                    $subClass->table[$indexType][$indexName] = $index;
513
                }
514
            }
515
        }
516 22
    }
517
518
    /**
519
     * Adds inherited named queries to the subclass mapping.
520
     *
521
     * @since 2.2
522
     *
523
     * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass
524
     * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass
525
     *
526
     * @return void
527
     */
528
    private function addInheritedNamedQueries(ClassMetadata $subClass, ClassMetadata $parentClass)
529
    {
530
        foreach ($parentClass->namedQueries as $name => $query) {
531
            if ( ! isset ($subClass->namedQueries[$name])) {
532
                $subClass->addNamedQuery(array(
533
                    'name'  => $query['name'],
534
                    'query' => $query['query']
535
                ));
536
            }
537
        }
538
    }
539
540
    /**
541
     * Adds inherited named native queries to the subclass mapping.
542
     *
543
     * @since 2.3
544
     *
545
     * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass
546
     * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass
547
     *
548
     * @return void
549
     */
550 8
    private function addInheritedNamedNativeQueries(ClassMetadata $subClass, ClassMetadata $parentClass)
551
    {
552 8
        foreach ($parentClass->namedNativeQueries as $name => $query) {
553 8
            if ( ! isset ($subClass->namedNativeQueries[$name])) {
554 8
                $subClass->addNamedNativeQuery(array(
555 8
                    'name'              => $query['name'],
556 8
                    'query'             => $query['query'],
557 8
                    'isSelfClass'       => $query['isSelfClass'],
558 8
                    'resultSetMapping'  => $query['resultSetMapping'],
559 8
                    'resultClass'       => $query['isSelfClass'] ? $subClass->name : $query['resultClass'],
560
                ));
561
            }
562
        }
563 8
    }
564
565
    /**
566
     * Adds inherited sql result set mappings to the subclass mapping.
567
     *
568
     * @since 2.3
569
     *
570
     * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass
571
     * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass
572
     *
573
     * @return void
574
     */
575 8
    private function addInheritedSqlResultSetMappings(ClassMetadata $subClass, ClassMetadata $parentClass)
576
    {
577 8
        foreach ($parentClass->sqlResultSetMappings as $name => $mapping) {
578 8
            if ( ! isset ($subClass->sqlResultSetMappings[$name])) {
579 8
                $entities = array();
580 8
                foreach ($mapping['entities'] as $entity) {
581 8
                    $entities[] = array(
582 8
                        'fields'                => $entity['fields'],
583 8
                        'isSelfClass'           => $entity['isSelfClass'],
584 8
                        'discriminatorColumn'   => $entity['discriminatorColumn'],
585 8
                        'entityClass'           => $entity['isSelfClass'] ? $subClass->name : $entity['entityClass'],
586
                    );
587
                }
588
589 8
                $subClass->addSqlResultSetMapping(array(
590 8
                    'name'          => $mapping['name'],
591 8
                    'columns'       => $mapping['columns'],
592 8
                    'entities'      => $entities,
593
                ));
594
            }
595
        }
596 8
    }
597
598
    /**
599
     * Completes the ID generator mapping. If "auto" is specified we choose the generator
600
     * most appropriate for the targeted database platform.
601
     *
602
     * @param ClassMetadataInfo $class
603
     *
604
     * @return void
605
     *
606
     * @throws ORMException
607
     */
608 383
    private function completeIdGeneratorMapping(ClassMetadataInfo $class)
609
    {
610 383
        $idGenType = $class->generatorType;
611 383
        if ($idGenType == ClassMetadata::GENERATOR_TYPE_AUTO) {
612 290
            if ($this->getTargetPlatform()->prefersSequences()) {
613
                $class->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_SEQUENCE);
614 290
            } else if ($this->getTargetPlatform()->prefersIdentityColumns()) {
615 290
                $class->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_IDENTITY);
616
            } else {
617
                $class->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_TABLE);
618
            }
619
        }
620
621
        // Create & assign an appropriate ID generator instance
622 383
        switch ($class->generatorType) {
623 383
            case ClassMetadata::GENERATOR_TYPE_IDENTITY:
624 302
                $sequenceName = null;
625 302
                $fieldName    = $class->identifier ? $class->getSingleIdentifierFieldName() : null;
626
627
                // Platforms that do not have native IDENTITY support need a sequence to emulate this behaviour.
628 302
                if ($this->getTargetPlatform()->usesSequenceEmulatedIdentityColumns()) {
629
                    $columnName     = $class->getSingleIdentifierColumnName();
630
                    $quoted         = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']);
631
                    $sequencePrefix = $class->getSequencePrefix($this->getTargetPlatform());
632
                    $sequenceName   = $this->getTargetPlatform()->getIdentitySequenceName($sequencePrefix, $columnName);
633
                    $definition     = array(
634
                        'sequenceName' => $this->getTargetPlatform()->fixSchemaElementName($sequenceName)
635
                    );
636
637
                    if ($quoted) {
638
                        $definition['quoted'] = true;
639
                    }
640
641
                    $sequenceName = $this
642
                        ->em
643
                        ->getConfiguration()
644
                        ->getQuoteStrategy()
645
                        ->getSequenceName($definition, $class, $this->getTargetPlatform());
646
                }
647
648 302
                $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...
649 1
                    ? new BigIntegerIdentityGenerator($sequenceName)
650 302
                    : new IdentityGenerator($sequenceName);
651
652 302
                $class->setIdGenerator($generator);
653
654 302
                break;
655
656 117
            case ClassMetadata::GENERATOR_TYPE_SEQUENCE:
657
                // If there is no sequence definition yet, create a default definition
658 3
                $definition = $class->sequenceGeneratorDefinition;
659
660 3
                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...
661
                    $fieldName      = $class->getSingleIdentifierFieldName();
662
                    $sequenceName   = $class->getSequenceName($this->getTargetPlatform());
663
                    $quoted         = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']);
664
665
                    $definition = array(
666
                        'sequenceName'      => $this->getTargetPlatform()->fixSchemaElementName($sequenceName),
667
                        'allocationSize'    => 1,
668
                        'initialValue'      => 1,
669
                    );
670
671
                    if ($quoted) {
672
                        $definition['quoted'] = true;
673
                    }
674
675
                    $class->setSequenceGeneratorDefinition($definition);
676
                }
677
678 3
                $sequenceGenerator = new \Doctrine\ORM\Id\SequenceGenerator(
679 3
                    $this->em->getConfiguration()->getQuoteStrategy()->getSequenceName($definition, $class, $this->getTargetPlatform()),
680 3
                    $definition['allocationSize']
681
                );
682 3
                $class->setIdGenerator($sequenceGenerator);
683 3
                break;
684
685 114
            case ClassMetadata::GENERATOR_TYPE_NONE:
686 110
                $class->setIdGenerator(new \Doctrine\ORM\Id\AssignedGenerator());
687 110
                break;
688
689 6
            case ClassMetadata::GENERATOR_TYPE_UUID:
690 2
                $class->setIdGenerator(new \Doctrine\ORM\Id\UuidGenerator());
691 2
                break;
692
693 4
            case ClassMetadata::GENERATOR_TYPE_TABLE:
694
                throw new ORMException("TableGenerator not yet implemented.");
695
                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...
696
697 4
            case ClassMetadata::GENERATOR_TYPE_CUSTOM:
698 4
                $definition = $class->customGeneratorDefinition;
699 4
                if ( ! class_exists($definition['class'])) {
700 2
                    throw new ORMException("Can't instantiate custom generator : " .
701 2
                        $definition['class']);
702
                }
703 2
                $class->setIdGenerator(new $definition['class']);
704 2
                break;
705
706
            default:
707
                throw new ORMException("Unknown generator type: " . $class->generatorType);
708
        }
709 381
    }
710
711
    /**
712
     * Inherits the ID generator mapping from a parent class.
713
     *
714
     * @param ClassMetadataInfo $class
715
     * @param ClassMetadataInfo $parent
716
     */
717 79
    private function inheritIdGeneratorMapping(ClassMetadataInfo $class, ClassMetadataInfo $parent)
718
    {
719 79
        if ($parent->isIdGeneratorSequence()) {
720 1
            $class->setSequenceGeneratorDefinition($parent->sequenceGeneratorDefinition);
721 78
        } elseif ($parent->isIdGeneratorTable()) {
722
            $class->tableGeneratorDefinition = $parent->tableGeneratorDefinition;
723
        }
724
725 79
        if ($parent->generatorType) {
726 79
            $class->setIdGeneratorType($parent->generatorType);
727
        }
728
729 79
        if ($parent->idGenerator) {
730 79
            $class->setIdGenerator($parent->idGenerator);
731
        }
732 79
    }
733
734
    /**
735
     * {@inheritDoc}
736
     */
737 1966
    protected function wakeupReflection(ClassMetadataInterface $class, ReflectionService $reflService)
738
    {
739
        /* @var $class ClassMetadata */
740 1966
        $class->wakeupReflection($reflService);
741 1966
    }
742
743
    /**
744
     * {@inheritDoc}
745
     */
746 424
    protected function initializeReflection(ClassMetadataInterface $class, ReflectionService $reflService)
747
    {
748
        /* @var $class ClassMetadata */
749 424
        $class->initializeReflection($reflService);
750 424
    }
751
752
    /**
753
     * {@inheritDoc}
754
     */
755 4
    protected function getFqcnFromAlias($namespaceAlias, $simpleClassName)
756
    {
757 4
        return $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;
758
    }
759
760
    /**
761
     * {@inheritDoc}
762
     */
763 227
    protected function getDriver()
764
    {
765 227
        return $this->driver;
766
    }
767
768
    /**
769
     * {@inheritDoc}
770
     */
771 381
    protected function isEntity(ClassMetadataInterface $class)
772
    {
773 381
        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...
774
    }
775
776
    /**
777
     * @return Platforms\AbstractPlatform
778
     */
779 305
    private function getTargetPlatform()
780
    {
781 305
        if (!$this->targetPlatform) {
782 305
            $this->targetPlatform = $this->em->getConnection()->getDatabasePlatform();
783
        }
784
785 305
        return $this->targetPlatform;
786
    }
787
}
788