Completed
Pull Request — master (#5938)
by Maximilian
13:29 queued 05:17
created

ClassMetadataFactory::addInheritedIndexes()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 6.0359

Importance

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