These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
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 = []; |
||
72 | |||
73 | /** |
||
74 | * {@inheritDoc} |
||
75 | */ |
||
76 | 458 | protected function loadMetadata($name) |
|
77 | { |
||
78 | 458 | $loaded = parent::loadMetadata($name); |
|
79 | |||
80 | 439 | array_map([$this, 'resolveDiscriminatorValue'], array_map([$this, 'getMetadataFor'], $loaded)); |
|
81 | |||
82 | 439 | return $loaded; |
|
83 | } |
||
84 | |||
85 | /** |
||
86 | * @param EntityManagerInterface $em |
||
87 | */ |
||
88 | 2393 | public function setEntityManager(EntityManagerInterface $em) |
|
89 | { |
||
90 | 2393 | $this->em = $em; |
|
91 | 2393 | } |
|
92 | |||
93 | /** |
||
94 | * {@inheritDoc} |
||
95 | */ |
||
96 | 527 | protected function initialize() |
|
97 | { |
||
98 | 527 | $this->driver = $this->em->getConfiguration()->getMetadataDriverImpl(); |
|
99 | 527 | $this->evm = $this->em->getEventManager(); |
|
100 | 527 | $this->initialized = true; |
|
101 | 527 | } |
|
102 | |||
103 | /** |
||
104 | * {@inheritDoc} |
||
105 | */ |
||
106 | 3 | protected function onNotFoundMetadata($className) |
|
107 | { |
||
108 | 3 | if (! $this->evm->hasListeners(Events::onClassMetadataNotFound)) { |
|
109 | 1 | return; |
|
110 | } |
||
111 | |||
112 | 2 | $eventArgs = new OnClassMetadataNotFoundEventArgs($className, $this->em); |
|
113 | |||
114 | 2 | $this->evm->dispatchEvent(Events::onClassMetadataNotFound, $eventArgs); |
|
115 | |||
116 | 2 | return $eventArgs->getFoundMetadata(); |
|
117 | } |
||
118 | |||
119 | /** |
||
120 | * {@inheritDoc} |
||
121 | */ |
||
122 | 455 | protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonSuperclassParents) |
|
123 | { |
||
124 | /* @var $class ClassMetadata */ |
||
125 | /* @var $parent ClassMetadata */ |
||
126 | 455 | if ($parent) { |
|
127 | 138 | $class->setInheritanceType($parent->inheritanceType); |
|
128 | 138 | $class->setDiscriminatorColumn($parent->discriminatorColumn); |
|
129 | 138 | $class->setIdGeneratorType($parent->generatorType); |
|
130 | 138 | $this->addInheritedFields($class, $parent); |
|
131 | 138 | $this->addInheritedRelations($class, $parent); |
|
132 | 137 | $this->addInheritedEmbeddedClasses($class, $parent); |
|
133 | 137 | $class->setIdentifier($parent->identifier); |
|
134 | 137 | $class->setVersioned($parent->isVersioned); |
|
135 | 137 | $class->setVersionField($parent->versionField); |
|
136 | 137 | $class->setDiscriminatorMap($parent->discriminatorMap); |
|
137 | 137 | $class->setLifecycleCallbacks($parent->lifecycleCallbacks); |
|
138 | 137 | $class->setChangeTrackingPolicy($parent->changeTrackingPolicy); |
|
139 | |||
140 | 137 | if ( ! empty($parent->customGeneratorDefinition)) { |
|
141 | 1 | $class->setCustomGeneratorDefinition($parent->customGeneratorDefinition); |
|
142 | } |
||
143 | |||
144 | 137 | if ($parent->isMappedSuperclass) { |
|
145 | 53 | $class->setCustomRepositoryClass($parent->customRepositoryClassName); |
|
146 | } |
||
147 | } |
||
148 | |||
149 | // Invoke driver |
||
150 | try { |
||
151 | 455 | $this->driver->loadMetadataForClass($class->getName(), $class); |
|
152 | 2 | } catch (ReflectionException $e) { |
|
153 | throw MappingException::reflectionFailure($class->getName(), $e); |
||
154 | } |
||
155 | |||
156 | // If this class has a parent the id generator strategy is inherited. |
||
157 | // However this is only true if the hierarchy of parents contains the root entity, |
||
158 | // if it consists of mapped superclasses these don't necessarily include the id field. |
||
159 | 453 | if ($parent && $rootEntityFound) { |
|
160 | 90 | $this->inheritIdGeneratorMapping($class, $parent); |
|
161 | } else { |
||
162 | 449 | $this->completeIdGeneratorMapping($class); |
|
163 | } |
||
164 | |||
165 | 451 | if (!$class->isMappedSuperclass) { |
|
166 | 449 | foreach ($class->embeddedClasses as $property => $embeddableClass) { |
|
167 | |||
168 | 14 | if (isset($embeddableClass['inherited'])) { |
|
169 | 1 | continue; |
|
170 | } |
||
171 | |||
172 | 14 | if ( ! (isset($embeddableClass['class']) && $embeddableClass['class'])) { |
|
173 | 1 | throw MappingException::missingEmbeddedClass($property); |
|
174 | } |
||
175 | |||
176 | 13 | if (isset($this->embeddablesActiveNesting[$embeddableClass['class']])) { |
|
177 | 2 | throw MappingException::infiniteEmbeddableNesting($class->name, $property); |
|
178 | } |
||
179 | |||
180 | 13 | $this->embeddablesActiveNesting[$class->name] = true; |
|
181 | |||
182 | 13 | $embeddableMetadata = $this->getMetadataFor($embeddableClass['class']); |
|
183 | |||
184 | 12 | if ($embeddableMetadata->isEmbeddedClass) { |
|
185 | 12 | $this->addNestedEmbeddedClasses($embeddableMetadata, $class, $property); |
|
186 | } |
||
187 | |||
188 | 12 | $identifier = $embeddableMetadata->getIdentifier(); |
|
189 | |||
190 | 12 | if (! empty($identifier)) { |
|
191 | 5 | $this->inheritIdGeneratorMapping($class, $embeddableMetadata); |
|
192 | } |
||
193 | |||
194 | 12 | $class->inlineEmbeddable($property, $embeddableMetadata); |
|
195 | |||
196 | 12 | unset($this->embeddablesActiveNesting[$class->name]); |
|
197 | } |
||
198 | } |
||
199 | |||
200 | 448 | if ($parent) { |
|
201 | 137 | if ($parent->isInheritanceTypeSingleTable()) { |
|
202 | 37 | $class->setPrimaryTable($parent->table); |
|
203 | } |
||
204 | |||
205 | 137 | if ($parent) { |
|
206 | 137 | $this->addInheritedIndexes($class, $parent); |
|
207 | } |
||
208 | |||
209 | 137 | if ($parent->cache) { |
|
210 | 3 | $class->cache = $parent->cache; |
|
211 | } |
||
212 | |||
213 | 137 | if ($parent->containsForeignIdentifier) { |
|
214 | $class->containsForeignIdentifier = true; |
||
215 | } |
||
216 | |||
217 | 137 | if ( ! empty($parent->namedQueries)) { |
|
218 | 1 | $this->addInheritedNamedQueries($class, $parent); |
|
219 | } |
||
220 | |||
221 | 137 | if ( ! empty($parent->namedNativeQueries)) { |
|
222 | 9 | $this->addInheritedNamedNativeQueries($class, $parent); |
|
223 | } |
||
224 | |||
225 | 137 | if ( ! empty($parent->sqlResultSetMappings)) { |
|
226 | 9 | $this->addInheritedSqlResultSetMappings($class, $parent); |
|
227 | } |
||
228 | |||
229 | 137 | if ( ! empty($parent->entityListeners) && empty($class->entityListeners)) { |
|
230 | 15 | $class->entityListeners = $parent->entityListeners; |
|
231 | } |
||
232 | } |
||
233 | |||
234 | 448 | $class->setParentClasses($nonSuperclassParents); |
|
235 | |||
236 | 448 | if ($class->isRootEntity() && ! $class->isInheritanceTypeNone() && ! $class->discriminatorMap) { |
|
237 | 1 | $this->addDefaultDiscriminatorMap($class); |
|
238 | } |
||
239 | |||
240 | 448 | if ($this->evm->hasListeners(Events::loadClassMetadata)) { |
|
241 | 6 | $eventArgs = new LoadClassMetadataEventArgs($class, $this->em); |
|
242 | 6 | $this->evm->dispatchEvent(Events::loadClassMetadata, $eventArgs); |
|
243 | } |
||
244 | |||
245 | 447 | $this->validateRuntimeMetadata($class, $parent); |
|
246 | 446 | } |
|
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 | 447 | protected function validateRuntimeMetadata($class, $parent) |
|
259 | { |
||
260 | 447 | if ( ! $class->reflClass ) { |
|
261 | // only validate if there is a reflection class instance |
||
262 | 8 | return; |
|
263 | } |
||
264 | |||
265 | 439 | $class->validateIdentifier(); |
|
266 | 439 | $class->validateAssociations(); |
|
267 | 439 | $class->validateLifecycleCallbacks($this->getReflectionService()); |
|
268 | |||
269 | // verify inheritance |
||
270 | 439 | if ( ! $class->isMappedSuperclass && !$class->isInheritanceTypeNone()) { |
|
271 | 80 | if ( ! $parent) { |
|
272 | 76 | if (count($class->discriminatorMap) == 0) { |
|
273 | throw MappingException::missingDiscriminatorMap($class->name); |
||
274 | } |
||
275 | 76 | if ( ! $class->discriminatorColumn) { |
|
276 | 80 | throw MappingException::missingDiscriminatorColumn($class->name); |
|
277 | } |
||
278 | } |
||
279 | 400 | } else if ($class->isMappedSuperclass && $class->name == $class->rootEntityName && (count($class->discriminatorMap) || $class->discriminatorColumn)) { |
|
280 | // second condition is necessary for mapped superclasses in the middle of an inheritance hierarchy |
||
281 | 1 | throw MappingException::noInheritanceOnMappedSuperClass($class->name); |
|
282 | } |
||
283 | 438 | } |
|
284 | |||
285 | /** |
||
286 | * {@inheritDoc} |
||
287 | */ |
||
288 | 450 | protected function newClassMetadataInstance($className) |
|
289 | { |
||
290 | 450 | 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 | 439 | private function resolveDiscriminatorValue(ClassMetadata $metadata) |
|
304 | { |
||
305 | 439 | if ($metadata->discriminatorValue |
|
306 | 422 | || ! $metadata->discriminatorMap |
|
307 | 46 | || $metadata->isMappedSuperclass |
|
308 | 45 | || ! $metadata->reflClass |
|
309 | 439 | || $metadata->reflClass->isAbstract() |
|
310 | ) { |
||
311 | 439 | 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 = [$this->getShortName($class->name) => $fqcn]; |
|
354 | |||
355 | 1 | $duplicates = []; |
|
356 | 1 | foreach ($allClasses as $subClassCandidate) { |
|
357 | 1 | if (is_subclass_of($subClassCandidate, $fqcn)) { |
|
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) { |
|
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 | 138 | private function addInheritedFields(ClassMetadata $subClass, ClassMetadata $parentClass) |
|
402 | { |
||
403 | 138 | View Code Duplication | foreach ($parentClass->fieldMappings as $mapping) { |
0 ignored issues
–
show
|
|||
404 | 122 | if ( ! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) { |
|
405 | 90 | $mapping['inherited'] = $parentClass->name; |
|
406 | } |
||
407 | 122 | if ( ! isset($mapping['declared'])) { |
|
408 | 122 | $mapping['declared'] = $parentClass->name; |
|
409 | } |
||
410 | 122 | $subClass->addInheritedFieldMapping($mapping); |
|
411 | } |
||
412 | 138 | foreach ($parentClass->reflFields as $name => $field) { |
|
413 | 123 | $subClass->reflFields[$name] = $field; |
|
414 | } |
||
415 | 138 | } |
|
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 | 138 | private function addInheritedRelations(ClassMetadata $subClass, ClassMetadata $parentClass) |
|
428 | { |
||
429 | 138 | foreach ($parentClass->associationMappings as $field => $mapping) { |
|
430 | 58 | if ($parentClass->isMappedSuperclass) { |
|
431 | 16 | if ($mapping['type'] & ClassMetadata::TO_MANY && !$mapping['isOwningSide']) { |
|
432 | 1 | throw MappingException::illegalToManyAssociationOnMappedSuperclass($parentClass->name, $field); |
|
433 | } |
||
434 | 15 | $mapping['sourceEntity'] = $subClass->name; |
|
435 | } |
||
436 | |||
437 | //$subclassMapping = $mapping; |
||
438 | 57 | if ( ! isset($mapping['inherited']) && ! $parentClass->isMappedSuperclass) { |
|
439 | 42 | $mapping['inherited'] = $parentClass->name; |
|
440 | } |
||
441 | 57 | if ( ! isset($mapping['declared'])) { |
|
442 | 57 | $mapping['declared'] = $parentClass->name; |
|
443 | } |
||
444 | 57 | $subClass->addInheritedAssociationMapping($mapping); |
|
445 | } |
||
446 | 137 | } |
|
447 | |||
448 | 137 | private function addInheritedEmbeddedClasses(ClassMetadata $subClass, ClassMetadata $parentClass) |
|
449 | { |
||
450 | 137 | View Code Duplication | 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 | 137 | } |
|
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 | 12 | private function addNestedEmbeddedClasses(ClassMetadata $subClass, ClassMetadata $parentClass, $prefix) |
|
470 | { |
||
471 | 12 | 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( |
|
479 | [ |
||
480 | 4 | 'fieldName' => $prefix . '.' . $property, |
|
481 | 4 | 'class' => $embeddableMetadata->name, |
|
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 | } |
||
490 | 12 | } |
|
491 | |||
492 | /** |
||
493 | * Copy the table indices from the parent class superclass to the child class |
||
494 | * |
||
495 | * @param ClassMetadata $subClass |
||
496 | * @param ClassMetadata $parentClass |
||
497 | * |
||
498 | * @return void |
||
499 | */ |
||
500 | 137 | private function addInheritedIndexes(ClassMetadata $subClass, ClassMetadata $parentClass) |
|
501 | { |
||
502 | 137 | if (! $parentClass->isMappedSuperclass) { |
|
503 | 90 | return; |
|
504 | } |
||
505 | |||
506 | 53 | foreach (['uniqueConstraints', 'indexes'] as $indexType) { |
|
507 | 53 | if (isset($parentClass->table[$indexType])) { |
|
508 | 1 | foreach ($parentClass->table[$indexType] as $indexName => $index) { |
|
509 | 1 | if (isset($subClass->table[$indexType][$indexName])) { |
|
510 | continue; // Let the inheriting table override indices |
||
511 | } |
||
512 | |||
513 | 53 | $subClass->table[$indexType][$indexName] = $index; |
|
514 | } |
||
515 | } |
||
516 | } |
||
517 | 53 | } |
|
518 | |||
519 | /** |
||
520 | * Adds inherited named queries to the subclass mapping. |
||
521 | * |
||
522 | * @since 2.2 |
||
523 | * |
||
524 | * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass |
||
525 | * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass |
||
526 | * |
||
527 | * @return void |
||
528 | */ |
||
529 | 1 | private function addInheritedNamedQueries(ClassMetadata $subClass, ClassMetadata $parentClass) |
|
530 | { |
||
531 | 1 | foreach ($parentClass->namedQueries as $name => $query) { |
|
532 | 1 | if ( ! isset ($subClass->namedQueries[$name])) { |
|
533 | 1 | $subClass->addNamedQuery( |
|
534 | [ |
||
535 | 1 | 'name' => $query['name'], |
|
536 | 1 | 'query' => $query['query'] |
|
537 | ] |
||
538 | ); |
||
539 | } |
||
540 | } |
||
541 | 1 | } |
|
542 | |||
543 | /** |
||
544 | * Adds inherited named native queries to the subclass mapping. |
||
545 | * |
||
546 | * @since 2.3 |
||
547 | * |
||
548 | * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass |
||
549 | * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass |
||
550 | * |
||
551 | * @return void |
||
552 | */ |
||
553 | 9 | private function addInheritedNamedNativeQueries(ClassMetadata $subClass, ClassMetadata $parentClass) |
|
554 | { |
||
555 | 9 | foreach ($parentClass->namedNativeQueries as $name => $query) { |
|
556 | 9 | if ( ! isset ($subClass->namedNativeQueries[$name])) { |
|
557 | 9 | $subClass->addNamedNativeQuery( |
|
558 | [ |
||
559 | 9 | 'name' => $query['name'], |
|
560 | 9 | 'query' => $query['query'], |
|
561 | 9 | 'isSelfClass' => $query['isSelfClass'], |
|
562 | 9 | 'resultSetMapping' => $query['resultSetMapping'], |
|
563 | 9 | 'resultClass' => $query['isSelfClass'] ? $subClass->name : $query['resultClass'], |
|
564 | ] |
||
565 | ); |
||
566 | } |
||
567 | } |
||
568 | 9 | } |
|
569 | |||
570 | /** |
||
571 | * Adds inherited sql result set mappings to the subclass mapping. |
||
572 | * |
||
573 | * @since 2.3 |
||
574 | * |
||
575 | * @param \Doctrine\ORM\Mapping\ClassMetadata $subClass |
||
576 | * @param \Doctrine\ORM\Mapping\ClassMetadata $parentClass |
||
577 | * |
||
578 | * @return void |
||
579 | */ |
||
580 | 9 | private function addInheritedSqlResultSetMappings(ClassMetadata $subClass, ClassMetadata $parentClass) |
|
581 | { |
||
582 | 9 | foreach ($parentClass->sqlResultSetMappings as $name => $mapping) { |
|
583 | 9 | if ( ! isset ($subClass->sqlResultSetMappings[$name])) { |
|
584 | 9 | $entities = []; |
|
585 | 9 | foreach ($mapping['entities'] as $entity) { |
|
586 | 9 | $entities[] = [ |
|
587 | 9 | 'fields' => $entity['fields'], |
|
588 | 9 | 'isSelfClass' => $entity['isSelfClass'], |
|
589 | 9 | 'discriminatorColumn' => $entity['discriminatorColumn'], |
|
590 | 9 | 'entityClass' => $entity['isSelfClass'] ? $subClass->name : $entity['entityClass'], |
|
591 | ]; |
||
592 | } |
||
593 | |||
594 | 9 | $subClass->addSqlResultSetMapping( |
|
595 | [ |
||
596 | 9 | 'name' => $mapping['name'], |
|
597 | 9 | 'columns' => $mapping['columns'], |
|
598 | 9 | 'entities' => $entities, |
|
599 | ] |
||
600 | ); |
||
601 | } |
||
602 | } |
||
603 | 9 | } |
|
604 | |||
605 | /** |
||
606 | * Completes the ID generator mapping. If "auto" is specified we choose the generator |
||
607 | * most appropriate for the targeted database platform. |
||
608 | * |
||
609 | * @param ClassMetadataInfo $class |
||
610 | * |
||
611 | * @return void |
||
612 | * |
||
613 | * @throws ORMException |
||
614 | */ |
||
615 | 449 | private function completeIdGeneratorMapping(ClassMetadataInfo $class) |
|
616 | { |
||
617 | 449 | $idGenType = $class->generatorType; |
|
618 | 449 | if ($idGenType == ClassMetadata::GENERATOR_TYPE_AUTO) { |
|
619 | 322 | if ($this->getTargetPlatform()->prefersSequences()) { |
|
620 | $class->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_SEQUENCE); |
||
621 | 322 | } else if ($this->getTargetPlatform()->prefersIdentityColumns()) { |
|
622 | 322 | $class->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_IDENTITY); |
|
623 | } else { |
||
624 | $class->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_TABLE); |
||
625 | } |
||
626 | } |
||
627 | |||
628 | // Create & assign an appropriate ID generator instance |
||
629 | 449 | switch ($class->generatorType) { |
|
630 | 449 | case ClassMetadata::GENERATOR_TYPE_IDENTITY: |
|
631 | 335 | $sequenceName = null; |
|
632 | 335 | $fieldName = $class->identifier ? $class->getSingleIdentifierFieldName() : null; |
|
633 | |||
634 | // Platforms that do not have native IDENTITY support need a sequence to emulate this behaviour. |
||
635 | 335 | if ($this->getTargetPlatform()->usesSequenceEmulatedIdentityColumns()) { |
|
636 | $columnName = $class->getSingleIdentifierColumnName(); |
||
637 | $quoted = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']); |
||
638 | $sequencePrefix = $class->getSequencePrefix($this->getTargetPlatform()); |
||
639 | $sequenceName = $this->getTargetPlatform()->getIdentitySequenceName($sequencePrefix, $columnName); |
||
640 | $definition = [ |
||
641 | 'sequenceName' => $this->getTargetPlatform()->fixSchemaElementName($sequenceName) |
||
642 | ]; |
||
643 | |||
644 | if ($quoted) { |
||
645 | $definition['quoted'] = true; |
||
646 | } |
||
647 | |||
648 | $sequenceName = $this |
||
649 | ->em |
||
650 | ->getConfiguration() |
||
651 | ->getQuoteStrategy() |
||
652 | ->getSequenceName($definition, $class, $this->getTargetPlatform()); |
||
653 | } |
||
654 | |||
655 | 335 | $generator = ($fieldName && $class->fieldMappings[$fieldName]['type'] === 'bigint') |
|
656 | 1 | ? new BigIntegerIdentityGenerator($sequenceName) |
|
657 | 335 | : new IdentityGenerator($sequenceName); |
|
658 | |||
659 | 335 | $class->setIdGenerator($generator); |
|
660 | |||
661 | 335 | break; |
|
662 | |||
663 | 160 | case ClassMetadata::GENERATOR_TYPE_SEQUENCE: |
|
664 | // If there is no sequence definition yet, create a default definition |
||
665 | 6 | $definition = $class->sequenceGeneratorDefinition; |
|
666 | |||
667 | 6 | if ( ! $definition) { |
|
668 | $fieldName = $class->getSingleIdentifierFieldName(); |
||
669 | $sequenceName = $class->getSequenceName($this->getTargetPlatform()); |
||
670 | $quoted = isset($class->fieldMappings[$fieldName]['quoted']) || isset($class->table['quoted']); |
||
671 | |||
672 | $definition = [ |
||
673 | 'sequenceName' => $this->getTargetPlatform()->fixSchemaElementName($sequenceName), |
||
674 | 'allocationSize' => 1, |
||
675 | 'initialValue' => 1, |
||
676 | ]; |
||
677 | |||
678 | if ($quoted) { |
||
679 | $definition['quoted'] = true; |
||
680 | } |
||
681 | |||
682 | $class->setSequenceGeneratorDefinition($definition); |
||
683 | } |
||
684 | |||
685 | 6 | $sequenceGenerator = new \Doctrine\ORM\Id\SequenceGenerator( |
|
686 | 6 | $this->em->getConfiguration()->getQuoteStrategy()->getSequenceName($definition, $class, $this->getTargetPlatform()), |
|
687 | 6 | $definition['allocationSize'] |
|
688 | ); |
||
689 | 6 | $class->setIdGenerator($sequenceGenerator); |
|
690 | 6 | break; |
|
691 | |||
692 | 157 | case ClassMetadata::GENERATOR_TYPE_NONE: |
|
693 | 152 | $class->setIdGenerator(new \Doctrine\ORM\Id\AssignedGenerator()); |
|
694 | 152 | break; |
|
695 | |||
696 | 7 | case ClassMetadata::GENERATOR_TYPE_UUID: |
|
697 | 2 | $class->setIdGenerator(new \Doctrine\ORM\Id\UuidGenerator()); |
|
698 | 2 | break; |
|
699 | |||
700 | 5 | case ClassMetadata::GENERATOR_TYPE_TABLE: |
|
701 | throw new ORMException("TableGenerator not yet implemented."); |
||
702 | break; |
||
703 | |||
704 | 5 | case ClassMetadata::GENERATOR_TYPE_CUSTOM: |
|
705 | 5 | $definition = $class->customGeneratorDefinition; |
|
706 | 5 | if ( ! class_exists($definition['class'])) { |
|
707 | 2 | throw new ORMException("Can't instantiate custom generator : " . |
|
708 | 2 | $definition['class']); |
|
709 | } |
||
710 | 3 | $class->setIdGenerator(new $definition['class']); |
|
711 | 3 | break; |
|
712 | |||
713 | default: |
||
714 | throw new ORMException("Unknown generator type: " . $class->generatorType); |
||
715 | } |
||
716 | 447 | } |
|
717 | |||
718 | /** |
||
719 | * Inherits the ID generator mapping from a parent class. |
||
720 | * |
||
721 | * @param ClassMetadataInfo $class |
||
722 | * @param ClassMetadataInfo $parent |
||
723 | */ |
||
724 | 95 | private function inheritIdGeneratorMapping(ClassMetadataInfo $class, ClassMetadataInfo $parent) |
|
725 | { |
||
726 | 95 | if ($parent->isIdGeneratorSequence()) { |
|
727 | 3 | $class->setSequenceGeneratorDefinition($parent->sequenceGeneratorDefinition); |
|
728 | 92 | } elseif ($parent->isIdGeneratorTable()) { |
|
729 | $class->tableGeneratorDefinition = $parent->tableGeneratorDefinition; |
||
730 | } |
||
731 | |||
732 | 95 | if ($parent->generatorType) { |
|
733 | 95 | $class->setIdGeneratorType($parent->generatorType); |
|
734 | } |
||
735 | |||
736 | 95 | if ($parent->idGenerator) { |
|
737 | 95 | $class->setIdGenerator($parent->idGenerator); |
|
738 | } |
||
739 | 95 | } |
|
740 | |||
741 | /** |
||
742 | * {@inheritDoc} |
||
743 | */ |
||
744 | 2062 | protected function wakeupReflection(ClassMetadataInterface $class, ReflectionService $reflService) |
|
745 | { |
||
746 | /* @var $class ClassMetadata */ |
||
747 | 2062 | $class->wakeupReflection($reflService); |
|
748 | 2062 | } |
|
749 | |||
750 | /** |
||
751 | * {@inheritDoc} |
||
752 | */ |
||
753 | 455 | protected function initializeReflection(ClassMetadataInterface $class, ReflectionService $reflService) |
|
754 | { |
||
755 | /* @var $class ClassMetadata */ |
||
756 | 455 | $class->initializeReflection($reflService); |
|
757 | 455 | } |
|
758 | |||
759 | /** |
||
760 | * {@inheritDoc} |
||
761 | */ |
||
762 | 4 | protected function getFqcnFromAlias($namespaceAlias, $simpleClassName) |
|
763 | { |
||
764 | 4 | return $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName; |
|
765 | } |
||
766 | |||
767 | /** |
||
768 | * {@inheritDoc} |
||
769 | */ |
||
770 | 248 | protected function getDriver() |
|
771 | { |
||
772 | 248 | return $this->driver; |
|
773 | } |
||
774 | |||
775 | /** |
||
776 | * {@inheritDoc} |
||
777 | */ |
||
778 | 446 | protected function isEntity(ClassMetadataInterface $class) |
|
779 | { |
||
780 | 446 | return isset($class->isMappedSuperclass) && $class->isMappedSuperclass === false; |
|
781 | } |
||
782 | |||
783 | /** |
||
784 | * @return Platforms\AbstractPlatform |
||
785 | */ |
||
786 | 341 | private function getTargetPlatform() |
|
787 | { |
||
788 | 341 | if (!$this->targetPlatform) { |
|
789 | 341 | $this->targetPlatform = $this->em->getConnection()->getDatabasePlatform(); |
|
790 | } |
||
791 | |||
792 | 341 | return $this->targetPlatform; |
|
793 | } |
||
794 | } |
||
795 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.