Completed
Pull Request — master (#1790)
by Andreas
17:11 queued 06:37
created

XmlDriver::addGridFSMappings()   B

Complexity

Conditions 6
Paths 9

Size

Total Lines 25
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 6.105

Importance

Changes 0
Metric Value
dl 0
loc 25
ccs 12
cts 14
cp 0.8571
rs 8.439
c 0
b 0
f 0
cc 6
eloc 13
nc 9
nop 2
crap 6.105
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ODM\MongoDB\Mapping\Driver;
6
7
use Doctrine\Common\Persistence\Mapping\Driver\FileDriver;
8
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
9
use Doctrine\ODM\MongoDB\Utility\CollectionHelper;
10
use function array_keys;
11
use function constant;
12
use function count;
13
use function current;
14
use function explode;
15
use function in_array;
16
use function is_numeric;
17
use function iterator_to_array;
18
use function next;
19
use function preg_match;
20
use function simplexml_load_file;
21
use function strtoupper;
22
use function trim;
23
24
/**
25
 * XmlDriver is a metadata driver that enables mapping through XML files.
26
 *
27
 */
28
class XmlDriver extends FileDriver
29
{
30
    public const DEFAULT_FILE_EXTENSION = '.dcm.xml';
31
32
    private const DEFAULT_GRIDFS_MAPPINGS = [
33
        'length' => [
34
            'name' => 'length',
35
            'type' => 'int',
36
            'notSaved' => true,
37
        ],
38
        'chunk-size' => [
39
            'name' => 'chunkSize',
40
            'type' => 'int',
41
            'notSaved' => true,
42
        ],
43
        'filename' => [
44
            'name' => 'filename',
45
            'type' => 'string',
46
            'notSaved' => true,
47
        ],
48
        'upload-date' => [
49
            'name' => 'uploadDate',
50
            'type' => 'date',
51
            'notSaved' => true,
52
        ],
53
    ];
54
55
    /**
56
     * {@inheritDoc}
57
     */
58 14
    public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENSION)
59
    {
60 14
        parent::__construct($locator, $fileExtension);
61 14
    }
62
63
    /**
64
     * {@inheritDoc}
65
     */
66 8
    public function loadMetadataForClass($className, \Doctrine\Common\Persistence\Mapping\ClassMetadata $class)
67
    {
68
        /** @var ClassMetadata $class */
69
        /** @var \SimpleXMLElement $xmlRoot */
70 8
        $xmlRoot = $this->getElement($className);
71 8
        if (! $xmlRoot) {
72
            return;
73
        }
74
75 8
        if ($xmlRoot->getName() === 'document') {
76 7
            if (isset($xmlRoot['repository-class'])) {
77 7
                $class->setCustomRepositoryClass((string) $xmlRoot['repository-class']);
78
            }
79 3
        } elseif ($xmlRoot->getName() === 'mapped-superclass') {
80 1
            $class->setCustomRepositoryClass(
81 1
                isset($xmlRoot['repository-class']) ? (string) $xmlRoot['repository-class'] : null
82
            );
83 1
            $class->isMappedSuperclass = true;
84 2
        } elseif ($xmlRoot->getName() === 'embedded-document') {
85 1
            $class->isEmbeddedDocument = true;
86 2
        } elseif ($xmlRoot->getName() === 'query-result-document') {
87 1
            $class->isQueryResultDocument = true;
88 1
        } elseif ($xmlRoot->getName() === 'gridfs-file') {
89 1
            $class->isFile = true;
90
        }
91
92 8
        if (isset($xmlRoot['db'])) {
93 4
            $class->setDatabase((string) $xmlRoot['db']);
94
        }
95
96 8
        if (isset($xmlRoot['collection'])) {
97 6
            if (isset($xmlRoot['capped-collection'])) {
98
                $config = ['name' => (string) $xmlRoot['collection']];
99
                $config['capped'] = (bool) $xmlRoot['capped-collection'];
100
                if (isset($xmlRoot['capped-collection-max'])) {
101
                    $config['max'] = (int) $xmlRoot['capped-collection-max'];
102
                }
103
                if (isset($xmlRoot['capped-collection-size'])) {
104
                    $config['size'] = (int) $xmlRoot['capped-collection-size'];
105
                }
106
                $class->setCollection($config);
107
            } else {
108 6
                $class->setCollection((string) $xmlRoot['collection']);
109
            }
110
        }
111 8
        if (isset($xmlRoot['bucket-name'])) {
112
            $class->setBucketName((string) $xmlRoot['bucket-name']);
113
        }
114 8
        if (isset($xmlRoot['writeConcern'])) {
115
            $class->setWriteConcern((string) $xmlRoot['writeConcern']);
116
        }
117 8
        if (isset($xmlRoot['inheritance-type'])) {
118
            $inheritanceType = (string) $xmlRoot['inheritance-type'];
119
            $class->setInheritanceType(constant(ClassMetadata::class . '::INHERITANCE_TYPE_' . $inheritanceType));
120
        }
121 8
        if (isset($xmlRoot['change-tracking-policy'])) {
122 1
            $class->setChangeTrackingPolicy(constant(ClassMetadata::class . '::CHANGETRACKING_' . strtoupper((string) $xmlRoot['change-tracking-policy'])));
123
        }
124 8
        if (isset($xmlRoot->{'discriminator-field'})) {
125
            $discrField = $xmlRoot->{'discriminator-field'};
126
            /* XSD only allows for "name", which is consistent with association
127
             * configurations, but fall back to "fieldName" for BC.
128
             */
129
            $class->setDiscriminatorField(
130
                (string) ($discrField['name'] ?? $discrField['fieldName'])
131
            );
132
        }
133 8
        if (isset($xmlRoot->{'discriminator-map'})) {
134
            $map = [];
135
            foreach ($xmlRoot->{'discriminator-map'}->{'discriminator-mapping'} as $discrMapElement) {
136
                $map[(string) $discrMapElement['value']] = (string) $discrMapElement['class'];
137
            }
138
            $class->setDiscriminatorMap($map);
139
        }
140 8
        if (isset($xmlRoot->{'default-discriminator-value'})) {
141
            $class->setDefaultDiscriminatorValue((string) $xmlRoot->{'default-discriminator-value'}['value']);
142
        }
143 8
        if (isset($xmlRoot->{'indexes'})) {
144 2
            foreach ($xmlRoot->{'indexes'}->{'index'} as $index) {
145 2
                $this->addIndex($class, $index);
146
            }
147
        }
148 8
        if (isset($xmlRoot->{'shard-key'})) {
149
            $this->setShardKey($class, $xmlRoot->{'shard-key'}[0]);
150
        }
151 8
        if (isset($xmlRoot['read-only']) && (string) $xmlRoot['read-only'] === 'true') {
152
            $class->markReadOnly();
153
        }
154 8
        if (isset($xmlRoot->{'read-preference'})) {
155
            $class->setReadPreference(...$this->transformReadPreference($xmlRoot->{'read-preference'}));
156
        }
157
158 8
        if (isset($xmlRoot->id)) {
159 8
            $field = $xmlRoot->id;
0 ignored issues
show
Bug introduced by
The property id does not seem to exist in SimpleXMLElement.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
160
            $mapping = [
161 8
                'id' => true,
162
                'fieldName' => 'id',
163
            ];
164
165 8
            $attributes = $field->attributes();
166 8
            foreach ($attributes as $key => $value) {
167 2
                $mapping[$key] = (string) $value;
168
            }
169
170 8
            if (isset($mapping['strategy'])) {
171 2
                $mapping['options'] = [];
172 2
                if (isset($field->{'generator-option'})) {
173 1
                    foreach ($field->{'generator-option'} as $generatorOptions) {
174 1
                        $attributesGenerator = iterator_to_array($generatorOptions->attributes());
175 1
                        if (! isset($attributesGenerator['name']) || ! isset($attributesGenerator['value'])) {
176
                            continue;
177
                        }
178
179 1
                        $mapping['options'][(string) $attributesGenerator['name']] = (string) $attributesGenerator['value'];
180
                    }
181
                }
182
            }
183
184 8
            $this->addFieldMapping($class, $mapping);
185
        }
186
187 8
        if (isset($xmlRoot->field)) {
188 2
            foreach ($xmlRoot->field as $field) {
189 2
                $mapping = [];
190 2
                $attributes = $field->attributes();
191 2
                foreach ($attributes as $key => $value) {
192 2
                    $mapping[$key] = (string) $value;
193 2
                    $booleanAttributes = ['id', 'reference', 'embed', 'unique', 'sparse'];
194 2
                    if (! in_array($key, $booleanAttributes)) {
195 2
                        continue;
196
                    }
197
198 1
                    $mapping[$key] = ($mapping[$key] === 'true');
199
                }
200
201 2
                if (isset($attributes['not-saved'])) {
202
                    $mapping['notSaved'] = ((string) $attributes['not-saved'] === 'true');
203
                }
204
205 2
                if (isset($attributes['also-load'])) {
206
                    $mapping['alsoLoadFields'] = explode(',', $attributes['also-load']);
207 2
                } elseif (isset($attributes['version'])) {
208
                    $mapping['version'] = ((string) $attributes['version'] === 'true');
209 2
                } elseif (isset($attributes['lock'])) {
210
                    $mapping['lock'] = ((string) $attributes['lock'] === 'true');
211
                }
212
213 2
                $this->addFieldMapping($class, $mapping);
214
            }
215
        }
216
217 8
        $this->addGridFSMappings($class, $xmlRoot);
218
219 8
        if (isset($xmlRoot->{'embed-one'})) {
220 1
            foreach ($xmlRoot->{'embed-one'} as $embed) {
221 1
                $this->addEmbedMapping($class, $embed, 'one');
222
            }
223
        }
224 8
        if (isset($xmlRoot->{'embed-many'})) {
225 1
            foreach ($xmlRoot->{'embed-many'} as $embed) {
226 1
                $this->addEmbedMapping($class, $embed, 'many');
227
            }
228
        }
229 8
        if (isset($xmlRoot->{'reference-many'})) {
230 3
            foreach ($xmlRoot->{'reference-many'} as $reference) {
231 3
                $this->addReferenceMapping($class, $reference, 'many');
232
            }
233
        }
234 8
        if (isset($xmlRoot->{'reference-one'})) {
235 2
            foreach ($xmlRoot->{'reference-one'} as $reference) {
236 2
                $this->addReferenceMapping($class, $reference, 'one');
237
            }
238
        }
239 8
        if (isset($xmlRoot->{'lifecycle-callbacks'})) {
240 1
            foreach ($xmlRoot->{'lifecycle-callbacks'}->{'lifecycle-callback'} as $lifecycleCallback) {
241 1
                $class->addLifecycleCallback((string) $lifecycleCallback['method'], constant('Doctrine\ODM\MongoDB\Events::' . (string) $lifecycleCallback['type']));
242
            }
243
        }
244 8
        if (! isset($xmlRoot->{'also-load-methods'})) {
245 8
            return;
246
        }
247
248 1
        foreach ($xmlRoot->{'also-load-methods'}->{'also-load-method'} as $alsoLoadMethod) {
249 1
            $class->registerAlsoLoadMethod((string) $alsoLoadMethod['method'], (string) $alsoLoadMethod['field']);
250
        }
251 1
    }
252
253 9
    private function addFieldMapping(ClassMetadata $class, $mapping)
254
    {
255 9
        if (isset($mapping['name'])) {
256 6
            $name = $mapping['name'];
257 8
        } elseif (isset($mapping['fieldName'])) {
258 8
            $name = $mapping['fieldName'];
259
        } else {
260
            throw new \InvalidArgumentException('Cannot infer a MongoDB name from the mapping');
261
        }
262
263 9
        $class->mapField($mapping);
264
265
        // Index this field if either "index", "unique", or "sparse" are set
266 9
        if (! (isset($mapping['index']) || isset($mapping['unique']) || isset($mapping['sparse']))) {
267 9
            return;
268
        }
269
270 1
        $keys = [$name => $mapping['order'] ?? 'asc'];
271 1
        $options = [];
272
273 1
        if (isset($mapping['background'])) {
274
            $options['background'] = (bool) $mapping['background'];
275
        }
276 1
        if (isset($mapping['drop-dups'])) {
277
            $options['dropDups'] = (bool) $mapping['drop-dups'];
278
        }
279 1
        if (isset($mapping['index-name'])) {
280
            $options['name'] = (string) $mapping['index-name'];
281
        }
282 1
        if (isset($mapping['sparse'])) {
283 1
            $options['sparse'] = (bool) $mapping['sparse'];
284
        }
285 1
        if (isset($mapping['unique'])) {
286 1
            $options['unique'] = (bool) $mapping['unique'];
287
        }
288
289 1
        $class->addIndex($keys, $options);
290 1
    }
291
292 2
    private function addEmbedMapping(ClassMetadata $class, $embed, $type)
293
    {
294 2
        $attributes = $embed->attributes();
295 2
        $defaultStrategy = $type === 'one' ? ClassMetadata::STORAGE_STRATEGY_SET : CollectionHelper::DEFAULT_STRATEGY;
296
        $mapping = [
297 2
            'type'            => $type,
298
            'embedded'        => true,
299 2
            'targetDocument'  => isset($attributes['target-document']) ? (string) $attributes['target-document'] : null,
300 2
            'collectionClass' => isset($attributes['collection-class']) ? (string) $attributes['collection-class'] : null,
301 2
            'name'            => (string) $attributes['field'],
302 2
            'strategy'        => (string) ($attributes['strategy'] ?? $defaultStrategy),
303
        ];
304 2
        if (isset($attributes['fieldName'])) {
305
            $mapping['fieldName'] = (string) $attributes['fieldName'];
306
        }
307 2
        if (isset($embed->{'discriminator-field'})) {
308
            $attr = $embed->{'discriminator-field'};
309
            $mapping['discriminatorField'] = (string) $attr['name'];
310
        }
311 2
        if (isset($embed->{'discriminator-map'})) {
312
            foreach ($embed->{'discriminator-map'}->{'discriminator-mapping'} as $discriminatorMapping) {
313
                $attr = $discriminatorMapping->attributes();
314
                $mapping['discriminatorMap'][(string) $attr['value']] = (string) $attr['class'];
315
            }
316
        }
317 2
        if (isset($embed->{'default-discriminator-value'})) {
318
            $mapping['defaultDiscriminatorValue'] = (string) $embed->{'default-discriminator-value'}['value'];
319
        }
320 2
        if (isset($attributes['not-saved'])) {
321
            $mapping['notSaved'] = ((string) $attributes['not-saved'] === 'true');
322
        }
323 2
        if (isset($attributes['also-load'])) {
324
            $mapping['alsoLoadFields'] = explode(',', $attributes['also-load']);
325
        }
326 2
        $this->addFieldMapping($class, $mapping);
327 2
    }
328
329 4
    private function addReferenceMapping(ClassMetadata $class, $reference, $type)
330
    {
331 4
        $cascade = array_keys((array) $reference->cascade);
332 4
        if (count($cascade) === 1) {
333 1
            $cascade = current($cascade) ?: next($cascade);
334
        }
335 4
        $attributes = $reference->attributes();
336 4
        $defaultStrategy = $type === 'one' ? ClassMetadata::STORAGE_STRATEGY_SET : CollectionHelper::DEFAULT_STRATEGY;
337
        $mapping = [
338 4
            'cascade'          => $cascade,
339 4
            'orphanRemoval'    => isset($attributes['orphan-removal']) ? ((string) $attributes['orphan-removal'] === 'true') : false,
340 4
            'type'             => $type,
341
            'reference'        => true,
342 4
            'storeAs'          => (string) ($attributes['store-as'] ?? ClassMetadata::REFERENCE_STORE_AS_DB_REF),
343 4
            'targetDocument'   => isset($attributes['target-document']) ? (string) $attributes['target-document'] : null,
344 4
            'collectionClass'  => isset($attributes['collection-class']) ? (string) $attributes['collection-class'] : null,
345 4
            'name'             => (string) $attributes['field'],
346 4
            'strategy'         => (string) ($attributes['strategy'] ?? $defaultStrategy),
347 4
            'inversedBy'       => isset($attributes['inversed-by']) ? (string) $attributes['inversed-by'] : null,
348 4
            'mappedBy'         => isset($attributes['mapped-by']) ? (string) $attributes['mapped-by'] : null,
349 4
            'repositoryMethod' => isset($attributes['repository-method']) ? (string) $attributes['repository-method'] : null,
350 4
            'limit'            => isset($attributes['limit']) ? (int) $attributes['limit'] : null,
351 4
            'skip'             => isset($attributes['skip']) ? (int) $attributes['skip'] : null,
352
            'prime'            => [],
353
        ];
354
355 4
        if (isset($attributes['fieldName'])) {
356
            $mapping['fieldName'] = (string) $attributes['fieldName'];
357
        }
358 4
        if (isset($reference->{'discriminator-field'})) {
359
            $attr = $reference->{'discriminator-field'};
360
            $mapping['discriminatorField'] = (string) $attr['name'];
361
        }
362 4
        if (isset($reference->{'discriminator-map'})) {
363
            foreach ($reference->{'discriminator-map'}->{'discriminator-mapping'} as $discriminatorMapping) {
364
                $attr = $discriminatorMapping->attributes();
365
                $mapping['discriminatorMap'][(string) $attr['value']] = (string) $attr['class'];
366
            }
367
        }
368 4
        if (isset($reference->{'default-discriminator-value'})) {
369
            $mapping['defaultDiscriminatorValue'] = (string) $reference->{'default-discriminator-value'}['value'];
370
        }
371 4
        if (isset($reference->{'sort'})) {
372
            foreach ($reference->{'sort'}->{'sort'} as $sort) {
373
                $attr = $sort->attributes();
374
                $mapping['sort'][(string) $attr['field']] = (string) ($attr['order'] ?? 'asc');
375
            }
376
        }
377 4
        if (isset($reference->{'criteria'})) {
378
            foreach ($reference->{'criteria'}->{'criteria'} as $criteria) {
379
                $attr = $criteria->attributes();
380
                $mapping['criteria'][(string) $attr['field']] = (string) $attr['value'];
381
            }
382
        }
383 4
        if (isset($attributes['not-saved'])) {
384
            $mapping['notSaved'] = ((string) $attributes['not-saved'] === 'true');
385
        }
386 4
        if (isset($attributes['also-load'])) {
387
            $mapping['alsoLoadFields'] = explode(',', $attributes['also-load']);
388
        }
389 4
        if (isset($reference->{'prime'})) {
390 1
            foreach ($reference->{'prime'}->{'field'} as $field) {
391 1
                $attr = $field->attributes();
392 1
                $mapping['prime'][] = (string) $attr['name'];
393
            }
394
        }
395
396 4
        $this->addFieldMapping($class, $mapping);
397 4
    }
398
399 2
    private function addIndex(ClassMetadata $class, \SimpleXmlElement $xmlIndex)
400
    {
401 2
        $attributes = $xmlIndex->attributes();
402
403 2
        $keys = [];
404
405 2
        foreach ($xmlIndex->{'key'} as $key) {
406 2
            $keys[(string) $key['name']] = (string) ($key['order'] ?? 'asc');
407
        }
408
409 2
        $options = [];
410
411 2
        if (isset($attributes['background'])) {
412
            $options['background'] = ((string) $attributes['background'] === 'true');
413
        }
414 2
        if (isset($attributes['drop-dups'])) {
415
            $options['dropDups'] = ((string) $attributes['drop-dups'] === 'true');
416
        }
417 2
        if (isset($attributes['name'])) {
418
            $options['name'] = (string) $attributes['name'];
419
        }
420 2
        if (isset($attributes['sparse'])) {
421
            $options['sparse'] = ((string) $attributes['sparse'] === 'true');
422
        }
423 2
        if (isset($attributes['unique'])) {
424
            $options['unique'] = ((string) $attributes['unique'] === 'true');
425
        }
426
427 2
        if (isset($xmlIndex->{'option'})) {
428
            foreach ($xmlIndex->{'option'} as $option) {
429
                $value = (string) $option['value'];
430
                if ($value === 'true') {
431
                    $value = true;
432
                } elseif ($value === 'false') {
433
                    $value = false;
434
                } elseif (is_numeric($value)) {
435
                    $value = preg_match('/^[-]?\d+$/', $value) ? (int) $value : (float) $value;
436
                }
437
                $options[(string) $option['name']] = $value;
438
            }
439
        }
440
441 2
        if (isset($xmlIndex->{'partial-filter-expression'})) {
442 2
            $partialFilterExpressionMapping = $xmlIndex->{'partial-filter-expression'};
443
444 2
            if (isset($partialFilterExpressionMapping->and)) {
445 2
                foreach ($partialFilterExpressionMapping->and as $and) {
446 2
                    if (! isset($and->field)) {
447 1
                        continue;
448
                    }
449
450 2
                    $partialFilterExpression = $this->getPartialFilterExpression($and->field);
451 2
                    if (! $partialFilterExpression) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $partialFilterExpression of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
452
                        continue;
453
                    }
454
455 2
                    $options['partialFilterExpression']['$and'][] = $partialFilterExpression;
456
                }
457 1
            } elseif (isset($partialFilterExpressionMapping->field)) {
458 1
                $partialFilterExpression = $this->getPartialFilterExpression($partialFilterExpressionMapping->field);
459
460 1
                if ($partialFilterExpression) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $partialFilterExpression of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
461 1
                    $options['partialFilterExpression'] = $partialFilterExpression;
462
                }
463
            }
464
        }
465
466 2
        $class->addIndex($keys, $options);
467 2
    }
468
469 2
    private function getPartialFilterExpression(\SimpleXMLElement $fields)
470
    {
471 2
        $partialFilterExpression = [];
472 2
        foreach ($fields as $field) {
473 2
            $operator = (string) $field['operator'] ?: null;
474
475 2
            if (! isset($field['value'])) {
476 1
                if (! isset($field->field)) {
477
                    continue;
478
                }
479
480 1
                $nestedExpression = $this->getPartialFilterExpression($field->field);
481 1
                if (! $nestedExpression) {
482
                    continue;
483
                }
484
485 1
                $value = $nestedExpression;
486
            } else {
487 2
                $value = trim((string) $field['value']);
488
            }
489
490 2
            if ($value === 'true') {
491
                $value = true;
492 2
            } elseif ($value === 'false') {
493
                $value = false;
494 2
            } elseif (is_numeric($value)) {
495 1
                $value = preg_match('/^[-]?\d+$/', $value) ? (int) $value : (float) $value;
496
            }
497
498 2
            $partialFilterExpression[(string) $field['name']] = $operator ? ['$' . $operator => $value] : $value;
499
        }
500
501 2
        return $partialFilterExpression;
502
    }
503
504 1
    private function setShardKey(ClassMetadata $class, \SimpleXmlElement $xmlShardkey)
505
    {
506 1
        $attributes = $xmlShardkey->attributes();
507
508 1
        $keys = [];
509 1
        $options = [];
510 1
        foreach ($xmlShardkey->{'key'} as $key) {
511 1
            $keys[(string) $key['name']] = (string) ($key['order'] ?? 'asc');
512
        }
513
514 1
        if (isset($attributes['unique'])) {
515 1
            $options['unique'] = ((string) $attributes['unique'] === 'true');
516
        }
517
518 1
        if (isset($attributes['numInitialChunks'])) {
519 1
            $options['numInitialChunks'] = (int) $attributes['numInitialChunks'];
520
        }
521
522 1
        if (isset($xmlShardkey->{'option'})) {
523
            foreach ($xmlShardkey->{'option'} as $option) {
524
                $value = (string) $option['value'];
525
                if ($value === 'true') {
526
                    $value = true;
527
                } elseif ($value === 'false') {
528
                    $value = false;
529
                } elseif (is_numeric($value)) {
530
                    $value = preg_match('/^[-]?\d+$/', $value) ? (int) $value : (float) $value;
531
                }
532
                $options[(string) $option['name']] = $value;
533
            }
534
        }
535
536 1
        $class->setShardKey($keys, $options);
537 1
    }
538
539
    /**
540
     * Parses <read-preference> to a format suitable for the underlying driver.
541
     *
542
     * list($readPreference, $tags) = $this->transformReadPreference($xml->{read-preference});
543
     *
544
     * @param \SimpleXMLElement $xmlReadPreference
545
     * @return array
546
     */
547
    private function transformReadPreference($xmlReadPreference)
548
    {
549
        $tags = null;
550
        if (isset($xmlReadPreference->{'tag-set'})) {
551
            $tags = [];
552
            foreach ($xmlReadPreference->{'tag-set'} as $tagSet) {
553
                $set = [];
554
                foreach ($tagSet->tag as $tag) {
555
                    $set[(string) $tag['name']] = (string) $tag['value'];
556
                }
557
                $tags[] = $set;
558
            }
559
        }
560
        return [(string) $xmlReadPreference['mode'], $tags];
561
    }
562
563
    /**
564
     * {@inheritDoc}
565
     */
566 8
    protected function loadMappingFile($file)
567
    {
568 8
        $result = [];
569 8
        $xmlElement = simplexml_load_file($file);
570
571 8
        foreach (['document', 'embedded-document', 'mapped-superclass', 'query-result-document', 'gridfs-file'] as $type) {
572 8
            if (! isset($xmlElement->$type)) {
573 8
                continue;
574
            }
575
576 8
            foreach ($xmlElement->$type as $documentElement) {
577 8
                $documentName = (string) $documentElement['name'];
578 8
                $result[$documentName] = $documentElement;
579
            }
580
        }
581
582 8
        return $result;
583
    }
584
585 8
    private function addGridFSMappings(ClassMetadata $class, \SimpleXMLElement $xmlRoot): void
586
    {
587 8
        if (! $class->isFile) {
588 7
            return;
589
        }
590
591 1
        foreach (self::DEFAULT_GRIDFS_MAPPINGS as $name => $mapping) {
592 1
            if (! isset($xmlRoot->{$name})) {
593
                continue;
594
            }
595
596 1
            if (isset($xmlRoot->{$name}->attributes()['fieldName'])) {
597 1
                $mapping['fieldName'] = (string) $xmlRoot->{$name}->attributes()['fieldName'];
598
            }
599
600 1
            $this->addFieldMapping($class, $mapping);
601
        }
602
603 1
        if (! isset($xmlRoot->metadata)) {
604
            return;
605
        }
606
607 1
        $xmlRoot->metadata->addAttribute('field', 'metadata');
608 1
        $this->addEmbedMapping($class, $xmlRoot->metadata, 'one');
609 1
    }
610
}
611