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

AnnotationDriver::joinColumnToArray()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1
Metric Value
dl 0
loc 11
ccs 7
cts 7
cp 1
rs 9.4286
cc 1
eloc 8
nc 1
nop 1
crap 1
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ORM\Mapping\Driver;
21
22
use Doctrine\Common\Annotations\AnnotationReader;
23
use Doctrine\ORM\Mapping\MappingException;
24
use Doctrine\ORM\Mapping\JoinColumn;
25
use Doctrine\ORM\Mapping\Column;
26
use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
27
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
28
use Doctrine\Common\Persistence\Mapping\Driver\AnnotationDriver as AbstractAnnotationDriver;
29
use Doctrine\ORM\Events;
30
31
/**
32
 * The AnnotationDriver reads the mapping metadata from docblock annotations.
33
 *
34
 * @since 2.0
35
 * @author Benjamin Eberlei <[email protected]>
36
 * @author Guilherme Blanco <[email protected]>
37
 * @author Jonathan H. Wage <[email protected]>
38
 * @author Roman Borschel <[email protected]>
39
 */
40
class AnnotationDriver extends AbstractAnnotationDriver
41
{
42
    /**
43
     * {@inheritDoc}
44
     */
45
    protected $entityAnnotationClasses = array(
46
        'Doctrine\ORM\Mapping\Entity' => 1,
47
        'Doctrine\ORM\Mapping\MappedSuperclass' => 2,
48
    );
49
50
    /**
51
     * {@inheritDoc}
52
     */
53 361
    public function loadMetadataForClass($className, ClassMetadata $metadata)
54
    {
55
        /* @var $metadata \Doctrine\ORM\Mapping\ClassMetadataInfo */
56 361
        $class = $metadata->getReflectionClass();
57
58 361
        if ( ! $class) {
59
            // this happens when running annotation driver in combination with
60
            // static reflection services. This is not the nicest fix
61 1
            $class = new \ReflectionClass($metadata->name);
62
        }
63
64 361
        $classAnnotations = $this->reader->getClassAnnotations($class);
65
66 361
        if ($classAnnotations) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $classAnnotations 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...
67 358
            foreach ($classAnnotations as $key => $annot) {
68 358
                if ( ! is_numeric($key)) {
69
                    continue;
70
                }
71
72 358
                $classAnnotations[get_class($annot)] = $annot;
73
            }
74
        }
75
76
        // Evaluate Entity annotation
77 361
        if (isset($classAnnotations['Doctrine\ORM\Mapping\Entity'])) {
78 320
            $entityAnnot = $classAnnotations['Doctrine\ORM\Mapping\Entity'];
79 320
            if ($entityAnnot->repositoryClass !== null) {
80 7
                $metadata->setCustomRepositoryClass($entityAnnot->repositoryClass);
81
            }
82
83 320
            if ($entityAnnot->persisterClass !== null) {
84
                $metadata->setCustomPersisterClass($entityAnnot->persisterClass);
85
            }
86
87 320
            if ($entityAnnot->readOnly) {
88 320
                $metadata->markReadOnly();
89
            }
90 56
        } else if (isset($classAnnotations['Doctrine\ORM\Mapping\MappedSuperclass'])) {
91 47
            $mappedSuperclassAnnot = $classAnnotations['Doctrine\ORM\Mapping\MappedSuperclass'];
92
93 47
            $metadata->setCustomRepositoryClass($mappedSuperclassAnnot->repositoryClass);
94 47
            $metadata->setCustomPersisterClass($mappedSuperclassAnnot->persisterClass);
95
            $metadata->isMappedSuperclass = true;
96 13
        } else if (isset($classAnnotations['Doctrine\ORM\Mapping\Embeddable'])) {
97 10
            $metadata->isEmbeddedClass = true;
98
        } else {
99 3
            throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
100
        }
101
102
        // Evaluate Table annotation
103 322
        if (isset($classAnnotations['Doctrine\ORM\Mapping\Table'])) {
104 178
            $tableAnnot   = $classAnnotations['Doctrine\ORM\Mapping\Table'];
105
            $primaryTable = array(
106 178
                'name'   => $tableAnnot->name,
107 178
                'schema' => $tableAnnot->schema
108
            );
109
110 178
            if ($tableAnnot->indexes !== null) {
111 12
                foreach ($tableAnnot->indexes as $indexAnnot) {
112 12
                    $index = array('columns' => $indexAnnot->columns);
113
114 12
                    if ( ! empty($indexAnnot->flags)) {
115 1
                        $index['flags'] = $indexAnnot->flags;
116
                    }
117
118 12
                    if ( ! empty($indexAnnot->options)) {
119 1
                        $index['options'] = $indexAnnot->options;
120
                    }
121
122 12
                    if ( ! empty($indexAnnot->name)) {
123 11
                        $primaryTable['indexes'][$indexAnnot->name] = $index;
124
                    } else {
125 12
                        $primaryTable['indexes'][] = $index;
126
                    }
127
                }
128
            }
129
130 178
            if ($tableAnnot->uniqueConstraints !== null) {
131 7
                foreach ($tableAnnot->uniqueConstraints as $uniqueConstraintAnnot) {
132 7
                    $uniqueConstraint = array('columns' => $uniqueConstraintAnnot->columns);
133
134 7
                    if ( ! empty($uniqueConstraintAnnot->options)) {
135 2
                        $uniqueConstraint['options'] = $uniqueConstraintAnnot->options;
136
                    }
137
138 7
                    if ( ! empty($uniqueConstraintAnnot->name)) {
139 7
                        $primaryTable['uniqueConstraints'][$uniqueConstraintAnnot->name] = $uniqueConstraint;
140
                    } else {
141 7
                        $primaryTable['uniqueConstraints'][] = $uniqueConstraint;
142
                    }
143
                }
144
            }
145
146 178
            if ($tableAnnot->options) {
147 5
                $primaryTable['options'] = $tableAnnot->options;
148
            }
149
150 178
            $metadata->setPrimaryTable($primaryTable);
151
        }
152
153
        // Evaluate @Cache annotation
154 322
        if (isset($classAnnotations['Doctrine\ORM\Mapping\Cache'])) {
155 13
            $cacheAnnot = $classAnnotations['Doctrine\ORM\Mapping\Cache'];
156
            $cacheMap   = array(
157 13
                'region' => $cacheAnnot->region,
158 13
                'usage'  => constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $cacheAnnot->usage),
159
            );
160
161 13
            $metadata->enableCache($cacheMap);
162
        }
163
164
        // Evaluate NamedNativeQueries annotation
165 322
        if (isset($classAnnotations['Doctrine\ORM\Mapping\NamedNativeQueries'])) {
166 14
            $namedNativeQueriesAnnot = $classAnnotations['Doctrine\ORM\Mapping\NamedNativeQueries'];
167
168 14
            foreach ($namedNativeQueriesAnnot->value as $namedNativeQuery) {
169 14
                $metadata->addNamedNativeQuery(array(
170 14
                    'name'              => $namedNativeQuery->name,
171 14
                    'query'             => $namedNativeQuery->query,
172 14
                    'resultClass'       => $namedNativeQuery->resultClass,
173 14
                    'resultSetMapping'  => $namedNativeQuery->resultSetMapping,
174
                ));
175
            }
176
        }
177
178
        // Evaluate SqlResultSetMappings annotation
179 322
        if (isset($classAnnotations['Doctrine\ORM\Mapping\SqlResultSetMappings'])) {
180 14
            $sqlResultSetMappingsAnnot = $classAnnotations['Doctrine\ORM\Mapping\SqlResultSetMappings'];
181
182 14
            foreach ($sqlResultSetMappingsAnnot->value as $resultSetMapping) {
183 14
                $entities = array();
184 14
                $columns  = array();
185 14
                foreach ($resultSetMapping->entities as $entityResultAnnot) {
186
                    $entityResult = array(
187 14
                        'fields'                => array(),
188 14
                        'entityClass'           => $entityResultAnnot->entityClass,
189 14
                        'discriminatorColumn'   => $entityResultAnnot->discriminatorColumn,
190
                    );
191
192 14
                    foreach ($entityResultAnnot->fields as $fieldResultAnnot) {
193 14
                        $entityResult['fields'][] = array(
194 14
                            'name'      => $fieldResultAnnot->name,
195 14
                            'column'    => $fieldResultAnnot->column
196
                        );
197
                    }
198
199 14
                    $entities[] = $entityResult;
200
                }
201
202 14
                foreach ($resultSetMapping->columns as $columnResultAnnot) {
203 9
                    $columns[] = array(
204 9
                        'name' => $columnResultAnnot->name,
205
                    );
206
                }
207
208 14
                $metadata->addSqlResultSetMapping(array(
209 14
                    'name'          => $resultSetMapping->name,
210 14
                    'entities'      => $entities,
211 14
                    'columns'       => $columns
212
                ));
213
            }
214
        }
215
216
        // Evaluate NamedQueries annotation
217 322
        if (isset($classAnnotations['Doctrine\ORM\Mapping\NamedQueries'])) {
218 8
            $namedQueriesAnnot = $classAnnotations['Doctrine\ORM\Mapping\NamedQueries'];
219
220 8
            if ( ! is_array($namedQueriesAnnot->value)) {
221
                throw new \UnexpectedValueException("@NamedQueries should contain an array of @NamedQuery annotations.");
222
            }
223
224 8
            foreach ($namedQueriesAnnot->value as $namedQuery) {
225 8
                if ( ! ($namedQuery instanceof \Doctrine\ORM\Mapping\NamedQuery)) {
226
                    throw new \UnexpectedValueException("@NamedQueries should contain an array of @NamedQuery annotations.");
227
                }
228 8
                $metadata->addNamedQuery(array(
229 8
                    'name'  => $namedQuery->name,
230 8
                    'query' => $namedQuery->query
231
                ));
232
            }
233
        }
234
235
        // Evaluate InheritanceType annotation
236 322
        if (isset($classAnnotations['Doctrine\ORM\Mapping\InheritanceType'])) {
237 64
            $inheritanceTypeAnnot = $classAnnotations['Doctrine\ORM\Mapping\InheritanceType'];
238
239 64
            $metadata->setInheritanceType(
240 64
                constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceTypeAnnot->value)
241
            );
242
243 64
            if ($metadata->inheritanceType != \Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_NONE) {
244
                // Evaluate DiscriminatorColumn annotation
245 64
                if (isset($classAnnotations['Doctrine\ORM\Mapping\DiscriminatorColumn'])) {
246 48
                    $discrColumnAnnot = $classAnnotations['Doctrine\ORM\Mapping\DiscriminatorColumn'];
247
248 48
                    $metadata->setDiscriminatorColumn(array(
249 48
                        'name'             => $discrColumnAnnot->name,
250 48
                        'type'             => $discrColumnAnnot->type ?: 'string',
251 48
                        'length'           => $discrColumnAnnot->length ?: 255,
252 48
                        'columnDefinition' => $discrColumnAnnot->columnDefinition,
253
                    ));
254
                } else {
255 19
                    $metadata->setDiscriminatorColumn(array('name' => 'dtype', 'type' => 'string', 'length' => 255));
256
                }
257
258
                // Evaluate DiscriminatorMap annotation
259 64
                if (isset($classAnnotations['Doctrine\ORM\Mapping\DiscriminatorMap'])) {
260 63
                    $discrMapAnnot = $classAnnotations['Doctrine\ORM\Mapping\DiscriminatorMap'];
261 63
                    $metadata->setDiscriminatorMap($discrMapAnnot->value);
262
                }
263
            }
264
        }
265
266
267
        // Evaluate DoctrineChangeTrackingPolicy annotation
268 322
        if (isset($classAnnotations['Doctrine\ORM\Mapping\ChangeTrackingPolicy'])) {
269 5
            $changeTrackingAnnot = $classAnnotations['Doctrine\ORM\Mapping\ChangeTrackingPolicy'];
270 5
            $metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_' . $changeTrackingAnnot->value));
271
        }
272
273
        // Evaluate annotations on properties/fields
274
        /* @var $property \ReflectionProperty */
275 322
        foreach ($class->getProperties() as $property) {
276 322
            if ($metadata->isMappedSuperclass && ! $property->isPrivate()
277
                ||
278 322
                $metadata->isInheritedField($property->name)
279
                ||
280 322
                $metadata->isInheritedAssociation($property->name)
281
                ||
282 322
                $metadata->isInheritedEmbeddedClass($property->name)) {
283 50
                continue;
284
            }
285
286 322
            $mapping = array();
287 322
            $mapping['fieldName'] = $property->getName();
288
289
            // Evaluate @Cache annotation
290 322
            if (($cacheAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Cache')) !== null) {
291 11
                $mapping['cache'] = $metadata->getAssociationCacheDefaults($mapping['fieldName'], array(
292 11
                        'usage'         => constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $cacheAnnot->usage),
293 11
                        'region'        => $cacheAnnot->region,
294
                ));
295
            }
296
            // Check for JoinColumn/JoinColumns annotations
297 321
            $joinColumns = array();
298
299 321
            if ($joinColumnAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinColumn')) {
300 131
                $joinColumns[] = $this->joinColumnToArray($joinColumnAnnot);
301 320
            } else if ($joinColumnsAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinColumns')) {
302 18
                foreach ($joinColumnsAnnot->value as $joinColumn) {
303 18
                    $joinColumns[] = $this->joinColumnToArray($joinColumn);
304
                }
305
            }
306
307
            // Field can only be annotated with one of:
308
            // @Column, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany
309 321
            if ($columnAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Column')) {
310 314
                if ($columnAnnot->type == null) {
311
                    throw MappingException::propertyTypeIsRequired($className, $property->getName());
312
                }
313
314 314
                $mapping = $this->columnToArray($property->getName(), $columnAnnot);
315
316 314
                if ($idAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) {
0 ignored issues
show
Unused Code introduced by
$idAnnot is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
317 308
                    $mapping['id'] = true;
318
                }
319
320 314
                if ($generatedValueAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\GeneratedValue')) {
321 272
                    $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_' . $generatedValueAnnot->strategy));
322
                }
323
324 314
                if ($this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Version')) {
325 13
                    $metadata->setVersionMapping($mapping);
326
                }
327
328 314
                $metadata->mapField($mapping);
329
330
                // Check for SequenceGenerator/TableGenerator definition
331 314
                if ($seqGeneratorAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\SequenceGenerator')) {
332 5
                    $metadata->setSequenceGeneratorDefinition(array(
333 5
                        'sequenceName' => $seqGeneratorAnnot->sequenceName,
334 5
                        'allocationSize' => $seqGeneratorAnnot->allocationSize,
335 5
                        'initialValue' => $seqGeneratorAnnot->initialValue
336
                    ));
337 312
                } else if ($this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\TableGenerator')) {
338
                    throw MappingException::tableIdGeneratorNotImplemented($className);
339 312
                } else if ($customGeneratorAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\CustomIdGenerator')) {
340 2
                    $metadata->setCustomGeneratorDefinition(array(
341 314
                        'class' => $customGeneratorAnnot->class
342
                    ));
343
                }
344 241
            } else if ($oneToOneAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OneToOne')) {
345 103
                if ($idAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) {
0 ignored issues
show
Unused Code introduced by
$idAnnot is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
346 9
                    $mapping['id'] = true;
347
                }
348
349 103
                $mapping['targetEntity'] = $oneToOneAnnot->targetEntity;
350 103
                $mapping['joinColumns'] = $joinColumns;
351 103
                $mapping['mappedBy'] = $oneToOneAnnot->mappedBy;
352 103
                $mapping['inversedBy'] = $oneToOneAnnot->inversedBy;
353 103
                $mapping['cascade'] = $oneToOneAnnot->cascade;
354 103
                $mapping['orphanRemoval'] = $oneToOneAnnot->orphanRemoval;
355 103
                $mapping['fetch'] = $this->getFetchMode($className, $oneToOneAnnot->fetch);
356 103
                $metadata->mapOneToOne($mapping);
357 192
            } else if ($oneToManyAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OneToMany')) {
358 101
                $mapping['mappedBy'] = $oneToManyAnnot->mappedBy;
359 101
                $mapping['targetEntity'] = $oneToManyAnnot->targetEntity;
360 101
                $mapping['cascade'] = $oneToManyAnnot->cascade;
361 101
                $mapping['indexBy'] = $oneToManyAnnot->indexBy;
362 101
                $mapping['orphanRemoval'] = $oneToManyAnnot->orphanRemoval;
363 101
                $mapping['fetch'] = $this->getFetchMode($className, $oneToManyAnnot->fetch);
364 101
                $mapping['persister'] = $oneToManyAnnot->persister;
365
366 101
                if ($orderByAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
367 15
                    $mapping['orderBy'] = $orderByAnnot->value;
368
                }
369
370 101
                $metadata->mapOneToMany($mapping);
371 189
            } else if ($manyToOneAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToOne')) {
372 126
                if ($idAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Id')) {
0 ignored issues
show
Unused Code introduced by
$idAnnot is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
373 30
                    $mapping['id'] = true;
374
                }
375
376 126
                $mapping['joinColumns'] = $joinColumns;
377 126
                $mapping['cascade'] = $manyToOneAnnot->cascade;
378 126
                $mapping['inversedBy'] = $manyToOneAnnot->inversedBy;
379 126
                $mapping['targetEntity'] = $manyToOneAnnot->targetEntity;
380 126
                $mapping['fetch'] = $this->getFetchMode($className, $manyToOneAnnot->fetch);
381 126
                $metadata->mapManyToOne($mapping);
382 101
            } else if ($manyToManyAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\ManyToMany')) {
383 79
                $joinTable = array();
384
385 79
                if ($joinTableAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\JoinTable')) {
386
                    $joinTable = array(
387 63
                        'name' => $joinTableAnnot->name,
388 63
                        'schema' => $joinTableAnnot->schema
389
                    );
390
391 63
                    foreach ($joinTableAnnot->joinColumns as $joinColumn) {
392 62
                        $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumn);
393
                    }
394
395 63
                    foreach ($joinTableAnnot->inverseJoinColumns as $joinColumn) {
396 62
                        $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumn);
397
                    }
398
                }
399
400 79
                $mapping['joinTable'] = $joinTable;
401 79
                $mapping['targetEntity'] = $manyToManyAnnot->targetEntity;
402 79
                $mapping['mappedBy'] = $manyToManyAnnot->mappedBy;
403 79
                $mapping['inversedBy'] = $manyToManyAnnot->inversedBy;
404 79
                $mapping['cascade'] = $manyToManyAnnot->cascade;
405 79
                $mapping['indexBy'] = $manyToManyAnnot->indexBy;
406 79
                $mapping['orphanRemoval'] = $manyToManyAnnot->orphanRemoval;
407 79
                $mapping['fetch'] = $this->getFetchMode($className, $manyToManyAnnot->fetch);
408 79
                $mapping['persister'] = $manyToManyAnnot->persister;
409
410 79
                if ($orderByAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\OrderBy')) {
411 3
                    $mapping['orderBy'] = $orderByAnnot->value;
412
                }
413
414 79
                $metadata->mapManyToMany($mapping);
415 39
            } else if ($embeddedAnnot = $this->reader->getPropertyAnnotation($property, 'Doctrine\ORM\Mapping\Embedded')) {
416 11
                $mapping['class'] = $embeddedAnnot->class;
417 11
                $mapping['columnPrefix'] = $embeddedAnnot->columnPrefix;
418
419 320
                $metadata->mapEmbedded($mapping);
420
            }
421
        }
422
423
        // Evaluate AssociationOverrides annotation
424 320
        if (isset($classAnnotations['Doctrine\ORM\Mapping\AssociationOverrides'])) {
425 1
            $associationOverridesAnnot = $classAnnotations['Doctrine\ORM\Mapping\AssociationOverrides'];
426
427 1
            foreach ($associationOverridesAnnot->value as $associationOverride) {
428 1
                $override   = array();
429 1
                $fieldName  = $associationOverride->name;
430
431
                // Check for JoinColumn/JoinColumns annotations
432 1
                if ($associationOverride->joinColumns) {
433 1
                    $joinColumns = array();
434
435 1
                    foreach ($associationOverride->joinColumns as $joinColumn) {
436 1
                        $joinColumns[] = $this->joinColumnToArray($joinColumn);
437
                    }
438
439 1
                    $override['joinColumns'] = $joinColumns;
440
                }
441
442
                // Check for JoinTable annotations
443 1
                if ($associationOverride->joinTable) {
444
                    $joinTableAnnot = $associationOverride->joinTable;
445
                    $joinTable      = array(
446
                        'name'      => $joinTableAnnot->name,
447
                        'schema'    => $joinTableAnnot->schema
448
                    );
449
450
                    foreach ($joinTableAnnot->joinColumns as $joinColumn) {
451
                        $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumn);
452
                    }
453
454
                    foreach ($joinTableAnnot->inverseJoinColumns as $joinColumn) {
455
                        $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumn);
456
                    }
457
458
                    $override['joinTable'] = $joinTable;
459
                }
460
461
                // Check for inversedBy
462 1
                if ($associationOverride->inversedBy) {
463
                    $override['inversedBy'] = $associationOverride->inversedBy;
464
                }
465
466 1
                $metadata->setAssociationOverride($fieldName, $override);
467
            }
468
        }
469
470
        // Evaluate AttributeOverrides annotation
471 320
        if (isset($classAnnotations['Doctrine\ORM\Mapping\AttributeOverrides'])) {
472 1
            $attributeOverridesAnnot = $classAnnotations['Doctrine\ORM\Mapping\AttributeOverrides'];
473
474 1
            foreach ($attributeOverridesAnnot->value as $attributeOverrideAnnot) {
475 1
                $attributeOverride = $this->columnToArray($attributeOverrideAnnot->name, $attributeOverrideAnnot->column);
476
477 1
                $metadata->setAttributeOverride($attributeOverrideAnnot->name, $attributeOverride);
478
            }
479
        }
480
481
        // Evaluate EntityListeners annotation
482 320
        if (isset($classAnnotations['Doctrine\ORM\Mapping\EntityListeners'])) {
483 10
            $entityListenersAnnot = $classAnnotations['Doctrine\ORM\Mapping\EntityListeners'];
484
485 10
            foreach ($entityListenersAnnot->value as $item) {
486 10
                $listenerClassName = $metadata->fullyQualifiedClassName($item);
487
488 10
                if ( ! class_exists($listenerClassName)) {
489
                    throw MappingException::entityListenerClassNotFound($listenerClassName, $className);
490
                }
491
492 10
                $hasMapping     = false;
493 10
                $listenerClass  = new \ReflectionClass($listenerClassName);
494
495
                /* @var $method \ReflectionMethod */
496 10
                foreach ($listenerClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
497
                    // find method callbacks.
498 10
                    $callbacks  = $this->getMethodCallbacks($method);
499 10
                    $hasMapping = $hasMapping ?: ( ! empty($callbacks));
500
501 10
                    foreach ($callbacks as $value) {
502 10
                        $metadata->addEntityListener($value[1], $listenerClassName, $value[0]);
503
                    }
504
                }
505
506
                // Evaluate the listener using naming convention.
507 10
                if ( ! $hasMapping ) {
508 10
                    EntityListenerBuilder::bindEntityListener($metadata, $listenerClassName);
0 ignored issues
show
Compatibility introduced by
$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...
509
                }
510
            }
511
        }
512
513
        // Evaluate @HasLifecycleCallbacks annotation
514 320
        if (isset($classAnnotations['Doctrine\ORM\Mapping\HasLifecycleCallbacks'])) {
515
            /* @var $method \ReflectionMethod */
516 16
            foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
517 15
                foreach ($this->getMethodCallbacks($method) as $value) {
518 15
                    $metadata->addLifecycleCallback($value[0], $value[1]);
519
                }
520
            }
521
        }
522 320
    }
523
524
    /**
525
     * Attempts to resolve the fetch mode.
526
     *
527
     * @param string $className The class name.
528
     * @param string $fetchMode The fetch mode.
529
     *
530
     * @return integer The fetch mode as defined in ClassMetadata.
531
     *
532
     * @throws MappingException If the fetch mode is not valid.
533
     */
534 229
    private function getFetchMode($className, $fetchMode)
535
    {
536 229
        if ( ! defined('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $fetchMode)) {
537
            throw MappingException::invalidFetchMode($className, $fetchMode);
538
        }
539
540 229
        return constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $fetchMode);
541
    }
542
543
    /**
544
     * Parses the given method.
545
     *
546
     * @param \ReflectionMethod $method
547
     *
548
     * @return array
549
     */
550 25
    private function getMethodCallbacks(\ReflectionMethod $method)
551
    {
552 25
        $callbacks   = array();
553 25
        $annotations = $this->reader->getMethodAnnotations($method);
554
555 25
        foreach ($annotations as $annot) {
556 19
            if ($annot instanceof \Doctrine\ORM\Mapping\PrePersist) {
557 12
                $callbacks[] = array($method->name, Events::prePersist);
558
            }
559
560 19
            if ($annot instanceof \Doctrine\ORM\Mapping\PostPersist) {
561 10
                $callbacks[] = array($method->name, Events::postPersist);
562
            }
563
564 19
            if ($annot instanceof \Doctrine\ORM\Mapping\PreUpdate) {
565 10
                $callbacks[] = array($method->name, Events::preUpdate);
566
            }
567
568 19
            if ($annot instanceof \Doctrine\ORM\Mapping\PostUpdate) {
569 7
                $callbacks[] = array($method->name, Events::postUpdate);
570
            }
571
572 19
            if ($annot instanceof \Doctrine\ORM\Mapping\PreRemove) {
573 8
                $callbacks[] = array($method->name, Events::preRemove);
574
            }
575
576 19
            if ($annot instanceof \Doctrine\ORM\Mapping\PostRemove) {
577 6
                $callbacks[] = array($method->name, Events::postRemove);
578
            }
579
580 19
            if ($annot instanceof \Doctrine\ORM\Mapping\PostLoad) {
581 11
                $callbacks[] = array($method->name, Events::postLoad);
582
            }
583
584 19
            if ($annot instanceof \Doctrine\ORM\Mapping\PreFlush) {
585 19
                $callbacks[] = array($method->name, Events::preFlush);
586
            }
587
        }
588
589 25
        return $callbacks;
590
    }
591
592
    /**
593
     * Parse the given JoinColumn as array
594
     *
595
     * @param JoinColumn $joinColumn
596
     * @return array
597
     */
598 168
    private function joinColumnToArray(JoinColumn $joinColumn)
599
    {
600
        return array(
601 168
            'name' => $joinColumn->name,
602 168
            'unique' => $joinColumn->unique,
603 168
            'nullable' => $joinColumn->nullable,
604 168
            'onDelete' => $joinColumn->onDelete,
605 168
            'columnDefinition' => $joinColumn->columnDefinition,
606 168
            'referencedColumnName' => $joinColumn->referencedColumnName,
607
        );
608
    }
609
610
    /**
611
     * Parse the given Column as array
612
     *
613
     * @param string $fieldName
614
     * @param Column $column
615
     *
616
     * @return array
617
     */
618 314
    private function columnToArray($fieldName, Column $column)
619
    {
620
        $mapping = array(
621 314
            'fieldName' => $fieldName,
622 314
            'type'      => $column->type,
623 314
            'scale'     => $column->scale,
624 314
            'length'    => $column->length,
625 314
            'unique'    => $column->unique,
626 314
            'nullable'  => $column->nullable,
627 314
            'precision' => $column->precision
628
        );
629
630 314
        if ($column->options) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $column->options 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...
631 7
            $mapping['options'] = $column->options;
632
        }
633
634 314
        if (isset($column->name)) {
635 74
            $mapping['columnName'] = $column->name;
636
        }
637
638 314
        if (isset($column->columnDefinition)) {
639 5
            $mapping['columnDefinition'] = $column->columnDefinition;
640
        }
641
642 314
        return $mapping;
643
    }
644
645
    /**
646
     * Factory method for the Annotation Driver.
647
     *
648
     * @param array|string          $paths
649
     * @param AnnotationReader|null $reader
650
     *
651
     * @return AnnotationDriver
652
     */
653
    static public function create($paths = array(), AnnotationReader $reader = null)
654
    {
655
        if ($reader == null) {
656
            $reader = new AnnotationReader();
657
        }
658
659
        return new self($reader, $paths);
660
    }
661
}
662