Completed
Push — master ( 2a239b...205ee7 )
by Marco
22s
created

YamlDriver::cacheToArray()   B

Complexity

Conditions 6
Paths 12

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 6.0493

Importance

Changes 0
Metric Value
dl 0
loc 18
c 0
b 0
f 0
ccs 8
cts 9
cp 0.8889
rs 8.8571
cc 6
eloc 10
nc 12
nop 1
crap 6.0493
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 65
    public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENSION)
45
    {
46 65
        parent::__construct($locator, $fileExtension);
47 65
    }
48
49
    /**
50
     * {@inheritDoc}
51
     */
52 60
    public function loadMetadataForClass($className, ClassMetadata $metadata)
53
    {
54
        /* @var $metadata \Doctrine\ORM\Mapping\ClassMetadataInfo */
55 60
        $element = $this->getElement($className);
56
57 58
        if ($element['type'] == 'entity') {
58 56
            if (isset($element['repositoryClass'])) {
59
                $metadata->setCustomRepositoryClass($element['repositoryClass']);
60
            }
61 56
            if (isset($element['readOnly']) && $element['readOnly'] == true) {
62 56
                $metadata->markReadOnly();
63
            }
64 14
        } else if ($element['type'] == 'mappedSuperclass') {
65 12
            $metadata->setCustomRepositoryClass(
66 12
                isset($element['repositoryClass']) ? $element['repositoryClass'] : null
67
            );
68 12
            $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 56
        $primaryTable = [];
77
78 56
        if (isset($element['table'])) {
79 22
            $primaryTable['name'] = $element['table'];
80
        }
81
82 56
        if (isset($element['schema'])) {
83 2
            $primaryTable['schema'] = $element['schema'];
84
        }
85
86
        // Evaluate second level cache
87 56
        if (isset($element['cache'])) {
88 2
            $metadata->enableCache($this->cacheToArray($element['cache']));
89
        }
90
91 56
        $metadata->setPrimaryTable($primaryTable);
92
93
        // Evaluate named queries
94 56
        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 56
        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 56
        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 56
        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 56
        if (isset($element['changeTrackingPolicy'])) {
203
            $metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_'
204
                . strtoupper($element['changeTrackingPolicy'])));
205
        }
206
207
        // Evaluate indexes
208 56
        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 56
        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 56
        if (isset($element['options'])) {
258 4
            $metadata->table['options'] = $element['options'];
259
        }
260
261 56
        $associationIds = [];
262 56
        if (isset($element['id'])) {
263
            // Evaluate identifier settings
264 52
            foreach ($element['id'] as $name => $idElement) {
265 52
                if (isset($idElement['associationKey']) && $idElement['associationKey'] == true) {
266
                    $associationIds[$name] = true;
267
                    continue;
268
                }
269
270
                $mapping = [
271 52
                    'id' => true,
272 52
                    'fieldName' => $name
273
                ];
274
275 52
                if (isset($idElement['type'])) {
276 32
                    $mapping['type'] = $idElement['type'];
277
                }
278
279 52
                if (isset($idElement['column'])) {
280 6
                    $mapping['columnName'] = $idElement['column'];
281
                }
282
283 52
                if (isset($idElement['length'])) {
284 6
                    $mapping['length'] = $idElement['length'];
285
                }
286
287 52
                if (isset($idElement['columnDefinition'])) {
288 2
                    $mapping['columnDefinition'] = $idElement['columnDefinition'];
289
                }
290
291 52
                if (isset($idElement['options'])) {
292 2
                    $mapping['options'] = $idElement['options'];
293
                }
294
295 52
                $metadata->mapField($mapping);
296
297 52
                if (isset($idElement['generator'])) {
298 49
                    $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_'
299 49
                        . strtoupper($idElement['generator']['strategy'])));
300
                }
301
                // Check for SequenceGenerator/TableGenerator definition
302 52
                if (isset($idElement['sequenceGenerator'])) {
303 2
                    $metadata->setSequenceGeneratorDefinition($idElement['sequenceGenerator']);
304 50
                } else if (isset($idElement['customIdGenerator'])) {
305 4
                    $customGenerator = $idElement['customIdGenerator'];
306 4
                    $metadata->setCustomGeneratorDefinition(
307
                        [
308 4
                            'class' => (string) $customGenerator['class']
309
                        ]
310
                    );
311 46
                } else if (isset($idElement['tableGenerator'])) {
312 52
                    throw MappingException::tableIdGeneratorNotImplemented($className);
313
                }
314
            }
315
        }
316
317
        // Evaluate fields
318 56
        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 56
        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 56
        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 56
        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 56
        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 56
        if (isset($element['manyToMany'])) {
498 15
            foreach ($element['manyToMany'] as $name => $manyToManyElement) {
499
                $mapping = [
500 15
                    'fieldName' => $name,
501 15
                    'targetEntity' => $manyToManyElement['targetEntity']
502
                ];
503
504 15
                if (isset($manyToManyElement['fetch'])) {
505 2
                    $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToManyElement['fetch']);
506
                }
507
508 15
                if (isset($manyToManyElement['mappedBy'])) {
509 2
                    $mapping['mappedBy'] = $manyToManyElement['mappedBy'];
510 13
                } 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 15
                if (isset($manyToManyElement['inversedBy'])) {
543
                    $mapping['inversedBy'] = $manyToManyElement['inversedBy'];
544
                }
545
546 15
                if (isset($manyToManyElement['cascade'])) {
547 10
                    $mapping['cascade'] = $manyToManyElement['cascade'];
548
                }
549
550 15
                if (isset($manyToManyElement['orderBy'])) {
551
                    $mapping['orderBy'] = $manyToManyElement['orderBy'];
552
                }
553
554 15
                if (isset($manyToManyElement['indexBy'])) {
555
                    $mapping['indexBy'] = $manyToManyElement['indexBy'];
556
                }
557
558 15
                if (isset($manyToManyElement['orphanRemoval'])) {
559
                    $mapping['orphanRemoval'] = (bool) $manyToManyElement['orphanRemoval'];
560
                }
561
562
                // Evaluate second level cache
563 15
                if (isset($manyToManyElement['cache'])) {
564
                    $mapping['cache'] = $metadata->getAssociationCacheDefaults($mapping['fieldName'], $this->cacheToArray($manyToManyElement['cache']));
565
                }
566
567 15
                $metadata->mapManyToMany($mapping);
568
            }
569
        }
570
571
        // Evaluate associationOverride
572 56
        if (isset($element['associationOverride']) && is_array($element['associationOverride'])) {
573
574 6
            foreach ($element['associationOverride'] as $fieldName => $associationOverrideElement) {
575 6
                $override   = [];
576
577
                // Check for joinColumn
578 6
                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 6
                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 6
                if (isset($associationOverrideElement['inversedBy'])) {
622 2
                    $override['inversedBy'] = (string) $associationOverrideElement['inversedBy'];
623
                }
624
625 6
                $metadata->setAssociationOverride($fieldName, $override);
626
            }
627
        }
628
629
        // Evaluate associationOverride
630 56
        if (isset($element['attributeOverride']) && is_array($element['attributeOverride'])) {
631
632 4
            foreach ($element['attributeOverride'] as $fieldName => $attributeOverrideElement) {
633 4
                $mapping = $this->columnToArray($fieldName, $attributeOverrideElement);
634 4
                $metadata->setAttributeOverride($fieldName, $mapping);
635
            }
636
        }
637
638
        // Evaluate lifeCycleCallbacks
639 56
        if (isset($element['lifecycleCallbacks'])) {
640 5
            foreach ($element['lifecycleCallbacks'] as $type => $methods) {
641 4
                foreach ($methods as $method) {
642 4
                    $metadata->addLifecycleCallback($method, constant('Doctrine\ORM\Events::' . $type));
643
                }
644
            }
645
        }
646
647
        // Evaluate entityListeners
648 56
        if (isset($element['entityListeners'])) {
649 8
            foreach ($element['entityListeners'] as $className => $entityListener) {
650
                // Evaluate the listener using naming convention.
651 8
                if (empty($entityListener)) {
652 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...
653
654 4
                    continue;
655
                }
656
657 4
                foreach ($entityListener as $eventName => $callbackElement) {
658 4
                    foreach ($callbackElement as $methodName) {
659 4
                        $metadata->addEntityListener($eventName, $className, $methodName);
660
                    }
661
                }
662
            }
663
        }
664 56
    }
665
666
    /**
667
     * Constructs a joinColumn mapping array based on the information
668
     * found in the given join column element.
669
     *
670
     * @param array $joinColumnElement The array join column element.
671
     *
672
     * @return array The mapping array.
673
     */
674 17
    private function joinColumnToArray($joinColumnElement)
675
    {
676 17
        $joinColumn = [];
677 17
        if (isset($joinColumnElement['referencedColumnName'])) {
678 17
            $joinColumn['referencedColumnName'] = (string) $joinColumnElement['referencedColumnName'];
679
        }
680
681 17
        if (isset($joinColumnElement['name'])) {
682 13
            $joinColumn['name'] = (string) $joinColumnElement['name'];
683
        }
684
685 17
        if (isset($joinColumnElement['fieldName'])) {
686
            $joinColumn['fieldName'] = (string) $joinColumnElement['fieldName'];
687
        }
688
689 17
        if (isset($joinColumnElement['unique'])) {
690 4
            $joinColumn['unique'] = (bool) $joinColumnElement['unique'];
691
        }
692
693 17
        if (isset($joinColumnElement['nullable'])) {
694 6
            $joinColumn['nullable'] = (bool) $joinColumnElement['nullable'];
695
        }
696
697 17
        if (isset($joinColumnElement['onDelete'])) {
698 4
            $joinColumn['onDelete'] = $joinColumnElement['onDelete'];
699
        }
700
701 17
        if (isset($joinColumnElement['columnDefinition'])) {
702 4
            $joinColumn['columnDefinition'] = $joinColumnElement['columnDefinition'];
703
        }
704
705 17
        return $joinColumn;
706
    }
707
708
    /**
709
     * Parses the given column as array.
710
     *
711
     * @param string $fieldName
712
     * @param array  $column
713
     *
714
     * @return  array
715
     */
716 39
    private function columnToArray($fieldName, $column)
717
    {
718
        $mapping = [
719 39
            'fieldName' => $fieldName
720
        ];
721
722 39
        if (isset($column['type'])) {
723 33
            $params = explode('(', $column['type']);
724
725 33
            $column['type']  = $params[0];
726 33
            $mapping['type'] = $column['type'];
727
728 33
            if (isset($params[1])) {
729 2
                $column['length'] = (integer) substr($params[1], 0, strlen($params[1]) - 1);
730
            }
731
        }
732
733 39
        if (isset($column['column'])) {
734 11
            $mapping['columnName'] = $column['column'];
735
        }
736
737 39
        if (isset($column['length'])) {
738 21
            $mapping['length'] = $column['length'];
739
        }
740
741 39
        if (isset($column['precision'])) {
742
            $mapping['precision'] = $column['precision'];
743
        }
744
745 39
        if (isset($column['scale'])) {
746
            $mapping['scale'] = $column['scale'];
747
        }
748
749 39
        if (isset($column['unique'])) {
750 13
            $mapping['unique'] = (bool) $column['unique'];
751
        }
752
753 39
        if (isset($column['options'])) {
754 4
            $mapping['options'] = $column['options'];
755
        }
756
757 39
        if (isset($column['nullable'])) {
758 10
            $mapping['nullable'] = $column['nullable'];
759
        }
760
761 39
        if (isset($column['version']) && $column['version']) {
762 2
            $mapping['version'] = $column['version'];
763
        }
764
765 39
        if (isset($column['columnDefinition'])) {
766 6
            $mapping['columnDefinition'] = $column['columnDefinition'];
767
        }
768
769 39
        return $mapping;
770
    }
771
772
    /**
773
     * Parse / Normalize the cache configuration
774
     *
775
     * @param array $cacheMapping
776
     *
777
     * @return array
778
     */
779 2
    private function cacheToArray($cacheMapping)
780
    {
781 2
        $region = isset($cacheMapping['region']) ? (string) $cacheMapping['region'] : null;
782 2
        $usage  = isset($cacheMapping['usage']) ? strtoupper($cacheMapping['usage']) : null;
783
784 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...
785
            throw new \InvalidArgumentException(sprintf('Invalid cache usage "%s"', $usage));
786
        }
787
788 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...
789 2
            $usage = constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $usage);
790
        }
791
792
        return [
793 2
            'usage'  => $usage,
794 2
            'region' => $region,
795
        ];
796
    }
797
798
    /**
799
     * {@inheritDoc}
800
     */
801 60
    protected function loadMappingFile($file)
802
    {
803 60
        if (defined(Yaml::class . '::PARSE_KEYS_AS_STRINGS')) {
804 60
            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...
805
        }
806
807
        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...
808
    }
809
}
810