Completed
Pull Request — master (#5938)
by Luís
10:36
created

YamlDriver::loadMappingFile()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
ccs 3
cts 4
cp 0.75
rs 9.4285
cc 2
eloc 4
nc 2
nop 1
crap 2.0625
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\Persistence\Mapping\ClassMetadata;
23
use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
24
use Doctrine\Common\Persistence\Mapping\Driver\FileDriver;
25
use Doctrine\ORM\Mapping\MappingException;
26
use Symfony\Component\Yaml\Yaml;
27
28
/**
29
 * The YamlDriver reads the mapping metadata from yaml schema files.
30
 *
31
 * @since 2.0
32
 * @author Benjamin Eberlei <[email protected]>
33
 * @author Guilherme Blanco <[email protected]>
34
 * @author Jonathan H. Wage <[email protected]>
35
 * @author Roman Borschel <[email protected]>
36
 */
37
class YamlDriver extends FileDriver
38
{
39
    const DEFAULT_FILE_EXTENSION = '.dcm.yml';
40
41
    /**
42
     * {@inheritDoc}
43
     */
44 67
    public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENSION)
45
    {
46 67
        parent::__construct($locator, $fileExtension);
47 67
    }
48
49
    /**
50
     * {@inheritDoc}
51
     */
52 62
    public function loadMetadataForClass($className, ClassMetadata $metadata)
53
    {
54
        /* @var $metadata \Doctrine\ORM\Mapping\ClassMetadataInfo */
55 62
        $element = $this->getElement($className);
56
57 60
        if ($element['type'] == 'entity') {
58 58
            if (isset($element['repositoryClass'])) {
59
                $metadata->setCustomRepositoryClass($element['repositoryClass']);
60
            }
61 58
            if (isset($element['readOnly']) && $element['readOnly'] == true) {
62 58
                $metadata->markReadOnly();
63
            }
64 16
        } else if ($element['type'] == 'mappedSuperclass') {
65 14
            $metadata->setCustomRepositoryClass(
66 14
                isset($element['repositoryClass']) ? $element['repositoryClass'] : null
67
            );
68 14
            $metadata->isMappedSuperclass = true;
69 2
        } else if ($element['type'] == 'embeddable') {
70
            $metadata->isEmbeddedClass = true;
71
        } else {
72 2
            throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
73
        }
74
75
        // Evaluate root level properties
76 58
        $primaryTable = [];
77
78 58
        if (isset($element['table'])) {
79 22
            $primaryTable['name'] = $element['table'];
80
        }
81
82 58
        if (isset($element['schema'])) {
83 2
            $primaryTable['schema'] = $element['schema'];
84
        }
85
86
        // Evaluate second level cache
87 58
        if (isset($element['cache'])) {
88 2
            $metadata->enableCache($this->cacheToArray($element['cache']));
89
        }
90
91 58
        $metadata->setPrimaryTable($primaryTable);
92
93
        // Evaluate named queries
94 58
        if (isset($element['namedQueries'])) {
95 4
            foreach ($element['namedQueries'] as $name => $queryMapping) {
96 4
                if (is_string($queryMapping)) {
97 4
                    $queryMapping = ['query' => $queryMapping];
98
                }
99
100 4
                if ( ! isset($queryMapping['name'])) {
101 4
                    $queryMapping['name'] = $name;
102
                }
103
104 4
                $metadata->addNamedQuery($queryMapping);
105
            }
106
        }
107
108
        // Evaluate named native queries
109 58
        if (isset($element['namedNativeQueries'])) {
110 6
            foreach ($element['namedNativeQueries'] as $name => $mappingElement) {
111 6
                if (!isset($mappingElement['name'])) {
112 6
                    $mappingElement['name'] = $name;
113
                }
114 6
                $metadata->addNamedNativeQuery(
115
                    [
116 6
                        'name'              => $mappingElement['name'],
117 6
                        'query'             => isset($mappingElement['query']) ? $mappingElement['query'] : null,
118 6
                        'resultClass'       => isset($mappingElement['resultClass']) ? $mappingElement['resultClass'] : null,
119 6
                        'resultSetMapping'  => isset($mappingElement['resultSetMapping']) ? $mappingElement['resultSetMapping'] : null,
120
                    ]
121
                );
122
            }
123
        }
124
125
        // Evaluate sql result set mappings
126 58
        if (isset($element['sqlResultSetMappings'])) {
127 6
            foreach ($element['sqlResultSetMappings'] as $name => $resultSetMapping) {
128 6
                if (!isset($resultSetMapping['name'])) {
129 6
                    $resultSetMapping['name'] = $name;
130
                }
131
132 6
                $entities = [];
133 6
                $columns  = [];
134 6
                if (isset($resultSetMapping['entityResult'])) {
135 6
                    foreach ($resultSetMapping['entityResult'] as $entityResultElement) {
136
                        $entityResult = [
137 6
                            'fields'                => [],
138 6
                            'entityClass'           => isset($entityResultElement['entityClass']) ? $entityResultElement['entityClass'] : null,
139 6
                            'discriminatorColumn'   => isset($entityResultElement['discriminatorColumn']) ? $entityResultElement['discriminatorColumn'] : null,
140
                        ];
141
142 6
                        if (isset($entityResultElement['fieldResult'])) {
143 6
                            foreach ($entityResultElement['fieldResult'] as $fieldResultElement) {
144 6
                                $entityResult['fields'][] = [
145 6
                                    'name'      => isset($fieldResultElement['name']) ? $fieldResultElement['name'] : null,
146 6
                                    'column'    => isset($fieldResultElement['column']) ? $fieldResultElement['column'] : null,
147
                                ];
148
                            }
149
                        }
150
151 6
                        $entities[] = $entityResult;
152
                    }
153
                }
154
155
156 6
                if (isset($resultSetMapping['columnResult'])) {
157 6
                    foreach ($resultSetMapping['columnResult'] as $columnResultAnnot) {
158 6
                        $columns[] = [
159 6
                            'name' => isset($columnResultAnnot['name']) ? $columnResultAnnot['name'] : null,
160
                        ];
161
                    }
162
                }
163
164 6
                $metadata->addSqlResultSetMapping(
165
                    [
166 6
                        'name'          => $resultSetMapping['name'],
167 6
                        'entities'      => $entities,
168 6
                        'columns'       => $columns
169
                    ]
170
                );
171
            }
172
        }
173
174 58
        if (isset($element['inheritanceType'])) {
175 18
            $metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . strtoupper($element['inheritanceType'])));
176
177 18
            if ($metadata->inheritanceType != \Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_NONE) {
178
                // Evaluate discriminatorColumn
179 18
                if (isset($element['discriminatorColumn'])) {
180 12
                    $discrColumn = $element['discriminatorColumn'];
181 12
                    $metadata->setDiscriminatorColumn(
182
                        [
183 12
                            'name' => isset($discrColumn['name']) ? (string) $discrColumn['name'] : null,
184 12
                            'type' => isset($discrColumn['type']) ? (string) $discrColumn['type'] : 'string',
185 12
                            'length' => isset($discrColumn['length']) ? (string) $discrColumn['length'] : 255,
186 12
                            'columnDefinition' => isset($discrColumn['columnDefinition']) ? (string) $discrColumn['columnDefinition'] : null
187
                        ]
188
                    );
189
                } else {
190 12
                    $metadata->setDiscriminatorColumn(['name' => 'dtype', 'type' => 'string', 'length' => 255]);
191
                }
192
193
                // Evaluate discriminatorMap
194 18
                if (isset($element['discriminatorMap'])) {
195 18
                    $metadata->setDiscriminatorMap($element['discriminatorMap']);
196
                }
197
            }
198
        }
199
200
201
        // Evaluate changeTrackingPolicy
202 58
        if (isset($element['changeTrackingPolicy'])) {
203
            $metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_'
204
                . strtoupper($element['changeTrackingPolicy'])));
205
        }
206
207
        // Evaluate indexes
208 58
        if (isset($element['indexes'])) {
209 6
            foreach ($element['indexes'] as $name => $indexYml) {
210 6
                if ( ! isset($indexYml['name'])) {
211 6
                    $indexYml['name'] = $name;
212
                }
213
214 6
                if (is_string($indexYml['columns'])) {
215 6
                    $index = ['columns' => array_map('trim', explode(',', $indexYml['columns']))];
216
                } else {
217
                    $index = ['columns' => $indexYml['columns']];
218
                }
219
220 6
                if (isset($indexYml['flags'])) {
221 2
                    if (is_string($indexYml['flags'])) {
222 2
                        $index['flags'] = array_map('trim', explode(',', $indexYml['flags']));
223
                    } else {
224
                        $index['flags'] = $indexYml['flags'];
225
                    }
226
                }
227
228 6
                if (isset($indexYml['options'])) {
229 2
                    $index['options'] = $indexYml['options'];
230
                }
231
232 6
                $metadata->table['indexes'][$indexYml['name']] = $index;
233
            }
234
        }
235
236
        // Evaluate uniqueConstraints
237 58
        if (isset($element['uniqueConstraints'])) {
238 5
            foreach ($element['uniqueConstraints'] as $name => $uniqueYml) {
239 5
                if ( ! isset($uniqueYml['name'])) {
240 5
                    $uniqueYml['name'] = $name;
241
                }
242
243 5
                if (is_string($uniqueYml['columns'])) {
244 4
                    $unique = ['columns' => array_map('trim', explode(',', $uniqueYml['columns']))];
245
                } else {
246 1
                    $unique = ['columns' => $uniqueYml['columns']];
247
                }
248
249 5
                if (isset($uniqueYml['options'])) {
250 2
                    $unique['options'] = $uniqueYml['options'];
251
                }
252
253 5
                $metadata->table['uniqueConstraints'][$uniqueYml['name']] = $unique;
254
            }
255
        }
256
257 58
        if (isset($element['options'])) {
258 4
            $metadata->table['options'] = $element['options'];
259
        }
260
261 58
        $associationIds = [];
262 58
        if (isset($element['id'])) {
263
            // Evaluate identifier settings
264 54
            foreach ($element['id'] as $name => $idElement) {
265 54
                if (isset($idElement['associationKey']) && $idElement['associationKey'] == true) {
266
                    $associationIds[$name] = true;
267
                    continue;
268
                }
269
270
                $mapping = [
271 54
                    'id' => true,
272 54
                    'fieldName' => $name
273
                ];
274
275 54
                if (isset($idElement['type'])) {
276 34
                    $mapping['type'] = $idElement['type'];
277
                }
278
279 54
                if (isset($idElement['column'])) {
280 8
                    $mapping['columnName'] = $idElement['column'];
281
                }
282
283 54
                if (isset($idElement['length'])) {
284 6
                    $mapping['length'] = $idElement['length'];
285
                }
286
287 54
                if (isset($idElement['columnDefinition'])) {
288 2
                    $mapping['columnDefinition'] = $idElement['columnDefinition'];
289
                }
290
291 54
                if (isset($idElement['options'])) {
292 2
                    $mapping['options'] = $idElement['options'];
293
                }
294
295 54
                $metadata->mapField($mapping);
296
297 54
                if (isset($idElement['generator'])) {
298 51
                    $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_'
299 51
                        . strtoupper($idElement['generator']['strategy'])));
300
                }
301
                // Check for SequenceGenerator/TableGenerator definition
302 54
                if (isset($idElement['sequenceGenerator'])) {
303 2
                    $metadata->setSequenceGeneratorDefinition($idElement['sequenceGenerator']);
304 52
                } else if (isset($idElement['customIdGenerator'])) {
305 4
                    $customGenerator = $idElement['customIdGenerator'];
306 4
                    $metadata->setCustomGeneratorDefinition(
307
                        [
308 4
                            'class' => (string) $customGenerator['class']
309
                        ]
310
                    );
311 48
                } else if (isset($idElement['tableGenerator'])) {
312 54
                    throw MappingException::tableIdGeneratorNotImplemented($className);
313
                }
314
            }
315
        }
316
317
        // Evaluate fields
318 58
        if (isset($element['fields'])) {
319 39
            foreach ($element['fields'] as $name => $fieldMapping) {
320
321 39
                $mapping = $this->columnToArray($name, $fieldMapping);
322
323 39
                if (isset($fieldMapping['id'])) {
324
                    $mapping['id'] = true;
325
                    if (isset($fieldMapping['generator']['strategy'])) {
326
                        $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_'
327
                            . strtoupper($fieldMapping['generator']['strategy'])));
328
                    }
329
                }
330
331 39
                if (isset($mapping['version'])) {
332 2
                    $metadata->setVersionMapping($mapping);
333 2
                    unset($mapping['version']);
334
                }
335
336 39
                $metadata->mapField($mapping);
337
            }
338
        }
339
340 58
        if (isset($element['embedded'])) {
341
            foreach ($element['embedded'] as $name => $embeddedMapping) {
342
                $mapping = [
343
                    'fieldName' => $name,
344
                    'class' => $embeddedMapping['class'],
345
                    'columnPrefix' => isset($embeddedMapping['columnPrefix']) ? $embeddedMapping['columnPrefix'] : null,
346
                ];
347
                $metadata->mapEmbedded($mapping);
348
            }
349
        }
350
351
        // Evaluate oneToOne relationships
352 58
        if (isset($element['oneToOne'])) {
353 11
            foreach ($element['oneToOne'] as $name => $oneToOneElement) {
354
                $mapping = [
355 11
                    'fieldName' => $name,
356 11
                    'targetEntity' => $oneToOneElement['targetEntity']
357
                ];
358
359 11
                if (isset($associationIds[$mapping['fieldName']])) {
360
                    $mapping['id'] = true;
361
                }
362
363 11
                if (isset($oneToOneElement['fetch'])) {
364 3
                    $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToOneElement['fetch']);
365
                }
366
367 11
                if (isset($oneToOneElement['mappedBy'])) {
368 3
                    $mapping['mappedBy'] = $oneToOneElement['mappedBy'];
369
                } else {
370 10
                    if (isset($oneToOneElement['inversedBy'])) {
371 10
                        $mapping['inversedBy'] = $oneToOneElement['inversedBy'];
372
                    }
373
374 10
                    $joinColumns = [];
375
376 10
                    if (isset($oneToOneElement['joinColumn'])) {
377 9
                        $joinColumns[] = $this->joinColumnToArray($oneToOneElement['joinColumn']);
378 1
                    } else if (isset($oneToOneElement['joinColumns'])) {
379 1
                        foreach ($oneToOneElement['joinColumns'] as $joinColumnName => $joinColumnElement) {
380 1
                            if ( ! isset($joinColumnElement['name'])) {
381 1
                                $joinColumnElement['name'] = $joinColumnName;
382
                            }
383
384 1
                            $joinColumns[] = $this->joinColumnToArray($joinColumnElement);
385
                        }
386
                    }
387
388 10
                    $mapping['joinColumns'] = $joinColumns;
389
                }
390
391 11
                if (isset($oneToOneElement['cascade'])) {
392 7
                    $mapping['cascade'] = $oneToOneElement['cascade'];
393
                }
394
395 11
                if (isset($oneToOneElement['orphanRemoval'])) {
396 5
                    $mapping['orphanRemoval'] = (bool) $oneToOneElement['orphanRemoval'];
397
                }
398
399
                // Evaluate second level cache
400 11
                if (isset($oneToOneElement['cache'])) {
401
                    $mapping['cache'] = $metadata->getAssociationCacheDefaults($mapping['fieldName'], $this->cacheToArray($oneToOneElement['cache']));
402
                }
403
404 11
                $metadata->mapOneToOne($mapping);
405
            }
406
        }
407
408
        // Evaluate oneToMany relationships
409 58
        if (isset($element['oneToMany'])) {
410 6
            foreach ($element['oneToMany'] as $name => $oneToManyElement) {
411
                $mapping = [
412 6
                    'fieldName' => $name,
413 6
                    'targetEntity' => $oneToManyElement['targetEntity'],
414 6
                    'mappedBy' => $oneToManyElement['mappedBy']
415
                ];
416
417 6
                if (isset($oneToManyElement['fetch'])) {
418 2
                    $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToManyElement['fetch']);
419
                }
420
421 6
                if (isset($oneToManyElement['cascade'])) {
422 4
                    $mapping['cascade'] = $oneToManyElement['cascade'];
423
                }
424
425 6
                if (isset($oneToManyElement['orphanRemoval'])) {
426 4
                    $mapping['orphanRemoval'] = (bool) $oneToManyElement['orphanRemoval'];
427
                }
428
429 6
                if (isset($oneToManyElement['orderBy'])) {
430 6
                    $mapping['orderBy'] = $oneToManyElement['orderBy'];
431
                }
432
433 6
                if (isset($oneToManyElement['indexBy'])) {
434
                    $mapping['indexBy'] = $oneToManyElement['indexBy'];
435
                }
436
437
438
                // Evaluate second level cache
439 6
                if (isset($oneToManyElement['cache'])) {
440 2
                    $mapping['cache'] = $metadata->getAssociationCacheDefaults($mapping['fieldName'], $this->cacheToArray($oneToManyElement['cache']));
441
                }
442
443 6
                $metadata->mapOneToMany($mapping);
444
            }
445
        }
446
447
        // Evaluate manyToOne relationships
448 58
        if (isset($element['manyToOne'])) {
449 10
            foreach ($element['manyToOne'] as $name => $manyToOneElement) {
450
                $mapping = [
451 10
                    'fieldName' => $name,
452 10
                    'targetEntity' => $manyToOneElement['targetEntity']
453
                ];
454
455 10
                if (isset($associationIds[$mapping['fieldName']])) {
456
                    $mapping['id'] = true;
457
                }
458
459 10
                if (isset($manyToOneElement['fetch'])) {
460 1
                    $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToOneElement['fetch']);
461
                }
462
463 10
                if (isset($manyToOneElement['inversedBy'])) {
464 2
                    $mapping['inversedBy'] = $manyToOneElement['inversedBy'];
465
                }
466
467 10
                $joinColumns = [];
468
469 10
                if (isset($manyToOneElement['joinColumn'])) {
470 4
                    $joinColumns[] = $this->joinColumnToArray($manyToOneElement['joinColumn']);
471 6
                } else if (isset($manyToOneElement['joinColumns'])) {
472 3
                    foreach ($manyToOneElement['joinColumns'] as $joinColumnName => $joinColumnElement) {
473 3
                        if ( ! isset($joinColumnElement['name'])) {
474 3
                            $joinColumnElement['name'] = $joinColumnName;
475
                        }
476
477 3
                        $joinColumns[] = $this->joinColumnToArray($joinColumnElement);
478
                    }
479
                }
480
481 10
                $mapping['joinColumns'] = $joinColumns;
482
483 10
                if (isset($manyToOneElement['cascade'])) {
484 5
                    $mapping['cascade'] = $manyToOneElement['cascade'];
485
                }
486
487
                // Evaluate second level cache
488 10
                if (isset($manyToOneElement['cache'])) {
489 2
                    $mapping['cache'] = $metadata->getAssociationCacheDefaults($mapping['fieldName'], $this->cacheToArray($manyToOneElement['cache']));
490
                }
491
492 10
                $metadata->mapManyToOne($mapping);
493
            }
494
        }
495
496
        // Evaluate manyToMany relationships
497 58
        if (isset($element['manyToMany'])) {
498 17
            foreach ($element['manyToMany'] as $name => $manyToManyElement) {
499
                $mapping = [
500 17
                    'fieldName' => $name,
501 17
                    'targetEntity' => $manyToManyElement['targetEntity']
502
                ];
503
504 17
                if (isset($manyToManyElement['fetch'])) {
505 2
                    $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToManyElement['fetch']);
506
                }
507
508 17
                if (isset($manyToManyElement['mappedBy'])) {
509 2
                    $mapping['mappedBy'] = $manyToManyElement['mappedBy'];
510 15
                } else if (isset($manyToManyElement['joinTable'])) {
511
512 11
                    $joinTableElement = $manyToManyElement['joinTable'];
513
                    $joinTable = [
514 11
                        'name' => $joinTableElement['name']
515
                    ];
516
517 11
                    if (isset($joinTableElement['schema'])) {
518
                        $joinTable['schema'] = $joinTableElement['schema'];
519
                    }
520
521 11
                    if (isset($joinTableElement['joinColumns'])) {
522 11
                        foreach ($joinTableElement['joinColumns'] as $joinColumnName => $joinColumnElement) {
523 11
                            if ( ! isset($joinColumnElement['name'])) {
524 10
                                $joinColumnElement['name'] = $joinColumnName;
525
                            }
526 11
                            $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement);
527
                        }
528
                    }
529
530 11
                    if (isset($joinTableElement['inverseJoinColumns'])) {
531 11
                        foreach ($joinTableElement['inverseJoinColumns'] as $joinColumnName => $joinColumnElement) {
532 11
                            if ( ! isset($joinColumnElement['name'])) {
533 10
                                $joinColumnElement['name'] = $joinColumnName;
534
                            }
535 11
                            $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement);
536
                        }
537
                    }
538
539 11
                    $mapping['joinTable'] = $joinTable;
540
                }
541
542 17
                if (isset($manyToManyElement['inversedBy'])) {
543 2
                    $mapping['inversedBy'] = $manyToManyElement['inversedBy'];
544
                }
545
546 17
                if (isset($manyToManyElement['cascade'])) {
547 10
                    $mapping['cascade'] = $manyToManyElement['cascade'];
548
                }
549
550 17
                if (isset($manyToManyElement['orderBy'])) {
551
                    $mapping['orderBy'] = $manyToManyElement['orderBy'];
552
                }
553
554 17
                if (isset($manyToManyElement['indexBy'])) {
555
                    $mapping['indexBy'] = $manyToManyElement['indexBy'];
556
                }
557
558 17
                if (isset($manyToManyElement['orphanRemoval'])) {
559
                    $mapping['orphanRemoval'] = (bool) $manyToManyElement['orphanRemoval'];
560
                }
561
562
                // Evaluate second level cache
563 17
                if (isset($manyToManyElement['cache'])) {
564
                    $mapping['cache'] = $metadata->getAssociationCacheDefaults($mapping['fieldName'], $this->cacheToArray($manyToManyElement['cache']));
565
                }
566
567 17
                $metadata->mapManyToMany($mapping);
568
            }
569
        }
570
571
        // Evaluate associationOverride
572 58
        if (isset($element['associationOverride']) && is_array($element['associationOverride'])) {
573
574 8
            foreach ($element['associationOverride'] as $fieldName => $associationOverrideElement) {
575 8
                $override   = [];
576
577
                // Check for joinColumn
578 8
                if (isset($associationOverrideElement['joinColumn'])) {
579 4
                    $joinColumns = [];
580 4
                    foreach ($associationOverrideElement['joinColumn'] as $name => $joinColumnElement) {
581 4
                        if ( ! isset($joinColumnElement['name'])) {
582
                            $joinColumnElement['name'] = $name;
583
                        }
584 4
                        $joinColumns[] = $this->joinColumnToArray($joinColumnElement);
585
                    }
586 4
                    $override['joinColumns'] = $joinColumns;
587
                }
588
589
                // Check for joinTable
590 8
                if (isset($associationOverrideElement['joinTable'])) {
591
592 4
                    $joinTableElement   = $associationOverrideElement['joinTable'];
593
                    $joinTable          =  [
594 4
                        'name' => $joinTableElement['name']
595
                    ];
596
597 4
                    if (isset($joinTableElement['schema'])) {
598
                        $joinTable['schema'] = $joinTableElement['schema'];
599
                    }
600
601 4
                    foreach ($joinTableElement['joinColumns'] as $name => $joinColumnElement) {
602 4
                        if ( ! isset($joinColumnElement['name'])) {
603 4
                            $joinColumnElement['name'] = $name;
604
                        }
605
606 4
                        $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement);
607
                    }
608
609 4
                    foreach ($joinTableElement['inverseJoinColumns'] as $name => $joinColumnElement) {
610 4
                        if ( ! isset($joinColumnElement['name'])) {
611 4
                            $joinColumnElement['name'] = $name;
612
                        }
613
614 4
                        $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement);
615
                    }
616
617 4
                    $override['joinTable'] = $joinTable;
618
                }
619
620
                // Check for inversedBy
621 8
                if (isset($associationOverrideElement['inversedBy'])) {
622 2
                    $override['inversedBy'] = (string) $associationOverrideElement['inversedBy'];
623
                }
624
625
                // Check for `fetch`
626 8
                if (isset($associationOverrideElement['fetch'])) {
627 2
                    $override['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $associationOverrideElement['fetch']);
628
                }
629
630 8
                $metadata->setAssociationOverride($fieldName, $override);
631
            }
632
        }
633
634
        // Evaluate associationOverride
635 58
        if (isset($element['attributeOverride']) && is_array($element['attributeOverride'])) {
636
637 4
            foreach ($element['attributeOverride'] as $fieldName => $attributeOverrideElement) {
638 4
                $mapping = $this->columnToArray($fieldName, $attributeOverrideElement);
639 4
                $metadata->setAttributeOverride($fieldName, $mapping);
640
            }
641
        }
642
643
        // Evaluate lifeCycleCallbacks
644 58
        if (isset($element['lifecycleCallbacks'])) {
645 5
            foreach ($element['lifecycleCallbacks'] as $type => $methods) {
646 4
                foreach ($methods as $method) {
647 4
                    $metadata->addLifecycleCallback($method, constant('Doctrine\ORM\Events::' . $type));
648
                }
649
            }
650
        }
651
652
        // Evaluate entityListeners
653 58
        if (isset($element['entityListeners'])) {
654 8
            foreach ($element['entityListeners'] as $className => $entityListener) {
655
                // Evaluate the listener using naming convention.
656 8
                if (empty($entityListener)) {
657 4
                    EntityListenerBuilder::bindEntityListener($metadata, $className);
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...
658
659 4
                    continue;
660
                }
661
662 4
                foreach ($entityListener as $eventName => $callbackElement) {
663 4
                    foreach ($callbackElement as $methodName) {
664 4
                        $metadata->addEntityListener($eventName, $className, $methodName);
665
                    }
666
                }
667
            }
668
        }
669 58
    }
670
671
    /**
672
     * Constructs a joinColumn mapping array based on the information
673
     * found in the given join column element.
674
     *
675
     * @param array $joinColumnElement The array join column element.
676
     *
677
     * @return array The mapping array.
678
     */
679 17
    private function joinColumnToArray($joinColumnElement)
680
    {
681 17
        $joinColumn = [];
682 17
        if (isset($joinColumnElement['referencedColumnName'])) {
683 17
            $joinColumn['referencedColumnName'] = (string) $joinColumnElement['referencedColumnName'];
684
        }
685
686 17
        if (isset($joinColumnElement['name'])) {
687 13
            $joinColumn['name'] = (string) $joinColumnElement['name'];
688
        }
689
690 17
        if (isset($joinColumnElement['fieldName'])) {
691
            $joinColumn['fieldName'] = (string) $joinColumnElement['fieldName'];
692
        }
693
694 17
        if (isset($joinColumnElement['unique'])) {
695 4
            $joinColumn['unique'] = (bool) $joinColumnElement['unique'];
696
        }
697
698 17
        if (isset($joinColumnElement['nullable'])) {
699 6
            $joinColumn['nullable'] = (bool) $joinColumnElement['nullable'];
700
        }
701
702 17
        if (isset($joinColumnElement['onDelete'])) {
703 4
            $joinColumn['onDelete'] = $joinColumnElement['onDelete'];
704
        }
705
706 17
        if (isset($joinColumnElement['columnDefinition'])) {
707 4
            $joinColumn['columnDefinition'] = $joinColumnElement['columnDefinition'];
708
        }
709
710 17
        return $joinColumn;
711
    }
712
713
    /**
714
     * Parses the given column as array.
715
     *
716
     * @param string $fieldName
717
     * @param array  $column
718
     *
719
     * @return  array
720
     */
721 39
    private function columnToArray($fieldName, $column)
722
    {
723
        $mapping = [
724 39
            'fieldName' => $fieldName
725
        ];
726
727 39
        if (isset($column['type'])) {
728 33
            $params = explode('(', $column['type']);
729
730 33
            $column['type']  = $params[0];
731 33
            $mapping['type'] = $column['type'];
732
733 33
            if (isset($params[1])) {
734 2
                $column['length'] = (integer) substr($params[1], 0, strlen($params[1]) - 1);
735
            }
736
        }
737
738 39
        if (isset($column['column'])) {
739 11
            $mapping['columnName'] = $column['column'];
740
        }
741
742 39
        if (isset($column['length'])) {
743 21
            $mapping['length'] = $column['length'];
744
        }
745
746 39
        if (isset($column['precision'])) {
747
            $mapping['precision'] = $column['precision'];
748
        }
749
750 39
        if (isset($column['scale'])) {
751
            $mapping['scale'] = $column['scale'];
752
        }
753
754 39
        if (isset($column['unique'])) {
755 13
            $mapping['unique'] = (bool) $column['unique'];
756
        }
757
758 39
        if (isset($column['options'])) {
759 4
            $mapping['options'] = $column['options'];
760
        }
761
762 39
        if (isset($column['nullable'])) {
763 10
            $mapping['nullable'] = $column['nullable'];
764
        }
765
766 39
        if (isset($column['version']) && $column['version']) {
767 2
            $mapping['version'] = $column['version'];
768
        }
769
770 39
        if (isset($column['columnDefinition'])) {
771 6
            $mapping['columnDefinition'] = $column['columnDefinition'];
772
        }
773
774 39
        return $mapping;
775
    }
776
777
    /**
778
     * Parse / Normalize the cache configuration
779
     *
780
     * @param array $cacheMapping
781
     *
782
     * @return array
783
     */
784 2
    private function cacheToArray($cacheMapping)
785
    {
786 2
        $region = isset($cacheMapping['region']) ? (string) $cacheMapping['region'] : null;
787 2
        $usage  = isset($cacheMapping['usage']) ? strtoupper($cacheMapping['usage']) : null;
788
789 2
        if ($usage && ! defined('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $usage)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $usage of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
790
            throw new \InvalidArgumentException(sprintf('Invalid cache usage "%s"', $usage));
791
        }
792
793 2
        if ($usage) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $usage of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
794 2
            $usage = constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $usage);
795
        }
796
797
        return [
798 2
            'usage'  => $usage,
799 2
            'region' => $region,
800
        ];
801
    }
802
803
    /**
804
     * {@inheritDoc}
805
     */
806 62
    protected function loadMappingFile($file)
807
    {
808 62
        if (defined(Yaml::class . '::PARSE_KEYS_AS_STRINGS')) {
809 62
            return Yaml::parse(file_get_contents($file), Yaml::PARSE_KEYS_AS_STRINGS);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return \Symfony\Componen...PARSE_KEYS_AS_STRINGS); (null|Symfony\Component\Y...e|string|array|stdClass) is incompatible with the return type declared by the abstract method Doctrine\Common\Persiste...Driver::loadMappingFile of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
810
        }
811
812
        return Yaml::parse(file_get_contents($file));
0 ignored issues
show
Bug Best Practice introduced by
The return type of return \Symfony\Componen...e_get_contents($file)); (null|Symfony\Component\Y...e|string|array|stdClass) is incompatible with the return type declared by the abstract method Doctrine\Common\Persiste...Driver::loadMappingFile of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
813
    }
814
}
815