Completed
Pull Request — master (#1385)
by Andreas
08:02
created

SchemaManager::createCollections()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 9
Code Lines 5

Duplication

Lines 9
Ratio 100 %

Code Coverage

Tests 0
CRAP Score 20
Metric Value
dl 9
loc 9
ccs 0
cts 6
cp 0
rs 9.2
cc 4
eloc 5
nc 3
nop 0
crap 20
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\ODM\MongoDB;
21
22
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
23
use Doctrine\ODM\MongoDB\Mapping\ClassMetadataFactory;
24
25
class SchemaManager
26
{
27
    /**
28
     * @var DocumentManager
29
     */
30
    protected $dm;
31
32
    /**
33
     *
34
     * @var ClassMetadataFactory
35
     */
36
    protected $metadataFactory;
37
38
    /**
39
     * @param DocumentManager $dm
40
     * @param ClassMetadataFactory $cmf
41
     */
42 991
    public function __construct(DocumentManager $dm, ClassMetadataFactory $cmf)
43
    {
44 991
        $this->dm = $dm;
45 991
        $this->metadataFactory = $cmf;
46 991
    }
47
48
    /**
49
     * Ensure indexes are created for all documents that can be loaded with the
50
     * metadata factory.
51
     *
52
     * @param integer $timeout Timeout (ms) for acknowledged index creation
53
     */
54 View Code Duplication
    public function ensureIndexes($timeout = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
55
    {
56
        foreach ($this->metadataFactory->getAllMetadata() as $class) {
57
            if ($class->isMappedSuperclass || $class->isEmbeddedDocument) {
58
                continue;
59
            }
60
            $this->ensureDocumentIndexes($class->name, $timeout);
61
        }
62
    }
63
64
    /**
65
     * Ensure indexes exist for all mapped document classes.
66
     *
67
     * Indexes that exist in MongoDB but not the document metadata will be
68
     * deleted.
69
     *
70
     * @param integer $timeout Timeout (ms) for acknowledged index creation
71
     */
72 View Code Duplication
    public function updateIndexes($timeout = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
73
    {
74
        foreach ($this->metadataFactory->getAllMetadata() as $class) {
75
            if ($class->isMappedSuperclass || $class->isEmbeddedDocument) {
76
                continue;
77
            }
78
            $this->updateDocumentIndexes($class->name, $timeout);
79
        }
80
    }
81
82
    /**
83
     * Ensure indexes exist for the mapped document class.
84
     *
85
     * Indexes that exist in MongoDB but not the document metadata will be
86
     * deleted.
87
     *
88
     * @param string $documentName
89
     * @param integer $timeout Timeout (ms) for acknowledged index creation
90
     * @throws \InvalidArgumentException
91
     */
92 1
    public function updateDocumentIndexes($documentName, $timeout = null)
93
    {
94 1
        $class = $this->dm->getClassMetadata($documentName);
95
96 1
        if ($class->isMappedSuperclass || $class->isEmbeddedDocument) {
97
            throw new \InvalidArgumentException('Cannot update document indexes for mapped super classes or embedded documents.');
98
        }
99
100 1
        $documentIndexes = $this->getDocumentIndexes($documentName);
101 1
        $collection = $this->dm->getDocumentCollection($documentName);
102 1
        $mongoIndexes = $collection->getIndexInfo();
103
104
        /* Determine which Mongo indexes should be deleted. Exclude the ID index
105
         * and those that are equivalent to any in the class metadata.
106
         */
107 1
        $self = $this;
108 1
        $mongoIndexes = array_filter($mongoIndexes, function ($mongoIndex) use ($documentIndexes, $self) {
109
            if ('_id_' === $mongoIndex['name']) {
110
                return false;
111
            }
112
113
            foreach ($documentIndexes as $documentIndex) {
114
                if ($self->isMongoIndexEquivalentToDocumentIndex($mongoIndex, $documentIndex)) {
115
                    return false;
116
                }
117
            }
118
119
            return true;
120 1
        });
121
122
        // Delete indexes that do not exist in class metadata
123 1
        foreach ($mongoIndexes as $mongoIndex) {
124
            if (isset($mongoIndex['name'])) {
125
                /* Note: MongoCollection::deleteIndex() cannot delete
126
                 * custom-named indexes, so use the deleteIndexes command.
127
                 */
128
                $collection->getDatabase()->command(array(
129
                    'deleteIndexes' => $collection->getName(),
130
                    'index' => $mongoIndex['name'],
131
                ));
132
            }
133
        }
134
135 1
        $this->ensureDocumentIndexes($documentName, $timeout);
136 1
    }
137
138
    /**
139
     * @param string $documentName
140
     * @return array
141
     */
142 41
    public function getDocumentIndexes($documentName)
143
    {
144 41
        $visited = array();
145 41
        return $this->doGetDocumentIndexes($documentName, $visited);
146
    }
147
148
    /**
149
     * @param string $documentName
150
     * @param array $visited
151
     * @return array
152
     */
153 41
    private function doGetDocumentIndexes($documentName, array &$visited)
154
    {
155 41
        if (isset($visited[$documentName])) {
156
            return array();
157
        }
158
159 41
        $visited[$documentName] = true;
160
161 41
        $class = $this->dm->getClassMetadata($documentName);
162 41
        $indexes = $this->prepareIndexes($class);
163 41
        $embeddedDocumentIndexes = array();
164
165
        // Add indexes from embedded & referenced documents
166 41
        foreach ($class->fieldMappings as $fieldMapping) {
167 41
            if (isset($fieldMapping['embedded'])) {
168 30
                if (isset($fieldMapping['targetDocument'])) {
169 30
                    $possibleEmbeds = array($fieldMapping['targetDocument']);
170 1
                } elseif (isset($fieldMapping['discriminatorMap'])) {
171 1
                    $possibleEmbeds = array_unique($fieldMapping['discriminatorMap']);
172
                } else {
173
                    continue;
174
                }
175 30
                foreach ($possibleEmbeds as $embed) {
176 30
                    if (isset($embeddedDocumentIndexes[$embed])) {
177 24
                        $embeddedIndexes = $embeddedDocumentIndexes[$embed];
178
                    } else {
179 30
                        $embeddedIndexes = $this->doGetDocumentIndexes($embed, $visited);
180 30
                        $embeddedDocumentIndexes[$embed] = $embeddedIndexes;
181
                    }
182 30
                    foreach ($embeddedIndexes as $embeddedIndex) {
183 25
                        foreach ($embeddedIndex['keys'] as $key => $value) {
184 25
                            $embeddedIndex['keys'][$fieldMapping['name'] . '.' . $key] = $value;
185 25
                            unset($embeddedIndex['keys'][$key]);
186
                        }
187 30
                        $indexes[] = $embeddedIndex;
188
                    }
189
                }
190 41
            } elseif (isset($fieldMapping['reference']) && isset($fieldMapping['targetDocument'])) {
191 26
                foreach ($indexes as $idx => $index) {
192 26
                    $newKeys = array();
193 26
                    foreach ($index['keys'] as $key => $v) {
194 26
                        if ($key == $fieldMapping['name']) {
195 1
                            $key = $fieldMapping['simple'] ? $key : $key . '.$id';
196
                        }
197 26
                        $newKeys[$key] = $v;
198
                    }
199 41
                    $indexes[$idx]['keys'] = $newKeys;
200
                }
201
            }
202
        }
203 41
        return $indexes;
204
    }
205
206
    /**
207
     * @param ClassMetadata $class
208
     * @return array
209
     */
210 41
    private function prepareIndexes(ClassMetadata $class)
211
    {
212 41
        $persister = $this->dm->getUnitOfWork()->getDocumentPersister($class->name);
213 41
        $indexes = $class->getIndexes();
214 41
        $newIndexes = array();
215
216 41
        foreach ($indexes as $index) {
217
            $newIndex = array(
218 41
                'keys' => array(),
219 41
                'options' => $index['options']
220
            );
221 41
            foreach ($index['keys'] as $key => $value) {
222 41
                $key = $persister->prepareFieldName($key);
223 41
                if ($class->hasField($key)) {
224 39
                    $mapping = $class->getFieldMapping($key);
225 39
                    $newIndex['keys'][$mapping['name']] = $value;
226
                } else {
227 41
                    $newIndex['keys'][$key] = $value;
228
                }
229
            }
230
231 41
            $newIndexes[] = $newIndex;
232
        }
233
234 41
        return $newIndexes;
235
    }
236
237
    /**
238
     * Ensure the given document's indexes are created.
239
     *
240
     * @param string $documentName
241
     * @param integer $timeout Timeout (ms) for acknowledged index creation
242
     * @throws \InvalidArgumentException
243
     */
244 37
    public function ensureDocumentIndexes($documentName, $timeout = null)
245
    {
246 37
        $class = $this->dm->getClassMetadata($documentName);
247 37
        if ($class->isMappedSuperclass || $class->isEmbeddedDocument) {
248
            throw new \InvalidArgumentException('Cannot create document indexes for mapped super classes or embedded documents.');
249
        }
250 37
        if ($indexes = $this->getDocumentIndexes($documentName)) {
251 37
            $collection = $this->dm->getDocumentCollection($class->name);
252 37
            foreach ($indexes as $index) {
253 37
                $keys = $index['keys'];
254 37
                $options = $index['options'];
255
256 37
                if ( ! isset($options['safe']) && ! isset($options['w'])) {
257 36
                    $options['w'] = 1;
258
                }
259
260 37
                if (isset($options['safe']) && ! isset($options['w'])) {
261 1
                    $options['w'] = is_bool($options['safe']) ? (integer) $options['safe'] : $options['safe'];
262 1
                    unset($options['safe']);
263
                }
264
265 37
                if ( ! isset($options['timeout']) && isset($timeout)) {
266
                    $options['timeout'] = $timeout;
267
                }
268
269 37
                $collection->ensureIndex($keys, $options);
270
            }
271
        }
272 37
    }
273
274
    /**
275
     * Delete indexes for all documents that can be loaded with the
276
     * metadata factory.
277
     */
278 View Code Duplication
    public function deleteIndexes()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
279
    {
280
        foreach ($this->metadataFactory->getAllMetadata() as $class) {
281
            if ($class->isMappedSuperclass || $class->isEmbeddedDocument) {
282
                continue;
283
            }
284
            $this->deleteDocumentIndexes($class->name);
285
        }
286
    }
287
288
    /**
289
     * Delete the given document's indexes.
290
     *
291
     * @param string $documentName
292
     * @throws \InvalidArgumentException
293
     */
294 View Code Duplication
    public function deleteDocumentIndexes($documentName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
295
    {
296
        $class = $this->dm->getClassMetadata($documentName);
297
        if ($class->isMappedSuperclass || $class->isEmbeddedDocument) {
298
            throw new \InvalidArgumentException('Cannot delete document indexes for mapped super classes or embedded documents.');
299
        }
300
        $this->dm->getDocumentCollection($documentName)->deleteIndexes();
301
    }
302
303
    /**
304
     * Create all the mapped document collections in the metadata factory.
305
     */
306 View Code Duplication
    public function createCollections()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
307
    {
308
        foreach ($this->metadataFactory->getAllMetadata() as $class) {
309
            if ($class->isMappedSuperclass || $class->isEmbeddedDocument) {
310
                continue;
311
            }
312
            $this->createDocumentCollection($class->name);
313
        }
314
    }
315
316
    /**
317
     * Create the document collection for a mapped class.
318
     *
319
     * @param string $documentName
320
     * @throws \InvalidArgumentException
321
     */
322 1
    public function createDocumentCollection($documentName)
323
    {
324 1
        $class = $this->dm->getClassMetadata($documentName);
325
326 1
        if ($class->isMappedSuperclass || $class->isEmbeddedDocument) {
327
            throw new \InvalidArgumentException('Cannot create document collection for mapped super classes or embedded documents.');
328
        }
329
330 1
        if ($class->isFile()) {
331
            $this->dm->getDocumentDatabase($documentName)->createCollection($class->getCollection() . '.files');
332
            $this->dm->getDocumentDatabase($documentName)->createCollection($class->getCollection() . '.chunks');
333
334
            return;
335
        }
336
337 1
        $this->dm->getDocumentDatabase($documentName)->createCollection(
338 1
            $class->getCollection(),
339 1
            $class->getCollectionCapped(),
340 1
            $class->getCollectionSize(),
341 1
            $class->getCollectionMax()
342
        );
343 1
    }
344
345
    /**
346
     * Drop all the mapped document collections in the metadata factory.
347
     */
348 View Code Duplication
    public function dropCollections()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
349
    {
350
        foreach ($this->metadataFactory->getAllMetadata() as $class) {
351
            if ($class->isMappedSuperclass || $class->isEmbeddedDocument) {
352
                continue;
353
            }
354
            $this->dropDocumentCollection($class->name);
355
        }
356
    }
357
358
    /**
359
     * Drop the document collection for a mapped class.
360
     *
361
     * @param string $documentName
362
     * @throws \InvalidArgumentException
363
     */
364 1 View Code Duplication
    public function dropDocumentCollection($documentName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
365
    {
366 1
        $class = $this->dm->getClassMetadata($documentName);
367 1
        if ($class->isMappedSuperclass || $class->isEmbeddedDocument) {
368
            throw new \InvalidArgumentException('Cannot delete document indexes for mapped super classes or embedded documents.');
369
        }
370 1
        $this->dm->getDocumentDatabase($documentName)->dropCollection(
371 1
            $class->getCollection()
372
        );
373 1
    }
374
375
    /**
376
     * Drop all the mapped document databases in the metadata factory.
377
     */
378 View Code Duplication
    public function dropDatabases()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
379
    {
380
        foreach ($this->metadataFactory->getAllMetadata() as $class) {
381
            if ($class->isMappedSuperclass || $class->isEmbeddedDocument) {
382
                continue;
383
            }
384
            $this->dropDocumentDatabase($class->name);
385
        }
386
    }
387
388
    /**
389
     * Drop the document database for a mapped class.
390
     *
391
     * @param string $documentName
392
     * @throws \InvalidArgumentException
393
     */
394 View Code Duplication
    public function dropDocumentDatabase($documentName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
395
    {
396
        $class = $this->dm->getClassMetadata($documentName);
397
        if ($class->isMappedSuperclass || $class->isEmbeddedDocument) {
398
            throw new \InvalidArgumentException('Cannot drop document database for mapped super classes or embedded documents.');
399
        }
400
        $this->dm->getDocumentDatabase($documentName)->drop();
401
    }
402
403
    /**
404
     * Create all the mapped document databases in the metadata factory.
405
     */
406 View Code Duplication
    public function createDatabases()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
407
    {
408
        foreach ($this->metadataFactory->getAllMetadata() as $class) {
409
            if ($class->isMappedSuperclass || $class->isEmbeddedDocument) {
410
                continue;
411
            }
412
            $this->createDocumentDatabase($class->name);
413
        }
414
    }
415
416
    /**
417
     * Create the document database for a mapped class.
418
     *
419
     * @param string $documentName
420
     * @throws \InvalidArgumentException
421
     */
422 View Code Duplication
    public function createDocumentDatabase($documentName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
423
    {
424
        $class = $this->dm->getClassMetadata($documentName);
425
        if ($class->isMappedSuperclass || $class->isEmbeddedDocument) {
426
            throw new \InvalidArgumentException('Cannot delete document indexes for mapped super classes or embedded documents.');
427
        }
428
        $this->dm->getDocumentDatabase($documentName)->execute('function() { return true; }');
429
    }
430
431
    /**
432
     * Determine if an index returned by MongoCollection::getIndexInfo() can be
433
     * considered equivalent to an index in class metadata.
434
     *
435
     * Indexes are considered different if:
436
     *
437
     *   (a) Key/direction pairs differ or are not in the same order
438
     *   (b) Sparse or unique options differ
439
     *   (c) Mongo index is unique without dropDups and mapped index is unique
440
     *       with dropDups
441
     *   (d) Geospatial options differ (bits, max, min)
442
     *   (e) The partialFilterExpression differs
443
     *
444
     * Regarding (c), the inverse case is not a reason to delete and
445
     * recreate the index, since dropDups only affects creation of
446
     * the unique index. Additionally, the background option is only
447
     * relevant to index creation and is not considered.
448
     *
449
     * @param array $mongoIndex Mongo index data.
450
     * @param array $documentIndex Document index data.
451
     * @return bool True if the indexes are equivalent, otherwise false.
452
     */
453
    public function isMongoIndexEquivalentToDocumentIndex($mongoIndex, $documentIndex)
454
    {
455
        $documentIndexOptions = $documentIndex['options'];
456
457
        if ($mongoIndex['key'] != $documentIndex['keys']) {
458
            return false;
459
        }
460
461
        if (empty($mongoIndex['sparse']) xor empty($documentIndexOptions['sparse'])) {
462
            return false;
463
        }
464
465
        if (empty($mongoIndex['unique']) xor empty($documentIndexOptions['unique'])) {
466
            return false;
467
        }
468
469
        if ( ! empty($mongoIndex['unique']) && empty($mongoIndex['dropDups']) &&
470
            ! empty($documentIndexOptions['unique']) && ! empty($documentIndexOptions['dropDups'])) {
471
472
            return false;
473
        }
474
475
        foreach (array('bits', 'max', 'min') as $option) {
476
            if (isset($mongoIndex[$option]) xor isset($documentIndexOptions[$option])) {
477
                return false;
478
            }
479
480
            if (isset($mongoIndex[$option]) && isset($documentIndexOptions[$option]) &&
481
                $mongoIndex[$option] !== $documentIndexOptions[$option]) {
482
483
                return false;
484
            }
485
        }
486
487
        if (empty($mongoIndex['partialFilterExpression']) xor empty($documentIndexOptions['partialFilterExpression'])) {
488
            return false;
489
        }
490
491
        if (isset($mongoIndex['partialFilterExpression']) && isset($documentIndexOptions['partialFilterExpression']) &&
492
            $mongoIndex['partialFilterExpression'] !== $documentIndexOptions['partialFilterExpression']) {
493
494
            return false;
495
        }
496
497
        return true;
498
    }
499
500
    /**
501
     * Ensure collections are sharded for all documents that can be loaded with the
502
     * metadata factory.
503
     *
504
     * @param array $indexOptions Options for `ensureIndex` command. It's performed on an existing collections
505
     *
506
     * @throws MongoDBException
507
     */
508
    public function ensureSharding(array $indexOptions = array())
509
    {
510
        foreach ($this->metadataFactory->getAllMetadata() as $class) {
511
            if ($class->isMappedSuperclass || !$class->isSharded()) {
512
                continue;
513
            }
514
515
            $this->ensureDocumentSharding($class->name, $indexOptions);
516
        }
517
    }
518
519
    /**
520
     * Ensure sharding for collection by document name.
521
     *
522
     * @param string $documentName
523
     * @param array  $indexOptions Options for `ensureIndex` command. It's performed on an existing collections.
524
     *
525
     * @throws MongoDBException
526
     */
527
    public function ensureDocumentSharding($documentName, array $indexOptions = array())
528
    {
529
        $class = $this->dm->getClassMetadata($documentName);
530
        if ( ! $class->isSharded()) {
531
            return;
532
        }
533
534
        $this->enableShardingForDbByDocumentName($documentName);
535
536
        do {
537
            $result = $this->runShardCollectionCommand($documentName);
538
            $done = true;
539
            $try = 0;
540
541
            if ($result['ok'] != 1 && isset($result['proposedKey'])) {
542
                $this->dm->getDocumentCollection($documentName)->ensureIndex($result['proposedKey'], $indexOptions);
543
                $done = false;
544
                $try++;
545
            }
546
        } while (!$done && $try < 2);
547
548
        // Different MongoDB versions return different result sets.
549
        // Thus, check code if it exists and fall back on error message
550 View Code Duplication
        if ($result['ok'] != 1 && ((isset($result['code']) && $result['code'] !== 20) && $result['errmsg'] !== 'already sharded')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
551
            throw MongoDBException::failedToEnsureDocumentSharding($documentName, $result['errmsg']);
552
        }
553
    }
554
555
    /**
556
     * Enable sharding for database which contains documents with given name.
557
     *
558
     * @param string $documentName
559
     *
560
     * @throws MongoDBException
561
     */
562
    public function enableShardingForDbByDocumentName($documentName)
563
    {
564
        $dbName = $this->dm->getDocumentDatabase($documentName)->getName();
565
        $adminDb = $this->dm->getConnection()->selectDatabase('admin');
566
        $result = $adminDb->command(array('enableSharding' => $dbName));
567
568
        // Different MongoDB versions return different result sets.
569
        // Thus, check code if it exists and fall back on error message
570 View Code Duplication
        if ($result['ok'] != 1 && ((isset($result['code']) && $result['code'] !== 23) && $result['errmsg'] !== 'already enabled')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
571
            throw MongoDBException::failedToEnableSharding($dbName, $result['errmsg']);
572
        }
573
    }
574
575
    /**
576
     * @param $documentName
577
     *
578
     * @return array
579
     */
580
    private function runShardCollectionCommand($documentName)
581
    {
582
        $class = $this->dm->getClassMetadata($documentName);
583
        $dbName = $this->dm->getDocumentDatabase($documentName)->getName();
584
        $shardKey = $class->getShardKey();
585
        $adminDb = $this->dm->getConnection()->selectDatabase('admin');
586
587
        $result = $adminDb->command(
588
            array(
589
                'shardCollection' => $dbName . '.' . $class->getCollection(),
590
                'key'             => $shardKey['keys']
591
            ),
592
            $shardKey['options']
593
        );
594
595
        return $result;
596
    }
597
}
598