Failed Conditions
Push — master ( a0c0d3...57a950 )
by Marco
22:07
created

lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php (1 issue)

Check for loose comparison of strings.

Best Practice Bug Major

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ORM\Mapping\Driver;
21
22
use SimpleXMLElement;
23
use Doctrine\Common\Persistence\Mapping\Driver\FileDriver;
24
use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
25
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
26
use Doctrine\ORM\Mapping\MappingException;
27
use Doctrine\ORM\Mapping\ClassMetadata as Metadata;
28
29
/**
30
 * XmlDriver is a metadata driver that enables mapping through XML files.
31
 *
32
 * @license 	http://www.opensource.org/licenses/mit-license.php MIT
33
 * @link    	www.doctrine-project.org
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 XmlDriver extends FileDriver
41
{
42
    const DEFAULT_FILE_EXTENSION = '.dcm.xml';
43
44
    /**
45
     * {@inheritDoc}
46
     */
47 43
    public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENSION)
48
    {
49 43
        parent::__construct($locator, $fileExtension);
50 43
    }
51
52
    /**
53
     * {@inheritDoc}
54
     */
55 38
    public function loadMetadataForClass($className, ClassMetadata $metadata)
56
    {
57
        /* @var $metadata \Doctrine\ORM\Mapping\ClassMetadataInfo */
58
        /* @var $xmlRoot SimpleXMLElement */
59 38
        $xmlRoot = $this->getElement($className);
60
61 36
        if ($xmlRoot->getName() == 'entity') {
62 35
            if (isset($xmlRoot['repository-class'])) {
63
                $metadata->setCustomRepositoryClass((string) $xmlRoot['repository-class']);
64
            }
65 35
            if (isset($xmlRoot['read-only']) && $this->evaluateBoolean($xmlRoot['read-only'])) {
66 35
                $metadata->markReadOnly();
67
            }
68 8
        } else if ($xmlRoot->getName() == 'mapped-superclass') {
69 5
            $metadata->setCustomRepositoryClass(
70 5
                isset($xmlRoot['repository-class']) ? (string) $xmlRoot['repository-class'] : null
71
            );
72 5
            $metadata->isMappedSuperclass = true;
73 3 View Code Duplication
        } else if ($xmlRoot->getName() == 'embeddable') {
74 3
            $metadata->isEmbeddedClass = true;
75
        } else {
76
            throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
77
        }
78
79
        // Evaluate <entity...> attributes
80 36
        $primaryTable = [];
81
82 36
        if (isset($xmlRoot['table'])) {
83 15
            $primaryTable['name'] = (string) $xmlRoot['table'];
84
        }
85
86 36
        if (isset($xmlRoot['schema'])) {
87 1
            $primaryTable['schema'] = (string) $xmlRoot['schema'];
88
        }
89
90 36
        $metadata->setPrimaryTable($primaryTable);
91
92
        // Evaluate second level cache
93 36
        if (isset($xmlRoot->cache)) {
94 2
            $metadata->enableCache($this->cacheToArray($xmlRoot->cache));
95
        }
96
97
        // Evaluate named queries
98 36
        if (isset($xmlRoot->{'named-queries'})) {
99 4
            foreach ($xmlRoot->{'named-queries'}->{'named-query'} as $namedQueryElement) {
100 4
                $metadata->addNamedQuery(
101
                    [
102 4
                        'name'  => (string) $namedQueryElement['name'],
103 4
                        'query' => (string) $namedQueryElement['query']
104
                    ]
105
                );
106
            }
107
        }
108
109
        // Evaluate native named queries
110 36
        if (isset($xmlRoot->{'named-native-queries'})) {
111 3
            foreach ($xmlRoot->{'named-native-queries'}->{'named-native-query'} as $nativeQueryElement) {
112 3
                $metadata->addNamedNativeQuery(
113
                    [
114 3
                        'name'              => isset($nativeQueryElement['name']) ? (string) $nativeQueryElement['name'] : null,
115 3
                        'query'             => isset($nativeQueryElement->query) ? (string) $nativeQueryElement->query : null,
116 3
                        'resultClass'       => isset($nativeQueryElement['result-class']) ? (string) $nativeQueryElement['result-class'] : null,
117 3
                        'resultSetMapping'  => isset($nativeQueryElement['result-set-mapping']) ? (string) $nativeQueryElement['result-set-mapping'] : null,
118
                    ]
119
                );
120
            }
121
        }
122
123
        // Evaluate sql result set mapping
124 36
        if (isset($xmlRoot->{'sql-result-set-mappings'})) {
125 3
            foreach ($xmlRoot->{'sql-result-set-mappings'}->{'sql-result-set-mapping'} as $rsmElement) {
126 3
                $entities   = [];
127 3
                $columns    = [];
128 3
                foreach ($rsmElement as $entityElement) {
129
                    //<entity-result/>
130 3
                    if (isset($entityElement['entity-class'])) {
131
                        $entityResult = [
132 3
                            'fields'                => [],
133 3
                            'entityClass'           => (string) $entityElement['entity-class'],
134 3
                            'discriminatorColumn'   => isset($entityElement['discriminator-column']) ? (string) $entityElement['discriminator-column'] : null,
135
                        ];
136
137 3 View Code Duplication
                        foreach ($entityElement as $fieldElement) {
138 3
                            $entityResult['fields'][] = [
139 3
                                'name'      => isset($fieldElement['name']) ? (string) $fieldElement['name'] : null,
140 3
                                'column'    => isset($fieldElement['column']) ? (string) $fieldElement['column'] : null,
141
                            ];
142
                        }
143
144 3
                        $entities[] = $entityResult;
145
                    }
146
147
                    //<column-result/>
148 3
                    if (isset($entityElement['name'])) {
149 3
                        $columns[] = [
150 3
                            'name' => (string) $entityElement['name'],
151
                        ];
152
                    }
153
                }
154
155 3
                $metadata->addSqlResultSetMapping(
156
                    [
157 3
                        'name'          => (string) $rsmElement['name'],
158 3
                        'entities'      => $entities,
159 3
                        'columns'       => $columns
160
                    ]
161
                );
162
            }
163
        }
164
165 36
        if (isset($xmlRoot['inheritance-type'])) {
166 10
            $inheritanceType = (string) $xmlRoot['inheritance-type'];
167 10
            $metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . $inheritanceType));
168
169 10
            if ($metadata->inheritanceType != Metadata::INHERITANCE_TYPE_NONE) {
170
                // Evaluate <discriminator-column...>
171 10 View Code Duplication
                if (isset($xmlRoot->{'discriminator-column'})) {
172 7
                    $discrColumn = $xmlRoot->{'discriminator-column'};
173 7
                    $metadata->setDiscriminatorColumn(
174
                        [
175 7
                            'name' => isset($discrColumn['name']) ? (string) $discrColumn['name'] : null,
176 7
                            'type' => isset($discrColumn['type']) ? (string) $discrColumn['type'] : 'string',
177 7
                            'length' => isset($discrColumn['length']) ? (string) $discrColumn['length'] : 255,
178 7
                            'columnDefinition' => isset($discrColumn['column-definition']) ? (string) $discrColumn['column-definition'] : null
179
                        ]
180
                    );
181
                } else {
182 6
                    $metadata->setDiscriminatorColumn(['name' => 'dtype', 'type' => 'string', 'length' => 255]);
183
                }
184
185
                // Evaluate <discriminator-map...>
186 10
                if (isset($xmlRoot->{'discriminator-map'})) {
187 10
                    $map = [];
188 10
                    foreach ($xmlRoot->{'discriminator-map'}->{'discriminator-mapping'} as $discrMapElement) {
189 10
                        $map[(string) $discrMapElement['value']] = (string) $discrMapElement['class'];
190
                    }
191 10
                    $metadata->setDiscriminatorMap($map);
192
                }
193
            }
194
        }
195
196
197
        // Evaluate <change-tracking-policy...>
198 36 View Code Duplication
        if (isset($xmlRoot['change-tracking-policy'])) {
199
            $metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_'
200
                . strtoupper((string) $xmlRoot['change-tracking-policy'])));
201
        }
202
203
        // Evaluate <indexes...>
204 36
        if (isset($xmlRoot->indexes)) {
205 4
            $metadata->table['indexes'] = [];
206 4
            foreach ($xmlRoot->indexes->index as $indexXml) {
207 4
                $index = ['columns' => explode(',', (string) $indexXml['columns'])];
208
209 4
                if (isset($indexXml['flags'])) {
210 1
                    $index['flags'] = explode(',', (string) $indexXml['flags']);
211
                }
212
213 4
                if (isset($indexXml->options)) {
214 1
                    $index['options'] = $this->_parseOptions($indexXml->options->children());
215
                }
216
217 4
                if (isset($indexXml['name'])) {
218 3
                    $metadata->table['indexes'][(string) $indexXml['name']] = $index;
219
                } else {
220 4
                    $metadata->table['indexes'][] = $index;
221
                }
222
            }
223
        }
224
225
        // Evaluate <unique-constraints..>
226 36
        if (isset($xmlRoot->{'unique-constraints'})) {
227 3
            $metadata->table['uniqueConstraints'] = [];
228 3
            foreach ($xmlRoot->{'unique-constraints'}->{'unique-constraint'} as $uniqueXml) {
229 3
                $unique = ['columns' => explode(',', (string) $uniqueXml['columns'])];
230
231 3
                if (isset($uniqueXml->options)) {
232 3
                    $unique['options'] = $this->_parseOptions($uniqueXml->options->children());
233
                }
234
235 3
                if (isset($uniqueXml['name'])) {
236 3
                    $metadata->table['uniqueConstraints'][(string) $uniqueXml['name']] = $unique;
237
                } else {
238 3
                    $metadata->table['uniqueConstraints'][] = $unique;
239
                }
240
            }
241
        }
242
243 36
        if (isset($xmlRoot->options)) {
244 5
            $metadata->table['options'] = $this->_parseOptions($xmlRoot->options->children());
245
        }
246
247
        // The mapping assignment is done in 2 times as a bug might occurs on some php/xml lib versions
248
        // The internal SimpleXmlIterator get resetted, to this generate a duplicate field exception
249 36
        $mappings = [];
250
        // Evaluate <field ...> mappings
251 36
        if (isset($xmlRoot->field)) {
252 24
            foreach ($xmlRoot->field as $fieldMapping) {
253 24
                $mapping = $this->columnToArray($fieldMapping);
254
255 24
                if (isset($mapping['version'])) {
256 3
                    $metadata->setVersionMapping($mapping);
257 3
                    unset($mapping['version']);
258
                }
259
260 24
                $metadata->mapField($mapping);
261
            }
262
        }
263
264 36
        if (isset($xmlRoot->embedded)) {
265 3
            foreach ($xmlRoot->embedded as $embeddedMapping) {
266 3
                $columnPrefix = isset($embeddedMapping['column-prefix'])
267 3
                    ? (string) $embeddedMapping['column-prefix']
268 3
                    : null;
269
270 3
                $useColumnPrefix = isset($embeddedMapping['use-column-prefix'])
271 2
                    ? $this->evaluateBoolean($embeddedMapping['use-column-prefix'])
272 3
                    : true;
273
274
                $mapping = [
275 3
                    'fieldName' => (string) $embeddedMapping['name'],
276 3
                    'class' => (string) $embeddedMapping['class'],
277 3
                    'columnPrefix' => $useColumnPrefix ? $columnPrefix : false
278
                ];
279
280 3
                $metadata->mapEmbedded($mapping);
281
            }
282
        }
283
284 36
        foreach ($mappings as $mapping) {
285
            if (isset($mapping['version'])) {
286
                $metadata->setVersionMapping($mapping);
287
            }
288
289
            $metadata->mapField($mapping);
290
        }
291
292
        // Evaluate <id ...> mappings
293 36
        $associationIds = [];
294 36
        foreach ($xmlRoot->id as $idElement) {
295 33
            if (isset($idElement['association-key']) && $this->evaluateBoolean($idElement['association-key'])) {
296 2
                $associationIds[(string) $idElement['name']] = true;
297 2
                continue;
298
            }
299
300
            $mapping = [
301 32
                'id' => true,
302 32
                'fieldName' => (string) $idElement['name']
303
            ];
304
305 32
            if (isset($idElement['type'])) {
306 21
                $mapping['type'] = (string) $idElement['type'];
307
            }
308
309 32
            if (isset($idElement['length'])) {
310 3
                $mapping['length'] = (string) $idElement['length'];
311
            }
312
313 32
            if (isset($idElement['column'])) {
314 23
                $mapping['columnName'] = (string) $idElement['column'];
315
            }
316
317 32
            if (isset($idElement['column-definition'])) {
318 1
                $mapping['columnDefinition'] = (string) $idElement['column-definition'];
319
            }
320
321 32
            if (isset($idElement->options)) {
322 3
                $mapping['options'] = $this->_parseOptions($idElement->options->children());
323
            }
324
325 32
            $metadata->mapField($mapping);
326
327 32
            if (isset($idElement->generator)) {
328 31
                $strategy = isset($idElement->generator['strategy']) ?
329 31
                        (string) $idElement->generator['strategy'] : 'AUTO';
330 31
                $metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_'
331 31
                    . $strategy));
332
            }
333
334
            // Check for SequenceGenerator/TableGenerator definition
335 32
            if (isset($idElement->{'sequence-generator'})) {
336 3
                $seqGenerator = $idElement->{'sequence-generator'};
337 3
                $metadata->setSequenceGeneratorDefinition(
338
                    [
339 3
                        'sequenceName' => (string) $seqGenerator['sequence-name'],
340 3
                        'allocationSize' => (string) $seqGenerator['allocation-size'],
341 3
                        'initialValue' => (string) $seqGenerator['initial-value']
342
                    ]
343
                );
344 29
            } else if (isset($idElement->{'custom-id-generator'})) {
345 2
                $customGenerator = $idElement->{'custom-id-generator'};
346 2
                $metadata->setCustomGeneratorDefinition(
347
                    [
348 2
                        'class' => (string) $customGenerator['class']
349
                    ]
350
                );
351 27
            } else if (isset($idElement->{'table-generator'})) {
352 32
                throw MappingException::tableIdGeneratorNotImplemented($className);
353
            }
354
        }
355
356
        // Evaluate <one-to-one ...> mappings
357 36
        if (isset($xmlRoot->{'one-to-one'})) {
358 8
            foreach ($xmlRoot->{'one-to-one'} as $oneToOneElement) {
359
                $mapping = [
360 8
                    'fieldName' => (string) $oneToOneElement['field'],
361 8
                    'targetEntity' => (string) $oneToOneElement['target-entity']
362
                ];
363
364 8
                if (isset($associationIds[$mapping['fieldName']])) {
365
                    $mapping['id'] = true;
366
                }
367
368 8 View Code Duplication
                if (isset($oneToOneElement['fetch'])) {
369 2
                    $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string) $oneToOneElement['fetch']);
370
                }
371
372 8
                if (isset($oneToOneElement['mapped-by'])) {
373 2
                    $mapping['mappedBy'] = (string) $oneToOneElement['mapped-by'];
374
                } else {
375 8
                    if (isset($oneToOneElement['inversed-by'])) {
376 8
                        $mapping['inversedBy'] = (string) $oneToOneElement['inversed-by'];
377
                    }
378 8
                    $joinColumns = [];
379
380 8 View Code Duplication
                    if (isset($oneToOneElement->{'join-column'})) {
381 7
                        $joinColumns[] = $this->joinColumnToArray($oneToOneElement->{'join-column'});
382 1
                    } else if (isset($oneToOneElement->{'join-columns'})) {
383 1
                        foreach ($oneToOneElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
384 1
                            $joinColumns[] = $this->joinColumnToArray($joinColumnElement);
385
                        }
386
                    }
387
388 8
                    $mapping['joinColumns'] = $joinColumns;
389
                }
390
391 8
                if (isset($oneToOneElement->cascade)) {
392 6
                    $mapping['cascade'] = $this->_getCascadeMappings($oneToOneElement->cascade);
393
                }
394
395 8
                if (isset($oneToOneElement['orphan-removal'])) {
396 3
                    $mapping['orphanRemoval'] = $this->evaluateBoolean($oneToOneElement['orphan-removal']);
397
                }
398
399
                // Evaluate second level cache
400 8 View Code Duplication
                if (isset($oneToOneElement->cache)) {
401
                    $mapping['cache'] = $metadata->getAssociationCacheDefaults($mapping['fieldName'], $this->cacheToArray($oneToOneElement->cache));
402
                }
403
404 8
                $metadata->mapOneToOne($mapping);
405
            }
406
        }
407
408
        // Evaluate <one-to-many ...> mappings
409 36
        if (isset($xmlRoot->{'one-to-many'})) {
410 8
            foreach ($xmlRoot->{'one-to-many'} as $oneToManyElement) {
411
                $mapping = [
412 8
                    'fieldName' => (string) $oneToManyElement['field'],
413 8
                    'targetEntity' => (string) $oneToManyElement['target-entity'],
414 8
                    'mappedBy' => (string) $oneToManyElement['mapped-by']
415
                ];
416
417 8 View Code Duplication
                if (isset($oneToManyElement['fetch'])) {
418 2
                    $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string) $oneToManyElement['fetch']);
419
                }
420
421 8
                if (isset($oneToManyElement->cascade)) {
422 6
                    $mapping['cascade'] = $this->_getCascadeMappings($oneToManyElement->cascade);
423
                }
424
425 8
                if (isset($oneToManyElement['orphan-removal'])) {
426 6
                    $mapping['orphanRemoval'] = $this->evaluateBoolean($oneToManyElement['orphan-removal']);
427
                }
428
429 8 View Code Duplication
                if (isset($oneToManyElement->{'order-by'})) {
430 6
                    $orderBy = [];
431 6
                    foreach ($oneToManyElement->{'order-by'}->{'order-by-field'} as $orderByField) {
432 6
                        $orderBy[(string) $orderByField['name']] = (string) $orderByField['direction'];
433
                    }
434 6
                    $mapping['orderBy'] = $orderBy;
435
                }
436
437 8 View Code Duplication
                if (isset($oneToManyElement['index-by'])) {
438 3
                    $mapping['indexBy'] = (string) $oneToManyElement['index-by'];
439 5
                } else if (isset($oneToManyElement->{'index-by'})) {
440
                    throw new \InvalidArgumentException("<index-by /> is not a valid tag");
441
                }
442
443
                // Evaluate second level cache
444 8 View Code Duplication
                if (isset($oneToManyElement->cache)) {
445 1
                    $mapping['cache'] = $metadata->getAssociationCacheDefaults($mapping['fieldName'], $this->cacheToArray($oneToManyElement->cache));
446
                }
447
448 8
                $metadata->mapOneToMany($mapping);
449
            }
450
        }
451
452
        // Evaluate <many-to-one ...> mappings
453 36
        if (isset($xmlRoot->{'many-to-one'})) {
454 7
            foreach ($xmlRoot->{'many-to-one'} as $manyToOneElement) {
455
                $mapping = [
456 7
                    'fieldName' => (string) $manyToOneElement['field'],
457 7
                    'targetEntity' => (string) $manyToOneElement['target-entity']
458
                ];
459
460 7
                if (isset($associationIds[$mapping['fieldName']])) {
461 2
                    $mapping['id'] = true;
462
                }
463
464 7 View Code Duplication
                if (isset($manyToOneElement['fetch'])) {
465 1
                    $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string) $manyToOneElement['fetch']);
466
                }
467
468 7
                if (isset($manyToOneElement['inversed-by'])) {
469 1
                    $mapping['inversedBy'] = (string) $manyToOneElement['inversed-by'];
470
                }
471
472 7
                $joinColumns = [];
473
474 7 View Code Duplication
                if (isset($manyToOneElement->{'join-column'})) {
475 4
                    $joinColumns[] = $this->joinColumnToArray($manyToOneElement->{'join-column'});
476 3
                } else if (isset($manyToOneElement->{'join-columns'})) {
477 2
                    foreach ($manyToOneElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
478 2
                        $joinColumns[] = $this->joinColumnToArray($joinColumnElement);
479
                    }
480
                }
481
482 7
                $mapping['joinColumns'] = $joinColumns;
483
484 7
                if (isset($manyToOneElement->cascade)) {
485 2
                    $mapping['cascade'] = $this->_getCascadeMappings($manyToOneElement->cascade);
486
                }
487
488
                // Evaluate second level cache
489 7 View Code Duplication
                if (isset($manyToOneElement->cache)) {
490 1
                    $mapping['cache'] = $metadata->getAssociationCacheDefaults($mapping['fieldName'], $this->cacheToArray($manyToOneElement->cache));
491
                }
492
493 7
                $metadata->mapManyToOne($mapping);
494
495
            }
496
        }
497
498
        // Evaluate <many-to-many ...> mappings
499 35
        if (isset($xmlRoot->{'many-to-many'})) {
500 12
            foreach ($xmlRoot->{'many-to-many'} as $manyToManyElement) {
501
                $mapping = [
502 12
                    'fieldName' => (string) $manyToManyElement['field'],
503 12
                    'targetEntity' => (string) $manyToManyElement['target-entity']
504
                ];
505
506 12 View Code Duplication
                if (isset($manyToManyElement['fetch'])) {
507 3
                    $mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . (string) $manyToManyElement['fetch']);
508
                }
509
510 12
                if (isset($manyToManyElement['orphan-removal'])) {
511
                    $mapping['orphanRemoval'] = $this->evaluateBoolean($manyToManyElement['orphan-removal']);
512
                }
513
514 12
                if (isset($manyToManyElement['mapped-by'])) {
515 2
                    $mapping['mappedBy'] = (string) $manyToManyElement['mapped-by'];
516 10
                } else if (isset($manyToManyElement->{'join-table'})) {
517 8
                    if (isset($manyToManyElement['inversed-by'])) {
518 2
                        $mapping['inversedBy'] = (string) $manyToManyElement['inversed-by'];
519
                    }
520
521 8
                    $joinTableElement = $manyToManyElement->{'join-table'};
522
                    $joinTable = [
523 8
                        'name' => (string) $joinTableElement['name']
524
                    ];
525
526 8
                    if (isset($joinTableElement['schema'])) {
527
                        $joinTable['schema'] = (string) $joinTableElement['schema'];
528
                    }
529
530 8
                    foreach ($joinTableElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
531 8
                        $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement);
532
                    }
533
534 8
                    foreach ($joinTableElement->{'inverse-join-columns'}->{'join-column'} as $joinColumnElement) {
535 8
                        $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement);
536
                    }
537
538 8
                    $mapping['joinTable'] = $joinTable;
539
                }
540
541 12
                if (isset($manyToManyElement->cascade)) {
542 8
                    $mapping['cascade'] = $this->_getCascadeMappings($manyToManyElement->cascade);
543
                }
544
545 12 View Code Duplication
                if (isset($manyToManyElement->{'order-by'})) {
546
                    $orderBy = [];
547
                    foreach ($manyToManyElement->{'order-by'}->{'order-by-field'} as $orderByField) {
548
                        $orderBy[(string) $orderByField['name']] = (string) $orderByField['direction'];
549
                    }
550
                    $mapping['orderBy'] = $orderBy;
551
                }
552
553 12 View Code Duplication
                if (isset($manyToManyElement['index-by'])) {
554
                    $mapping['indexBy'] = (string) $manyToManyElement['index-by'];
555 12
                } else if (isset($manyToManyElement->{'index-by'})) {
556
                    throw new \InvalidArgumentException("<index-by /> is not a valid tag");
557
                }
558
559
                // Evaluate second level cache
560 12 View Code Duplication
                if (isset($manyToManyElement->cache)) {
561
                    $mapping['cache'] = $metadata->getAssociationCacheDefaults($mapping['fieldName'], $this->cacheToArray($manyToManyElement->cache));
562
                }
563
564 12
                $metadata->mapManyToMany($mapping);
565
            }
566
        }
567
568
        // Evaluate association-overrides
569 35
        if (isset($xmlRoot->{'attribute-overrides'})) {
570 2
            foreach ($xmlRoot->{'attribute-overrides'}->{'attribute-override'} as $overrideElement) {
571 2
                $fieldName = (string) $overrideElement['name'];
572 2
                foreach ($overrideElement->field as $field) {
573 2
                    $mapping = $this->columnToArray($field);
574 2
                    $mapping['fieldName'] = $fieldName;
575 2
                    $metadata->setAttributeOverride($fieldName, $mapping);
576
                }
577
            }
578
        }
579
580
        // Evaluate association-overrides
581 35
        if (isset($xmlRoot->{'association-overrides'})) {
582 4
            foreach ($xmlRoot->{'association-overrides'}->{'association-override'} as $overrideElement) {
583 4
                $fieldName  = (string) $overrideElement['name'];
584 4
                $override   = [];
585
586
                // Check for join-columns
587 4
                if (isset($overrideElement->{'join-columns'})) {
588 2
                    $joinColumns = [];
589 2
                    foreach ($overrideElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
590 2
                        $joinColumns[] = $this->joinColumnToArray($joinColumnElement);
591
                    }
592 2
                    $override['joinColumns'] = $joinColumns;
593
                }
594
595
                // Check for join-table
596 4
                if ($overrideElement->{'join-table'}) {
597 2
                    $joinTable          = null;
598 2
                    $joinTableElement   = $overrideElement->{'join-table'};
599
600
                    $joinTable = [
601 2
                        'name'      => (string) $joinTableElement['name'],
602 2
                        'schema'    => (string) $joinTableElement['schema']
603
                    ];
604
605 2
                    if (isset($joinTableElement->{'join-columns'})) {
606 2
                        foreach ($joinTableElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
607 2
                            $joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement);
608
                        }
609
                    }
610
611 2
                    if (isset($joinTableElement->{'inverse-join-columns'})) {
612 2
                        foreach ($joinTableElement->{'inverse-join-columns'}->{'join-column'} as $joinColumnElement) {
613 2
                            $joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement);
614
                        }
615
                    }
616
617 2
                    $override['joinTable'] = $joinTable;
618
                }
619
620
                // Check for inversed-by
621 4
                if (isset($overrideElement->{'inversed-by'})) {
622 1
                    $override['inversedBy'] = (string) $overrideElement->{'inversed-by'}['name'];
623
                }
624
625
                // Check for `fetch`
626 4 View Code Duplication
                if (isset($overrideElement['fetch'])) {
627 1
                    $override['fetch'] = constant(Metadata::class . '::FETCH_' . (string) $overrideElement['fetch']);
628
                }
629
630 4
                $metadata->setAssociationOverride($fieldName, $override);
631
            }
632
        }
633
634
        // Evaluate <lifecycle-callbacks...>
635 35
        if (isset($xmlRoot->{'lifecycle-callbacks'})) {
636 5
            foreach ($xmlRoot->{'lifecycle-callbacks'}->{'lifecycle-callback'} as $lifecycleCallback) {
637 5
                $metadata->addLifecycleCallback((string) $lifecycleCallback['method'], constant('Doctrine\ORM\Events::' . (string) $lifecycleCallback['type']));
638
            }
639
        }
640
641
        // Evaluate entity listener
642 35
        if (isset($xmlRoot->{'entity-listeners'})) {
643 4
            foreach ($xmlRoot->{'entity-listeners'}->{'entity-listener'} as $listenerElement) {
644 4
                $className = (string) $listenerElement['class'];
645
                // Evaluate the listener using naming convention.
646 4
                if ($listenerElement->count() === 0) {
647 2
                    EntityListenerBuilder::bindEntityListener($metadata, $className);
648
649 2
                    continue;
650
                }
651
652 2
                foreach ($listenerElement as $callbackElement) {
653 2
                    $eventName   = (string) $callbackElement['type'];
654 2
                    $methodName  = (string) $callbackElement['method'];
655
656 2
                    $metadata->addEntityListener($eventName, $className, $methodName);
657
                }
658
            }
659
        }
660 35
    }
661
662
    /**
663
     * Parses (nested) option elements.
664
     *
665
     * @param SimpleXMLElement $options The XML element.
666
     *
667
     * @return array The options array.
668
     */
669 6
    private function _parseOptions(SimpleXMLElement $options)
670
    {
671 6
        $array = [];
672
673
        /* @var $option SimpleXMLElement */
674 6
        foreach ($options as $option) {
675 6
            if ($option->count()) {
676 5
                $value = $this->_parseOptions($option->children());
677
            } else {
678 6
                $value = (string) $option;
679
            }
680
681 6
            $attributes = $option->attributes();
682
683 6
            if (isset($attributes->name)) {
684 6
                $nameAttribute = (string) $attributes->name;
685 6
                $array[$nameAttribute] = in_array($nameAttribute, ['unsigned', 'fixed'])
686 5
                    ? $this->evaluateBoolean($value)
687 6
                    : $value;
688
            } else {
689 6
                $array[] = $value;
690
            }
691
        }
692
693 6
        return $array;
694
    }
695
696
    /**
697
     * Constructs a joinColumn mapping array based on the information
698
     * found in the given SimpleXMLElement.
699
     *
700
     * @param SimpleXMLElement $joinColumnElement The XML element.
701
     *
702
     * @return array The mapping array.
703
     */
704 13
    private function joinColumnToArray(SimpleXMLElement $joinColumnElement)
705
    {
706
        $joinColumn = [
707 13
            'name' => (string) $joinColumnElement['name'],
708 13
            'referencedColumnName' => (string) $joinColumnElement['referenced-column-name']
709
        ];
710
711 13
        if (isset($joinColumnElement['unique'])) {
712 4
            $joinColumn['unique'] = $this->evaluateBoolean($joinColumnElement['unique']);
713
        }
714
715 13
        if (isset($joinColumnElement['nullable'])) {
716 6
            $joinColumn['nullable'] = $this->evaluateBoolean($joinColumnElement['nullable']);
717
        }
718
719 13
        if (isset($joinColumnElement['on-delete'])) {
720 5
            $joinColumn['onDelete'] = (string) $joinColumnElement['on-delete'];
721
        }
722
723 13
        if (isset($joinColumnElement['column-definition'])) {
724 5
            $joinColumn['columnDefinition'] = (string) $joinColumnElement['column-definition'];
725
        }
726
727 13
        return $joinColumn;
728
    }
729
730
     /**
731
     * Parses the given field as array.
732
     *
733
     * @param SimpleXMLElement $fieldMapping
734
     *
735
     * @return array
736
     */
737 24
    private function columnToArray(SimpleXMLElement $fieldMapping)
738
    {
739
        $mapping = [
740 24
            'fieldName' => (string) $fieldMapping['name'],
741
        ];
742
743 24
        if (isset($fieldMapping['type'])) {
744 20
            $mapping['type'] = (string) $fieldMapping['type'];
745
        }
746
747 24
        if (isset($fieldMapping['column'])) {
748 16
            $mapping['columnName'] = (string) $fieldMapping['column'];
749
        }
750
751 24
        if (isset($fieldMapping['length'])) {
752 11
            $mapping['length'] = (int) $fieldMapping['length'];
753
        }
754
755 24
        if (isset($fieldMapping['precision'])) {
756 1
            $mapping['precision'] = (int) $fieldMapping['precision'];
757
        }
758
759 24
        if (isset($fieldMapping['scale'])) {
760 1
            $mapping['scale'] = (int) $fieldMapping['scale'];
761
        }
762
763 24
        if (isset($fieldMapping['unique'])) {
764 10
            $mapping['unique'] = $this->evaluateBoolean($fieldMapping['unique']);
765
        }
766
767 24
        if (isset($fieldMapping['nullable'])) {
768 9
            $mapping['nullable'] = $this->evaluateBoolean($fieldMapping['nullable']);
769
        }
770
771 24
        if (isset($fieldMapping['version']) && $fieldMapping['version']) {
772 3
            $mapping['version'] = $this->evaluateBoolean($fieldMapping['version']);
773
        }
774
775 24
        if (isset($fieldMapping['column-definition'])) {
776 6
            $mapping['columnDefinition'] = (string) $fieldMapping['column-definition'];
777
        }
778
779 24
        if (isset($fieldMapping->options)) {
780 5
            $mapping['options'] = $this->_parseOptions($fieldMapping->options->children());
781
        }
782
783 24
        return $mapping;
784
    }
785
786
    /**
787
     * Parse / Normalize the cache configuration
788
     *
789
     * @param SimpleXMLElement $cacheMapping
790
     *
791
     * @return array
792
     */
793 2 View Code Duplication
    private function cacheToArray(SimpleXMLElement $cacheMapping)
794
    {
795 2
        $region = isset($cacheMapping['region']) ? (string) $cacheMapping['region'] : null;
796 2
        $usage  = isset($cacheMapping['usage']) ? strtoupper($cacheMapping['usage']) : null;
797
798 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...
799
            throw new \InvalidArgumentException(sprintf('Invalid cache usage "%s"', $usage));
800
        }
801
802 2
        if ($usage) {
803 2
            $usage = constant('Doctrine\ORM\Mapping\ClassMetadata::CACHE_USAGE_' . $usage);
804
        }
805
806
        return [
807 2
            'usage'  => $usage,
808 2
            'region' => $region,
809
        ];
810
    }
811
812
    /**
813
     * Gathers a list of cascade options found in the given cascade element.
814
     *
815
     * @param SimpleXMLElement $cascadeElement The cascade element.
816
     *
817
     * @return array The list of cascade options.
818
     */
819 8
    private function _getCascadeMappings(SimpleXMLElement $cascadeElement)
820
    {
821 8
        $cascades = [];
822
        /* @var $action SimpleXmlElement */
823 8
        foreach ($cascadeElement->children() as $action) {
824
            // According to the JPA specifications, XML uses "cascade-persist"
825
            // instead of "persist". Here, both variations
826
            // are supported because both YAML and Annotation use "persist"
827
            // and we want to make sure that this driver doesn't need to know
828
            // anything about the supported cascading actions
829 8
            $cascades[] = str_replace('cascade-', '', $action->getName());
830
        }
831
832 8
        return $cascades;
833
    }
834
835
    /**
836
     * {@inheritDoc}
837
     */
838 38
    protected function loadMappingFile($file)
839
    {
840 38
        $result = [];
841 38
        $xmlElement = simplexml_load_file($file);
842
843 38
        if (isset($xmlElement->entity)) {
844 36
            foreach ($xmlElement->entity as $entityElement) {
845 36
                $entityName = (string) $entityElement['name'];
846 36
                $result[$entityName] = $entityElement;
847
            }
848 9
        } else if (isset($xmlElement->{'mapped-superclass'})) {
849 5
            foreach ($xmlElement->{'mapped-superclass'} as $mappedSuperClass) {
850 5
                $className = (string) $mappedSuperClass['name'];
851 5
                $result[$className] = $mappedSuperClass;
852
            }
853 4
        } else if (isset($xmlElement->embeddable)) {
854 3
            foreach ($xmlElement->embeddable as $embeddableElement) {
855 3
                $embeddableName = (string) $embeddableElement['name'];
856 3
                $result[$embeddableName] = $embeddableElement;
857
            }
858
        }
859
860 38
        return $result;
861
    }
862
863
    /**
864
     * @param mixed $element
865
     *
866
     * @return bool
867
     */
868 14
    protected function evaluateBoolean($element)
869
    {
870 14
        $flag = (string) $element;
871
872 14
        return ($flag == "true" || $flag == "1");
873
    }
874
}
875