Completed
Pull Request — master (#1790)
by Andreas
14:35
created

XmlDriver   D

Complexity

Total Complexity 152

Size/Duplication

Total Lines 514
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 69.81%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 152
lcom 1
cbo 1
dl 0
loc 514
ccs 215
cts 308
cp 0.6981
rs 4.8717
c 1
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
F addEmbedMapping() 0 36 11
F addIndex() 0 69 20
F loadMetadataForClass() 0 166 55
C addFieldMapping() 0 38 11
F addReferenceMapping() 0 69 25
C getPartialFilterExpression() 0 34 11
D setShardKey() 0 34 10
A transformReadPreference() 0 15 4
A loadMappingFile() 0 18 4

How to fix   Complexity   

Complex Class

Complex classes like XmlDriver often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use XmlDriver, and based on these observations, apply Extract Interface, too.

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
    /**
33
     * {@inheritDoc}
34
     */
35 14
    public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENSION)
36
    {
37 14
        parent::__construct($locator, $fileExtension);
38 14
    }
39
40
    /**
41
     * {@inheritDoc}
42
     */
43 8
    public function loadMetadataForClass($className, \Doctrine\Common\Persistence\Mapping\ClassMetadata $class)
44
    {
45
        /* @var $class ClassMetadata */
46
        /* @var $xmlRoot \SimpleXMLElement */
47 8
        $xmlRoot = $this->getElement($className);
48 8
        if (! $xmlRoot) {
49
            return;
50
        }
51
52 8
        if ($xmlRoot->getName() === 'document') {
53 7
            if (isset($xmlRoot['repository-class'])) {
54 7
                $class->setCustomRepositoryClass((string) $xmlRoot['repository-class']);
55
            }
56 3
        } elseif ($xmlRoot->getName() === 'mapped-superclass') {
57 1
            $class->setCustomRepositoryClass(
58 1
                isset($xmlRoot['repository-class']) ? (string) $xmlRoot['repository-class'] : null
59
            );
60 1
            $class->isMappedSuperclass = true;
61 2
        } elseif ($xmlRoot->getName() === 'embedded-document') {
62 1
            $class->isEmbeddedDocument = true;
63 2
        } elseif ($xmlRoot->getName() === 'query-result-document') {
64 1
            $class->isQueryResultDocument = true;
65 1
        } elseif ($xmlRoot->getName() === 'gridfs-file') {
66 1
            $class->isFile = true;
67
        }
68
69 8
        if (isset($xmlRoot['db'])) {
70 4
            $class->setDatabase((string) $xmlRoot['db']);
71
        }
72
73 8
        if (isset($xmlRoot['collection'])) {
74 6
            if (isset($xmlRoot['capped-collection'])) {
75
                $config = ['name' => (string) $xmlRoot['collection']];
76
                $config['capped'] = (bool) $xmlRoot['capped-collection'];
77
                if (isset($xmlRoot['capped-collection-max'])) {
78
                    $config['max'] = (int) $xmlRoot['capped-collection-max'];
79
                }
80
                if (isset($xmlRoot['capped-collection-size'])) {
81
                    $config['size'] = (int) $xmlRoot['capped-collection-size'];
82
                }
83
                $class->setCollection($config);
84
            } else {
85 6
                $class->setCollection((string) $xmlRoot['collection']);
86
            }
87
        }
88 8
        if (isset($xmlRoot['bucket'])) {
89
            $class->setCollection((string) $xmlRoot['bucket']);
90
        }
91 8
        if (isset($xmlRoot['writeConcern'])) {
92
            $class->setWriteConcern((string) $xmlRoot['writeConcern']);
93
        }
94 8
        if (isset($xmlRoot['inheritance-type'])) {
95
            $inheritanceType = (string) $xmlRoot['inheritance-type'];
96
            $class->setInheritanceType(constant(ClassMetadata::class . '::INHERITANCE_TYPE_' . $inheritanceType));
97
        }
98 8
        if (isset($xmlRoot['change-tracking-policy'])) {
99 1
            $class->setChangeTrackingPolicy(constant(ClassMetadata::class . '::CHANGETRACKING_' . strtoupper((string) $xmlRoot['change-tracking-policy'])));
100
        }
101 8
        if (isset($xmlRoot->{'discriminator-field'})) {
102
            $discrField = $xmlRoot->{'discriminator-field'};
103
            /* XSD only allows for "name", which is consistent with association
104
             * configurations, but fall back to "fieldName" for BC.
105
             */
106
            $class->setDiscriminatorField(
107
                (string) ($discrField['name'] ?? $discrField['fieldName'])
108
            );
109
        }
110 8
        if (isset($xmlRoot->{'discriminator-map'})) {
111
            $map = [];
112
            foreach ($xmlRoot->{'discriminator-map'}->{'discriminator-mapping'} as $discrMapElement) {
113
                $map[(string) $discrMapElement['value']] = (string) $discrMapElement['class'];
114
            }
115
            $class->setDiscriminatorMap($map);
116
        }
117 8
        if (isset($xmlRoot->{'default-discriminator-value'})) {
118
            $class->setDefaultDiscriminatorValue((string) $xmlRoot->{'default-discriminator-value'}['value']);
119
        }
120 8
        if (isset($xmlRoot->{'indexes'})) {
121 2
            foreach ($xmlRoot->{'indexes'}->{'index'} as $index) {
122 2
                $this->addIndex($class, $index);
123
            }
124
        }
125 8
        if (isset($xmlRoot->{'shard-key'})) {
126
            $this->setShardKey($class, $xmlRoot->{'shard-key'}[0]);
127
        }
128 8
        if (isset($xmlRoot['read-only']) && (string) $xmlRoot['read-only'] === 'true') {
129
            $class->markReadOnly();
130
        }
131 8
        if (isset($xmlRoot->{'read-preference'})) {
132
            $class->setReadPreference(...$this->transformReadPreference($xmlRoot->{'read-preference'}));
133
        }
134 8
        if (isset($xmlRoot->field)) {
135 8
            foreach ($xmlRoot->field as $field) {
136 8
                $mapping = [];
137 8
                $attributes = $field->attributes();
138 8
                foreach ($attributes as $key => $value) {
139 8
                    $mapping[$key] = (string) $value;
140 8
                    $booleanAttributes = ['id', 'reference', 'embed', 'unique', 'sparse'];
141 8
                    if (! in_array($key, $booleanAttributes)) {
142 8
                        continue;
143
                    }
144
145 8
                    $mapping[$key] = ($mapping[$key] === 'true');
146
                }
147 8
                if (isset($mapping['id']) && $mapping['id'] === true && isset($mapping['strategy'])) {
148 2
                    $mapping['options'] = [];
149 2
                    if (isset($field->{'id-generator-option'})) {
150 1
                        foreach ($field->{'id-generator-option'} as $generatorOptions) {
151 1
                            $attributesGenerator = iterator_to_array($generatorOptions->attributes());
152 1
                            if (! isset($attributesGenerator['name']) || ! isset($attributesGenerator['value'])) {
153
                                continue;
154
                            }
155
156 1
                            $mapping['options'][(string) $attributesGenerator['name']] = (string) $attributesGenerator['value'];
157
                        }
158
                    }
159
                }
160
161 8
                if (isset($attributes['not-saved'])) {
162 1
                    $mapping['notSaved'] = ((string) $attributes['not-saved'] === 'true');
163
                }
164
165 8
                if (isset($attributes['also-load'])) {
166
                    $mapping['alsoLoadFields'] = explode(',', $attributes['also-load']);
167 8
                } elseif (isset($attributes['version'])) {
168
                    $mapping['version'] = ((string) $attributes['version'] === 'true');
169 8
                } elseif (isset($attributes['lock'])) {
170
                    $mapping['lock'] = ((string) $attributes['lock'] === 'true');
171
                }
172
173 8
                $this->addFieldMapping($class, $mapping);
174
            }
175
        }
176 8
        if (isset($xmlRoot->{'embed-one'})) {
177 2
            foreach ($xmlRoot->{'embed-one'} as $embed) {
178 2
                $this->addEmbedMapping($class, $embed, 'one');
179
            }
180
        }
181 8
        if (isset($xmlRoot->{'embed-many'})) {
182 1
            foreach ($xmlRoot->{'embed-many'} as $embed) {
183 1
                $this->addEmbedMapping($class, $embed, 'many');
184
            }
185
        }
186 8
        if (isset($xmlRoot->{'reference-many'})) {
187 3
            foreach ($xmlRoot->{'reference-many'} as $reference) {
188 3
                $this->addReferenceMapping($class, $reference, 'many');
189
            }
190
        }
191 8
        if (isset($xmlRoot->{'reference-one'})) {
192 2
            foreach ($xmlRoot->{'reference-one'} as $reference) {
193 2
                $this->addReferenceMapping($class, $reference, 'one');
194
            }
195
        }
196 8
        if (isset($xmlRoot->{'lifecycle-callbacks'})) {
197 1
            foreach ($xmlRoot->{'lifecycle-callbacks'}->{'lifecycle-callback'} as $lifecycleCallback) {
198 1
                $class->addLifecycleCallback((string) $lifecycleCallback['method'], constant('Doctrine\ODM\MongoDB\Events::' . (string) $lifecycleCallback['type']));
199
            }
200
        }
201 8
        if (! isset($xmlRoot->{'also-load-methods'})) {
202 8
            return;
203
        }
204
205 1
        foreach ($xmlRoot->{'also-load-methods'}->{'also-load-method'} as $alsoLoadMethod) {
206 1
            $class->registerAlsoLoadMethod((string) $alsoLoadMethod['method'], (string) $alsoLoadMethod['field']);
207
        }
208 1
    }
209
210 9
    private function addFieldMapping(ClassMetadata $class, $mapping)
211
    {
212 9
        if (isset($mapping['name'])) {
213 9
            $name = $mapping['name'];
214 1
        } elseif (isset($mapping['fieldName'])) {
215 1
            $name = $mapping['fieldName'];
216
        } else {
217
            throw new \InvalidArgumentException('Cannot infer a MongoDB name from the mapping');
218
        }
219
220 9
        $class->mapField($mapping);
221
222
        // Index this field if either "index", "unique", or "sparse" are set
223 9
        if (! (isset($mapping['index']) || isset($mapping['unique']) || isset($mapping['sparse']))) {
224 9
            return;
225
        }
226
227 1
        $keys = [$name => $mapping['order'] ?? 'asc'];
228 1
        $options = [];
229
230 1
        if (isset($mapping['background'])) {
231
            $options['background'] = (bool) $mapping['background'];
232
        }
233 1
        if (isset($mapping['drop-dups'])) {
234
            $options['dropDups'] = (bool) $mapping['drop-dups'];
235
        }
236 1
        if (isset($mapping['index-name'])) {
237
            $options['name'] = (string) $mapping['index-name'];
238
        }
239 1
        if (isset($mapping['sparse'])) {
240 1
            $options['sparse'] = (bool) $mapping['sparse'];
241
        }
242 1
        if (isset($mapping['unique'])) {
243 1
            $options['unique'] = (bool) $mapping['unique'];
244
        }
245
246 1
        $class->addIndex($keys, $options);
247 1
    }
248
249 2
    private function addEmbedMapping(ClassMetadata $class, $embed, $type)
250
    {
251 2
        $attributes = $embed->attributes();
252 2
        $defaultStrategy = $type === 'one' ? ClassMetadata::STORAGE_STRATEGY_SET : CollectionHelper::DEFAULT_STRATEGY;
253
        $mapping = [
254 2
            'type'            => $type,
255
            'embedded'        => true,
256 2
            'targetDocument'  => isset($attributes['target-document']) ? (string) $attributes['target-document'] : null,
257 2
            'collectionClass' => isset($attributes['collection-class']) ? (string) $attributes['collection-class'] : null,
258 2
            'name'            => (string) $attributes['field'],
259 2
            'strategy'        => (string) ($attributes['strategy'] ?? $defaultStrategy),
260
        ];
261 2
        if (isset($attributes['fieldName'])) {
262
            $mapping['fieldName'] = (string) $attributes['fieldName'];
263
        }
264 2
        if (isset($embed->{'discriminator-field'})) {
265
            $attr = $embed->{'discriminator-field'};
266
            $mapping['discriminatorField'] = (string) $attr['name'];
267
        }
268 2
        if (isset($embed->{'discriminator-map'})) {
269
            foreach ($embed->{'discriminator-map'}->{'discriminator-mapping'} as $discriminatorMapping) {
270
                $attr = $discriminatorMapping->attributes();
271
                $mapping['discriminatorMap'][(string) $attr['value']] = (string) $attr['class'];
272
            }
273
        }
274 2
        if (isset($embed->{'default-discriminator-value'})) {
275
            $mapping['defaultDiscriminatorValue'] = (string) $embed->{'default-discriminator-value'}['value'];
276
        }
277 2
        if (isset($attributes['not-saved'])) {
278
            $mapping['notSaved'] = ((string) $attributes['not-saved'] === 'true');
279
        }
280 2
        if (isset($attributes['also-load'])) {
281
            $mapping['alsoLoadFields'] = explode(',', $attributes['also-load']);
282
        }
283 2
        $this->addFieldMapping($class, $mapping);
284 2
    }
285
286 4
    private function addReferenceMapping(ClassMetadata $class, $reference, $type)
287
    {
288 4
        $cascade = array_keys((array) $reference->cascade);
289 4
        if (count($cascade) === 1) {
290 1
            $cascade = current($cascade) ?: next($cascade);
291
        }
292 4
        $attributes = $reference->attributes();
293 4
        $defaultStrategy = $type === 'one' ? ClassMetadata::STORAGE_STRATEGY_SET : CollectionHelper::DEFAULT_STRATEGY;
294
        $mapping = [
295 4
            'cascade'          => $cascade,
296 4
            'orphanRemoval'    => isset($attributes['orphan-removal']) ? ((string) $attributes['orphan-removal'] === 'true') : false,
297 4
            'type'             => $type,
298
            'reference'        => true,
299 4
            'storeAs'          => (string) ($attributes['store-as'] ?? ClassMetadata::REFERENCE_STORE_AS_DB_REF),
300 4
            'targetDocument'   => isset($attributes['target-document']) ? (string) $attributes['target-document'] : null,
301 4
            'collectionClass'  => isset($attributes['collection-class']) ? (string) $attributes['collection-class'] : null,
302 4
            'name'             => (string) $attributes['field'],
303 4
            'strategy'         => (string) ($attributes['strategy'] ?? $defaultStrategy),
304 4
            'inversedBy'       => isset($attributes['inversed-by']) ? (string) $attributes['inversed-by'] : null,
305 4
            'mappedBy'         => isset($attributes['mapped-by']) ? (string) $attributes['mapped-by'] : null,
306 4
            'repositoryMethod' => isset($attributes['repository-method']) ? (string) $attributes['repository-method'] : null,
307 4
            'limit'            => isset($attributes['limit']) ? (int) $attributes['limit'] : null,
308 4
            'skip'             => isset($attributes['skip']) ? (int) $attributes['skip'] : null,
309
            'prime'            => [],
310
        ];
311
312 4
        if (isset($attributes['fieldName'])) {
313
            $mapping['fieldName'] = (string) $attributes['fieldName'];
314
        }
315 4
        if (isset($reference->{'discriminator-field'})) {
316
            $attr = $reference->{'discriminator-field'};
317
            $mapping['discriminatorField'] = (string) $attr['name'];
318
        }
319 4
        if (isset($reference->{'discriminator-map'})) {
320
            foreach ($reference->{'discriminator-map'}->{'discriminator-mapping'} as $discriminatorMapping) {
321
                $attr = $discriminatorMapping->attributes();
322
                $mapping['discriminatorMap'][(string) $attr['value']] = (string) $attr['class'];
323
            }
324
        }
325 4
        if (isset($reference->{'default-discriminator-value'})) {
326
            $mapping['defaultDiscriminatorValue'] = (string) $reference->{'default-discriminator-value'}['value'];
327
        }
328 4
        if (isset($reference->{'sort'})) {
329
            foreach ($reference->{'sort'}->{'sort'} as $sort) {
330
                $attr = $sort->attributes();
331
                $mapping['sort'][(string) $attr['field']] = (string) ($attr['order'] ?? 'asc');
332
            }
333
        }
334 4
        if (isset($reference->{'criteria'})) {
335
            foreach ($reference->{'criteria'}->{'criteria'} as $criteria) {
336
                $attr = $criteria->attributes();
337
                $mapping['criteria'][(string) $attr['field']] = (string) $attr['value'];
338
            }
339
        }
340 4
        if (isset($attributes['not-saved'])) {
341
            $mapping['notSaved'] = ((string) $attributes['not-saved'] === 'true');
342
        }
343 4
        if (isset($attributes['also-load'])) {
344
            $mapping['alsoLoadFields'] = explode(',', $attributes['also-load']);
345
        }
346 4
        if (isset($reference->{'prime'})) {
347 1
            foreach ($reference->{'prime'}->{'field'} as $field) {
348 1
                $attr = $field->attributes();
349 1
                $mapping['prime'][] = (string) $attr['name'];
350
            }
351
        }
352
353 4
        $this->addFieldMapping($class, $mapping);
354 4
    }
355
356 2
    private function addIndex(ClassMetadata $class, \SimpleXmlElement $xmlIndex)
357
    {
358 2
        $attributes = $xmlIndex->attributes();
359
360 2
        $keys = [];
361
362 2
        foreach ($xmlIndex->{'key'} as $key) {
363 2
            $keys[(string) $key['name']] = (string) ($key['order'] ?? 'asc');
364
        }
365
366 2
        $options = [];
367
368 2
        if (isset($attributes['background'])) {
369
            $options['background'] = ((string) $attributes['background'] === 'true');
370
        }
371 2
        if (isset($attributes['drop-dups'])) {
372
            $options['dropDups'] = ((string) $attributes['drop-dups'] === 'true');
373
        }
374 2
        if (isset($attributes['name'])) {
375
            $options['name'] = (string) $attributes['name'];
376
        }
377 2
        if (isset($attributes['sparse'])) {
378
            $options['sparse'] = ((string) $attributes['sparse'] === 'true');
379
        }
380 2
        if (isset($attributes['unique'])) {
381
            $options['unique'] = ((string) $attributes['unique'] === 'true');
382
        }
383
384 2
        if (isset($xmlIndex->{'option'})) {
385
            foreach ($xmlIndex->{'option'} as $option) {
386
                $value = (string) $option['value'];
387
                if ($value === 'true') {
388
                    $value = true;
389
                } elseif ($value === 'false') {
390
                    $value = false;
391
                } elseif (is_numeric($value)) {
392
                    $value = preg_match('/^[-]?\d+$/', $value) ? (int) $value : (float) $value;
393
                }
394
                $options[(string) $option['name']] = $value;
395
            }
396
        }
397
398 2
        if (isset($xmlIndex->{'partial-filter-expression'})) {
399 2
            $partialFilterExpressionMapping = $xmlIndex->{'partial-filter-expression'};
400
401 2
            if (isset($partialFilterExpressionMapping->and)) {
402 2
                foreach ($partialFilterExpressionMapping->and as $and) {
403 2
                    if (! isset($and->field)) {
404 1
                        continue;
405
                    }
406
407 2
                    $partialFilterExpression = $this->getPartialFilterExpression($and->field);
408 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...
409
                        continue;
410
                    }
411
412 2
                    $options['partialFilterExpression']['$and'][] = $partialFilterExpression;
413
                }
414 1
            } elseif (isset($partialFilterExpressionMapping->field)) {
415 1
                $partialFilterExpression = $this->getPartialFilterExpression($partialFilterExpressionMapping->field);
416
417 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...
418 1
                    $options['partialFilterExpression'] = $partialFilterExpression;
419
                }
420
            }
421
        }
422
423 2
        $class->addIndex($keys, $options);
424 2
    }
425
426 2
    private function getPartialFilterExpression(\SimpleXMLElement $fields)
427
    {
428 2
        $partialFilterExpression = [];
429 2
        foreach ($fields as $field) {
430 2
            $operator = (string) $field['operator'] ?: null;
431
432 2
            if (! isset($field['value'])) {
433 1
                if (! isset($field->field)) {
434
                    continue;
435
                }
436
437 1
                $nestedExpression = $this->getPartialFilterExpression($field->field);
438 1
                if (! $nestedExpression) {
439
                    continue;
440
                }
441
442 1
                $value = $nestedExpression;
443
            } else {
444 2
                $value = trim((string) $field['value']);
445
            }
446
447 2
            if ($value === 'true') {
448
                $value = true;
449 2
            } elseif ($value === 'false') {
450
                $value = false;
451 2
            } elseif (is_numeric($value)) {
452 1
                $value = preg_match('/^[-]?\d+$/', $value) ? (int) $value : (float) $value;
453
            }
454
455 2
            $partialFilterExpression[(string) $field['name']] = $operator ? ['$' . $operator => $value] : $value;
456
        }
457
458 2
        return $partialFilterExpression;
459
    }
460
461 1
    private function setShardKey(ClassMetadata $class, \SimpleXmlElement $xmlShardkey)
462
    {
463 1
        $attributes = $xmlShardkey->attributes();
464
465 1
        $keys = [];
466 1
        $options = [];
467 1
        foreach ($xmlShardkey->{'key'} as $key) {
468 1
            $keys[(string) $key['name']] = (string) ($key['order'] ?? 'asc');
469
        }
470
471 1
        if (isset($attributes['unique'])) {
472 1
            $options['unique'] = ((string) $attributes['unique'] === 'true');
473
        }
474
475 1
        if (isset($attributes['numInitialChunks'])) {
476 1
            $options['numInitialChunks'] = (int) $attributes['numInitialChunks'];
477
        }
478
479 1
        if (isset($xmlShardkey->{'option'})) {
480
            foreach ($xmlShardkey->{'option'} as $option) {
481
                $value = (string) $option['value'];
482
                if ($value === 'true') {
483
                    $value = true;
484
                } elseif ($value === 'false') {
485
                    $value = false;
486
                } elseif (is_numeric($value)) {
487
                    $value = preg_match('/^[-]?\d+$/', $value) ? (int) $value : (float) $value;
488
                }
489
                $options[(string) $option['name']] = $value;
490
            }
491
        }
492
493 1
        $class->setShardKey($keys, $options);
494 1
    }
495
496
    /**
497
     * Parses <read-preference> to a format suitable for the underlying driver.
498
     *
499
     * list($readPreference, $tags) = $this->transformReadPreference($xml->{read-preference});
500
     *
501
     * @param \SimpleXMLElement $xmlReadPreference
502
     * @return array
503
     */
504
    private function transformReadPreference($xmlReadPreference)
505
    {
506
        $tags = null;
507
        if (isset($xmlReadPreference->{'tag-set'})) {
508
            $tags = [];
509
            foreach ($xmlReadPreference->{'tag-set'} as $tagSet) {
510
                $set = [];
511
                foreach ($tagSet->tag as $tag) {
512
                    $set[(string) $tag['name']] = (string) $tag['value'];
513
                }
514
                $tags[] = $set;
515
            }
516
        }
517
        return [(string) $xmlReadPreference['mode'], $tags];
518
    }
519
520
    /**
521
     * {@inheritDoc}
522
     */
523 8
    protected function loadMappingFile($file)
524
    {
525 8
        $result = [];
526 8
        $xmlElement = simplexml_load_file($file);
527
528 8
        foreach (['document', 'embedded-document', 'mapped-superclass', 'query-result-document', 'gridfs-file'] as $type) {
529 8
            if (! isset($xmlElement->$type)) {
530 8
                continue;
531
            }
532
533 8
            foreach ($xmlElement->$type as $documentElement) {
534 8
                $documentName = (string) $documentElement['name'];
535 8
                $result[$documentName] = $documentElement;
536
            }
537
        }
538
539 8
        return $result;
540
    }
541
}
542