Failed Conditions
Push — master ( 6744b4...2b8acb )
by Marco
60:45 queued 60:36
created

Doctrine/ORM/Mapping/Driver/AnnotationDriver.php (1 issue)

Upgrade to new PHP Analysis Engine

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\Driver;
21
22
use Doctrine\Common\Annotations\AnnotationReader;
23
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
24
use Doctrine\Common\Persistence\Mapping\Driver\AnnotationDriver as AbstractAnnotationDriver;
25
use Doctrine\ORM\Events;
26
use Doctrine\ORM\Mapping;
27
use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
28
use Doctrine\ORM\Mapping\MappingException;
29
30
/**
31
 * The AnnotationDriver reads the mapping metadata from docblock annotations.
32
 *
33
 * @since 2.0
34
 * @author Benjamin Eberlei <[email protected]>
35
 * @author Guilherme Blanco <[email protected]>
36
 * @author Jonathan H. Wage <[email protected]>
37
 * @author Roman Borschel <[email protected]>
38
 */
39
class AnnotationDriver extends AbstractAnnotationDriver
40
{
41
    /**
42
     * {@inheritDoc}
43
     */
44
    protected $entityAnnotationClasses = [
45
        Mapping\Entity::class => 1,
46
        Mapping\MappedSuperclass::class => 2,
47
    ];
48
49
    /**
50
     * {@inheritDoc}
51
     */
52 388
    public function loadMetadataForClass($className, ClassMetadata $metadata)
53
    {
54
        /* @var $metadata \Doctrine\ORM\Mapping\ClassMetadataInfo */
55 388
        $class = $metadata->getReflectionClass();
56
57 388
        if ( ! $class) {
58
            // this happens when running annotation driver in combination with
59
            // static reflection services. This is not the nicest fix
60 1
            $class = new \ReflectionClass($metadata->name);
61
        }
62
63 388
        $classAnnotations = $this->reader->getClassAnnotations($class);
64
65 388
        if ($classAnnotations) {
66 385
            foreach ($classAnnotations as $key => $annot) {
67 385
                if ( ! is_numeric($key)) {
68
                    continue;
69
                }
70
71 385
                $classAnnotations[get_class($annot)] = $annot;
72
            }
73
        }
74
75
        // Evaluate Entity annotation
76 388
        if (isset($classAnnotations[Mapping\Entity::class])) {
77 380
            $entityAnnot = $classAnnotations[Mapping\Entity::class];
78 380
            if ($entityAnnot->repositoryClass !== null) {
79 8
                $metadata->setCustomRepositoryClass($entityAnnot->repositoryClass);
80
            }
81
82 380
            if ($entityAnnot->readOnly) {
83 380
                $metadata->markReadOnly();
84
            }
85 45
        } else if (isset($classAnnotations[Mapping\MappedSuperclass::class])) {
86 32
            $mappedSuperclassAnnot = $classAnnotations[Mapping\MappedSuperclass::class];
87
88 32
            $metadata->setCustomRepositoryClass($mappedSuperclassAnnot->repositoryClass);
89 32
            $metadata->isMappedSuperclass = true;
90 15
        } else if (isset($classAnnotations[Mapping\Embeddable::class])) {
91 12
            $metadata->isEmbeddedClass = true;
92
        } else {
93 3
            throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
94
        }
95
96
        // Evaluate Table annotation
97 385
        if (isset($classAnnotations[Mapping\Table::class])) {
98 201
            $tableAnnot   = $classAnnotations[Mapping\Table::class];
99
            $primaryTable = [
100 201
                'name'   => $tableAnnot->name,
101 201
                'schema' => $tableAnnot->schema
102
            ];
103
104 201
            if ($tableAnnot->indexes !== null) {
105 16
                foreach ($tableAnnot->indexes as $indexAnnot) {
106 16
                    $index = ['columns' => $indexAnnot->columns];
107
108 16
                    if ( ! empty($indexAnnot->flags)) {
109 1
                        $index['flags'] = $indexAnnot->flags;
110
                    }
111
112 16
                    if ( ! empty($indexAnnot->options)) {
113 1
                        $index['options'] = $indexAnnot->options;
114
                    }
115
116 16
                    if ( ! empty($indexAnnot->name)) {
117 15
                        $primaryTable['indexes'][$indexAnnot->name] = $index;
118
                    } else {
119 16
                        $primaryTable['indexes'][] = $index;
120
                    }
121
                }
122
            }
123
124 201
            if ($tableAnnot->uniqueConstraints !== null) {
125 9
                foreach ($tableAnnot->uniqueConstraints as $uniqueConstraintAnnot) {
126 9
                    $uniqueConstraint = ['columns' => $uniqueConstraintAnnot->columns];
127
128 9
                    if ( ! empty($uniqueConstraintAnnot->options)) {
129 3
                        $uniqueConstraint['options'] = $uniqueConstraintAnnot->options;
130
                    }
131
132 9
                    if ( ! empty($uniqueConstraintAnnot->name)) {
133 9
                        $primaryTable['uniqueConstraints'][$uniqueConstraintAnnot->name] = $uniqueConstraint;
134
                    } else {
135 9
                        $primaryTable['uniqueConstraints'][] = $uniqueConstraint;
136
                    }
137
                }
138
            }
139
140 201
            if ($tableAnnot->options) {
141 6
                $primaryTable['options'] = $tableAnnot->options;
142
            }
143
144 201
            $metadata->setPrimaryTable($primaryTable);
145
        }
146
147
        // Evaluate @Cache annotation
148 385
        if (isset($classAnnotations[Mapping\Cache::class])) {
149 16
            $cacheAnnot = $classAnnotations[Mapping\Cache::class];
150
            $cacheMap   = [
151 16
                'region' => $cacheAnnot->region,
152 16
                'usage'  => constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $cacheAnnot->usage),
153
            ];
154
155 16
            $metadata->enableCache($cacheMap);
156
        }
157
158
        // Evaluate NamedNativeQueries annotation
159 385
        if (isset($classAnnotations[Mapping\NamedNativeQueries::class])) {
160 16
            $namedNativeQueriesAnnot = $classAnnotations[Mapping\NamedNativeQueries::class];
161
162 16
            foreach ($namedNativeQueriesAnnot->value as $namedNativeQuery) {
163 16
                $metadata->addNamedNativeQuery(
164
                    [
165 16
                        'name'              => $namedNativeQuery->name,
166 16
                        'query'             => $namedNativeQuery->query,
167 16
                        'resultClass'       => $namedNativeQuery->resultClass,
168 16
                        'resultSetMapping'  => $namedNativeQuery->resultSetMapping,
169
                    ]
170
                );
171
            }
172
        }
173
174
        // Evaluate SqlResultSetMappings annotation
175 385
        if (isset($classAnnotations[Mapping\SqlResultSetMappings::class])) {
176 16
            $sqlResultSetMappingsAnnot = $classAnnotations[Mapping\SqlResultSetMappings::class];
177
178 16
            foreach ($sqlResultSetMappingsAnnot->value as $resultSetMapping) {
179 16
                $entities = [];
180 16
                $columns  = [];
181 16
                foreach ($resultSetMapping->entities as $entityResultAnnot) {
182
                    $entityResult = [
183 16
                        'fields'                => [],
184 16
                        'entityClass'           => $entityResultAnnot->entityClass,
185 16
                        'discriminatorColumn'   => $entityResultAnnot->discriminatorColumn,
186
                    ];
187
188 16
                    foreach ($entityResultAnnot->fields as $fieldResultAnnot) {
189 16
                        $entityResult['fields'][] = [
190 16
                            'name'      => $fieldResultAnnot->name,
191 16
                            'column'    => $fieldResultAnnot->column
192
                        ];
193
                    }
194
195 16
                    $entities[] = $entityResult;
196
                }
197
198 16
                foreach ($resultSetMapping->columns as $columnResultAnnot) {
199 10
                    $columns[] = [
200 10
                        'name' => $columnResultAnnot->name,
201
                    ];
202
                }
203
204 16
                $metadata->addSqlResultSetMapping(
205
                    [
206 16
                        'name'          => $resultSetMapping->name,
207 16
                        'entities'      => $entities,
208 16
                        'columns'       => $columns
209
                    ]
210
                );
211
            }
212
        }
213
214
        // Evaluate NamedQueries annotation
215 385
        if (isset($classAnnotations[Mapping\NamedQueries::class])) {
216 11
            $namedQueriesAnnot = $classAnnotations[Mapping\NamedQueries::class];
217
218 11
            if ( ! is_array($namedQueriesAnnot->value)) {
219
                throw new \UnexpectedValueException("@NamedQueries should contain an array of @NamedQuery annotations.");
220
            }
221
222 11
            foreach ($namedQueriesAnnot->value as $namedQuery) {
223 11
                if ( ! ($namedQuery instanceof Mapping\NamedQuery)) {
224
                    throw new \UnexpectedValueException("@NamedQueries should contain an array of @NamedQuery annotations.");
225
                }
226 11
                $metadata->addNamedQuery(
227
                    [
228 11
                        'name'  => $namedQuery->name,
229 11
                        'query' => $namedQuery->query
230
                    ]
231
                );
232
            }
233
        }
234
235
        // Evaluate InheritanceType annotation
236 385
        if (isset($classAnnotations[Mapping\InheritanceType::class])) {
237 74
            $inheritanceTypeAnnot = $classAnnotations[Mapping\InheritanceType::class];
238
239 74
            $metadata->setInheritanceType(
240 74
                constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceTypeAnnot->value)
241
            );
242
243 74
            if ($metadata->inheritanceType != Mapping\ClassMetadata::INHERITANCE_TYPE_NONE) {
244
                // Evaluate DiscriminatorColumn annotation
245 74
                if (isset($classAnnotations[Mapping\DiscriminatorColumn::class])) {
246 56
                    $discrColumnAnnot = $classAnnotations[Mapping\DiscriminatorColumn::class];
247
248 56
                    $metadata->setDiscriminatorColumn(
249
                        [
250 56
                            'name'             => $discrColumnAnnot->name,
251 56
                            'type'             => $discrColumnAnnot->type ?: 'string',
252 56
                            'length'           => $discrColumnAnnot->length ?: 255,
253 56
                            'columnDefinition' => $discrColumnAnnot->columnDefinition,
254
                        ]
255
                    );
256
                } else {
257 21
                    $metadata->setDiscriminatorColumn(['name' => 'dtype', 'type' => 'string', 'length' => 255]);
258
                }
259
260
                // Evaluate DiscriminatorMap annotation
261 74
                if (isset($classAnnotations[Mapping\DiscriminatorMap::class])) {
262 73
                    $discrMapAnnot = $classAnnotations[Mapping\DiscriminatorMap::class];
263 73
                    $metadata->setDiscriminatorMap($discrMapAnnot->value);
264
                }
265
            }
266
        }
267
268
269
        // Evaluate DoctrineChangeTrackingPolicy annotation
270 385
        if (isset($classAnnotations[Mapping\ChangeTrackingPolicy::class])) {
271 5
            $changeTrackingAnnot = $classAnnotations[Mapping\ChangeTrackingPolicy::class];
272 5
            $metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_' . $changeTrackingAnnot->value));
273
        }
274
275
        // Evaluate annotations on properties/fields
276
        /* @var $property \ReflectionProperty */
277 385
        foreach ($class->getProperties() as $property) {
278 383
            if ($metadata->isMappedSuperclass && ! $property->isPrivate()
279
                ||
280 383
                $metadata->isInheritedField($property->name)
281
                ||
282 383
                $metadata->isInheritedAssociation($property->name)
283
                ||
284 383
                $metadata->isInheritedEmbeddedClass($property->name)) {
285 77
                continue;
286
            }
287
288 383
            $mapping = [];
289 383
            $mapping['fieldName'] = $property->getName();
290
291
            // Evaluate @Cache annotation
292 383
            if (($cacheAnnot = $this->reader->getPropertyAnnotation($property, Mapping\Cache::class)) !== null) {
293 13
                $mapping['cache'] = $metadata->getAssociationCacheDefaults(
294 13
                    $mapping['fieldName'],
295
                    [
296 13
                        'usage'  => constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $cacheAnnot->usage),
297 13
                        'region' => $cacheAnnot->region,
298
                    ]
299
                );
300
            }
301
            // Check for JoinColumn/JoinColumns annotations
302 382
            $joinColumns = [];
303
304 382
            if ($joinColumnAnnot = $this->reader->getPropertyAnnotation($property, Mapping\JoinColumn::class)) {
305 144
                $joinColumns[] = $this->joinColumnToArray($joinColumnAnnot);
306 381
            } else if ($joinColumnsAnnot = $this->reader->getPropertyAnnotation($property, Mapping\JoinColumns::class)) {
307 19
                foreach ($joinColumnsAnnot->value as $joinColumn) {
308 19
                    $joinColumns[] = $this->joinColumnToArray($joinColumn);
309
                }
310
            }
311
312
            // Field can only be annotated with one of:
313
            // @Column, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany
314 382
            if ($columnAnnot = $this->reader->getPropertyAnnotation($property, Mapping\Column::class)) {
315 374
                if ($columnAnnot->type == null) {
316
                    throw MappingException::propertyTypeIsRequired($className, $property->getName());
317
                }
318
319 374
                $mapping = $this->columnToArray($property->getName(), $columnAnnot);
320
321 374
                if ($idAnnot = $this->reader->getPropertyAnnotation($property, Mapping\Id::class)) {
322 367
                    $mapping['id'] = true;
323
                }
324
325 374
                if ($generatedValueAnnot = $this->reader->getPropertyAnnotation($property, Mapping\GeneratedValue::class)) {
326 313
                    $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' . $generatedValueAnnot->strategy));
327
                }
328
329 374
                if ($this->reader->getPropertyAnnotation($property, Mapping\Version::class)) {
330 16
                    $metadata->setVersionMapping($mapping);
331
                }
332
333 374
                $metadata->mapField($mapping);
334
335
                // Check for SequenceGenerator/TableGenerator definition
336 374
                if ($seqGeneratorAnnot = $this->reader->getPropertyAnnotation($property, Mapping\SequenceGenerator::class)) {
337 9
                    $metadata->setSequenceGeneratorDefinition(
338
                        [
339 9
                            'sequenceName' => $seqGeneratorAnnot->sequenceName,
340 9
                            'allocationSize' => $seqGeneratorAnnot->allocationSize,
341 9
                            'initialValue' => $seqGeneratorAnnot->initialValue
342
                        ]
343
                    );
344 371
                } else if ($this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\TableGenerator')) {
345
                    throw MappingException::tableIdGeneratorNotImplemented($className);
346 371
                } else if ($customGeneratorAnnot = $this->reader->getPropertyAnnotation($property, Mapping\CustomIdGenerator::class)) {
347 3
                    $metadata->setCustomGeneratorDefinition(
348
                        [
349 374
                            'class' => $customGeneratorAnnot->class
350
                        ]
351
                    );
352
                }
353 269
            } else if ($oneToOneAnnot = $this->reader->getPropertyAnnotation($property, Mapping\OneToOne::class)) {
354 114
                if ($idAnnot = $this->reader->getPropertyAnnotation($property, Mapping\Id::class)) {
355 9
                    $mapping['id'] = true;
356
                }
357
358 114
                $mapping['targetEntity'] = $oneToOneAnnot->targetEntity;
359 114
                $mapping['joinColumns'] = $joinColumns;
360 114
                $mapping['mappedBy'] = $oneToOneAnnot->mappedBy;
361 114
                $mapping['inversedBy'] = $oneToOneAnnot->inversedBy;
362 114
                $mapping['cascade'] = $oneToOneAnnot->cascade;
363 114
                $mapping['orphanRemoval'] = $oneToOneAnnot->orphanRemoval;
364 114
                $mapping['fetch'] = $this->getFetchMode($className, $oneToOneAnnot->fetch);
365 114
                $metadata->mapOneToOne($mapping);
366 218
            } else if ($oneToManyAnnot = $this->reader->getPropertyAnnotation($property, Mapping\OneToMany::class)) {
367 110
                $mapping['mappedBy'] = $oneToManyAnnot->mappedBy;
368 110
                $mapping['targetEntity'] = $oneToManyAnnot->targetEntity;
369 110
                $mapping['cascade'] = $oneToManyAnnot->cascade;
370 110
                $mapping['indexBy'] = $oneToManyAnnot->indexBy;
371 110
                $mapping['orphanRemoval'] = $oneToManyAnnot->orphanRemoval;
372 110
                $mapping['fetch'] = $this->getFetchMode($className, $oneToManyAnnot->fetch);
373
374 110
                if ($orderByAnnot = $this->reader->getPropertyAnnotation($property, Mapping\OrderBy::class)) {
375 16
                    $mapping['orderBy'] = $orderByAnnot->value;
376
                }
377
378 110
                $metadata->mapOneToMany($mapping);
379 215
            } else if ($manyToOneAnnot = $this->reader->getPropertyAnnotation($property, Mapping\ManyToOne::class)) {
380 138
                if ($idAnnot = $this->reader->getPropertyAnnotation($property, Mapping\Id::class)) {
381 31
                    $mapping['id'] = true;
382
                }
383
384 138
                $mapping['joinColumns'] = $joinColumns;
385 138
                $mapping['cascade'] = $manyToOneAnnot->cascade;
386 138
                $mapping['inversedBy'] = $manyToOneAnnot->inversedBy;
387 138
                $mapping['targetEntity'] = $manyToOneAnnot->targetEntity;
388 138
                $mapping['fetch'] = $this->getFetchMode($className, $manyToOneAnnot->fetch);
389 138
                $metadata->mapManyToOne($mapping);
390 122
            } else if ($manyToManyAnnot = $this->reader->getPropertyAnnotation($property, Mapping\ManyToMany::class)) {
391 92
                $joinTable = [];
392
393 92
                if ($joinTableAnnot = $this->reader->getPropertyAnnotation($property, Mapping\JoinTable::class)) {
394
                    $joinTable = [
395 72
                        'name' => $joinTableAnnot->name,
396 72
                        'schema' => $joinTableAnnot->schema
397
                    ];
398
399 72
                    foreach ($joinTableAnnot->joinColumns as $joinColumn) {
400 71
                        $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumn);
401
                    }
402
403 72
                    foreach ($joinTableAnnot->inverseJoinColumns as $joinColumn) {
404 71
                        $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumn);
405
                    }
406
                }
407
408 92
                $mapping['joinTable'] = $joinTable;
409 92
                $mapping['targetEntity'] = $manyToManyAnnot->targetEntity;
410 92
                $mapping['mappedBy'] = $manyToManyAnnot->mappedBy;
411 92
                $mapping['inversedBy'] = $manyToManyAnnot->inversedBy;
412 92
                $mapping['cascade'] = $manyToManyAnnot->cascade;
413 92
                $mapping['indexBy'] = $manyToManyAnnot->indexBy;
414 92
                $mapping['orphanRemoval'] = $manyToManyAnnot->orphanRemoval;
415 92
                $mapping['fetch'] = $this->getFetchMode($className, $manyToManyAnnot->fetch);
416
417 92
                if ($orderByAnnot = $this->reader->getPropertyAnnotation($property, Mapping\OrderBy::class)) {
418 3
                    $mapping['orderBy'] = $orderByAnnot->value;
419
                }
420
421 92
                $metadata->mapManyToMany($mapping);
422 50
            } else if ($embeddedAnnot = $this->reader->getPropertyAnnotation($property, Mapping\Embedded::class)) {
423 13
                $mapping['class'] = $embeddedAnnot->class;
424 13
                $mapping['columnPrefix'] = $embeddedAnnot->columnPrefix;
425
426 381
                $metadata->mapEmbedded($mapping);
427
            }
428
        }
429
430
        // Evaluate AssociationOverrides annotation
431 383
        if (isset($classAnnotations[Mapping\AssociationOverrides::class])) {
432 5
            $associationOverridesAnnot = $classAnnotations[Mapping\AssociationOverrides::class];
433
434 5
            foreach ($associationOverridesAnnot->value as $associationOverride) {
435 5
                $override   = [];
436 5
                $fieldName  = $associationOverride->name;
437
438
                // Check for JoinColumn/JoinColumns annotations
439 5
                if ($associationOverride->joinColumns) {
440 3
                    $joinColumns = [];
441
442 3
                    foreach ($associationOverride->joinColumns as $joinColumn) {
443 3
                        $joinColumns[] = $this->joinColumnToArray($joinColumn);
444
                    }
445
446 3
                    $override['joinColumns'] = $joinColumns;
447
                }
448
449
                // Check for JoinTable annotations
450 5
                if ($associationOverride->joinTable) {
451 2
                    $joinTableAnnot = $associationOverride->joinTable;
452
                    $joinTable      = [
453 2
                        'name'      => $joinTableAnnot->name,
454 2
                        'schema'    => $joinTableAnnot->schema
455
                    ];
456
457 2
                    foreach ($joinTableAnnot->joinColumns as $joinColumn) {
458 2
                        $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumn);
459
                    }
460
461 2
                    foreach ($joinTableAnnot->inverseJoinColumns as $joinColumn) {
462 2
                        $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumn);
463
                    }
464
465 2
                    $override['joinTable'] = $joinTable;
466
                }
467
468
                // Check for inversedBy
469 5
                if ($associationOverride->inversedBy) {
470 1
                    $override['inversedBy'] = $associationOverride->inversedBy;
471
                }
472
473
                // Check for `fetch`
474 5
                if ($associationOverride->fetch) {
475 1
                    $override['fetch'] = constant(Mapping\ClassMetadata::class . '::FETCH_' . $associationOverride->fetch);
476
                }
477
478 5
                $metadata->setAssociationOverride($fieldName, $override);
479
            }
480
        }
481
482
        // Evaluate AttributeOverrides annotation
483 383
        if (isset($classAnnotations[Mapping\AttributeOverrides::class])) {
484 3
            $attributeOverridesAnnot = $classAnnotations[Mapping\AttributeOverrides::class];
485
486 3
            foreach ($attributeOverridesAnnot->value as $attributeOverrideAnnot) {
487 3
                $attributeOverride = $this->columnToArray($attributeOverrideAnnot->name, $attributeOverrideAnnot->column);
488
489 3
                $metadata->setAttributeOverride($attributeOverrideAnnot->name, $attributeOverride);
490
            }
491
        }
492
493
        // Evaluate EntityListeners annotation
494 383
        if (isset($classAnnotations[Mapping\EntityListeners::class])) {
495 10
            $entityListenersAnnot = $classAnnotations[Mapping\EntityListeners::class];
496
497 10
            foreach ($entityListenersAnnot->value as $item) {
498 10
                $listenerClassName = $metadata->fullyQualifiedClassName($item);
499
500 10
                if ( ! class_exists($listenerClassName)) {
501
                    throw MappingException::entityListenerClassNotFound($listenerClassName, $className);
502
                }
503
504 10
                $hasMapping     = false;
505 10
                $listenerClass  = new \ReflectionClass($listenerClassName);
506
507
                /* @var $method \ReflectionMethod */
508 10
                foreach ($listenerClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
509
                    // find method callbacks.
510 10
                    $callbacks  = $this->getMethodCallbacks($method);
511 10
                    $hasMapping = $hasMapping ?: ( ! empty($callbacks));
512
513 10
                    foreach ($callbacks as $value) {
514 10
                        $metadata->addEntityListener($value[1], $listenerClassName, $value[0]);
515
                    }
516
                }
517
518
                // Evaluate the listener using naming convention.
519 10
                if ( ! $hasMapping ) {
520 10
                    EntityListenerBuilder::bindEntityListener($metadata, $listenerClassName);
0 ignored issues
show
$metadata of type object<Doctrine\ORM\Mapping\ClassMetadataInfo> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a child class of the class Doctrine\ORM\Mapping\ClassMetadataInfo 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...
521
                }
522
            }
523
        }
524
525
        // Evaluate @HasLifecycleCallbacks annotation
526 383
        if (isset($classAnnotations[Mapping\HasLifecycleCallbacks::class])) {
527
            /* @var $method \ReflectionMethod */
528 19
            foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
529 18
                foreach ($this->getMethodCallbacks($method) as $value) {
530 18
                    $metadata->addLifecycleCallback($value[0], $value[1]);
531
                }
532
            }
533
        }
534 383
    }
535
536
    /**
537
     * Attempts to resolve the fetch mode.
538
     *
539
     * @param string $className The class name.
540
     * @param string $fetchMode The fetch mode.
541
     *
542
     * @return integer The fetch mode as defined in ClassMetadata.
543
     *
544
     * @throws MappingException If the fetch mode is not valid.
545
     */
546 255
    private function getFetchMode($className, $fetchMode)
547
    {
548 255
        if ( ! defined('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $fetchMode)) {
549
            throw MappingException::invalidFetchMode($className, $fetchMode);
550
        }
551
552 255
        return constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $fetchMode);
553
    }
554
555
    /**
556
     * Parses the given method.
557
     *
558
     * @param \ReflectionMethod $method
559
     *
560
     * @return array
561
     */
562 28
    private function getMethodCallbacks(\ReflectionMethod $method)
563
    {
564 28
        $callbacks   = [];
565 28
        $annotations = $this->reader->getMethodAnnotations($method);
566
567 28
        foreach ($annotations as $annot) {
568 22
            if ($annot instanceof Mapping\PrePersist) {
569 15
                $callbacks[] = [$method->name, Events::prePersist];
570
            }
571
572 22
            if ($annot instanceof Mapping\PostPersist) {
573 11
                $callbacks[] = [$method->name, Events::postPersist];
574
            }
575
576 22
            if ($annot instanceof Mapping\PreUpdate) {
577 11
                $callbacks[] = [$method->name, Events::preUpdate];
578
            }
579
580 22
            if ($annot instanceof Mapping\PostUpdate) {
581 7
                $callbacks[] = [$method->name, Events::postUpdate];
582
            }
583
584 22
            if ($annot instanceof Mapping\PreRemove) {
585 8
                $callbacks[] = [$method->name, Events::preRemove];
586
            }
587
588 22
            if ($annot instanceof Mapping\PostRemove) {
589 6
                $callbacks[] = [$method->name, Events::postRemove];
590
            }
591
592 22
            if ($annot instanceof Mapping\PostLoad) {
593 11
                $callbacks[] = [$method->name, Events::postLoad];
594
            }
595
596 22
            if ($annot instanceof Mapping\PreFlush) {
597 22
                $callbacks[] = [$method->name, Events::preFlush];
598
            }
599
        }
600
601 28
        return $callbacks;
602
    }
603
604
    /**
605
     * Parse the given JoinColumn as array
606
     *
607
     * @param Mapping\JoinColumn $joinColumn
608
     * @return array
609
     */
610 182
    private function joinColumnToArray(Mapping\JoinColumn $joinColumn)
611
    {
612
        return [
613 182
            'name' => $joinColumn->name,
614 182
            'unique' => $joinColumn->unique,
615 182
            'nullable' => $joinColumn->nullable,
616 182
            'onDelete' => $joinColumn->onDelete,
617 182
            'columnDefinition' => $joinColumn->columnDefinition,
618 182
            'referencedColumnName' => $joinColumn->referencedColumnName,
619
        ];
620
    }
621
622
    /**
623
     * Parse the given Column as array
624
     *
625
     * @param string $fieldName
626
     * @param Mapping\Column $column
627
     *
628
     * @return array
629
     */
630 374
    private function columnToArray($fieldName, Mapping\Column $column)
631
    {
632
        $mapping = [
633 374
            'fieldName' => $fieldName,
634 374
            'type'      => $column->type,
635 374
            'scale'     => $column->scale,
636 374
            'length'    => $column->length,
637 374
            'unique'    => $column->unique,
638 374
            'nullable'  => $column->nullable,
639 374
            'precision' => $column->precision
640
        ];
641
642 374
        if ($column->options) {
643 8
            $mapping['options'] = $column->options;
644
        }
645
646 374
        if (isset($column->name)) {
647 84
            $mapping['columnName'] = $column->name;
648
        }
649
650 374
        if (isset($column->columnDefinition)) {
651 6
            $mapping['columnDefinition'] = $column->columnDefinition;
652
        }
653
654 374
        return $mapping;
655
    }
656
657
    /**
658
     * Factory method for the Annotation Driver.
659
     *
660
     * @param array|string          $paths
661
     * @param AnnotationReader|null $reader
662
     *
663
     * @return AnnotationDriver
664
     */
665
    static public function create($paths = [], AnnotationReader $reader = null)
666
    {
667
        if ($reader == null) {
668
            $reader = new AnnotationReader();
669
        }
670
671
        return new self($reader, $paths);
672
    }
673
}
674