Completed
Pull Request — master (#1718)
by Maciej
10:27 queued 04:03
created

SchemaManager::createDocumentDatabase()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 0
cts 9
cp 0
rs 9.2
c 0
b 0
f 0
cc 4
eloc 8
nc 2
nop 1
crap 20
1
<?php
2
3
namespace Doctrine\ODM\MongoDB;
4
5
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
6
use Doctrine\ODM\MongoDB\Mapping\ClassMetadataFactory;
7
use Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo;
8
use MongoDB\Driver\Exception\RuntimeException;
9
use MongoDB\Driver\WriteConcern;
10
use MongoDB\Model\IndexInfo;
11
12
class SchemaManager
13
{
14
    /**
15
     * @var DocumentManager
16
     */
17
    protected $dm;
18
19
    /**
20
     *
21
     * @var ClassMetadataFactory
22
     */
23
    protected $metadataFactory;
24
25
    /**
26
     * @param DocumentManager $dm
27
     * @param ClassMetadataFactory $cmf
28
     */
29 1670
    public function __construct(DocumentManager $dm, ClassMetadataFactory $cmf)
30
    {
31 1670
        $this->dm = $dm;
32 1670
        $this->metadataFactory = $cmf;
33 1670
    }
34
35
    /**
36
     * Ensure indexes are created for all documents that can be loaded with the
37
     * metadata factory.
38
     *
39
     * @param integer $timeout Timeout (ms) for acknowledged index creation
40
     */
41 1 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...
42
    {
43 1
        foreach ($this->metadataFactory->getAllMetadata() as $class) {
44 1
            if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
45 1
                continue;
46
            }
47 1
            $this->ensureDocumentIndexes($class->name, $timeout);
48
        }
49 1
    }
50
51
    /**
52
     * Ensure indexes exist for all mapped document classes.
53
     *
54
     * Indexes that exist in MongoDB but not the document metadata will be
55
     * deleted.
56
     *
57
     * @param integer $timeout Timeout (ms) for acknowledged index creation
58
     */
59 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...
60
    {
61
        foreach ($this->metadataFactory->getAllMetadata() as $class) {
62
            if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
63
                continue;
64
            }
65
            $this->updateDocumentIndexes($class->name, $timeout);
66
        }
67
    }
68
69
    /**
70
     * Ensure indexes exist for the mapped document class.
71
     *
72
     * Indexes that exist in MongoDB but not the document metadata will be
73
     * deleted.
74
     *
75
     * @param string $documentName
76
     * @param integer $timeout Timeout (ms) for acknowledged index creation
77
     * @throws \InvalidArgumentException
78
     */
79 3
    public function updateDocumentIndexes($documentName, $timeout = null)
80
    {
81 3
        $class = $this->dm->getClassMetadata($documentName);
82
83 3
        if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
84
            throw new \InvalidArgumentException('Cannot update document indexes for mapped super classes, embedded documents or aggregation result documents.');
85
        }
86
87 3
        $documentIndexes = $this->getDocumentIndexes($documentName);
88 3
        $collection = $this->dm->getDocumentCollection($documentName);
89 3
        $mongoIndexes = iterator_to_array($collection->listIndexes());
90
91
        /* Determine which Mongo indexes should be deleted. Exclude the ID index
92
         * and those that are equivalent to any in the class metadata.
93
         */
94 3
        $self = $this;
95 3
        $mongoIndexes = array_filter($mongoIndexes, function (IndexInfo $mongoIndex) use ($documentIndexes, $self) {
96 1
            if ('_id_' === $mongoIndex['name']) {
97
                return false;
98
            }
99
100 1
            foreach ($documentIndexes as $documentIndex) {
101 1
                if ($self->isMongoIndexEquivalentToDocumentIndex($mongoIndex, $documentIndex)) {
102 1
                    return false;
103
                }
104
            }
105
106 1
            return true;
107 3
        });
108
109
        // Delete indexes that do not exist in class metadata
110 3
        foreach ($mongoIndexes as $mongoIndex) {
111 1
            if (! isset($mongoIndex['name'])) {
112
                continue;
113
            }
114
115 1
            $collection->dropIndex($mongoIndex['name']);
116
        }
117
118 3
        $this->ensureDocumentIndexes($documentName, $timeout);
119 3
    }
120
121
    /**
122
     * @param string $documentName
123
     * @return array
124
     */
125 19
    public function getDocumentIndexes($documentName)
126
    {
127 19
        $visited = array();
128 19
        return $this->doGetDocumentIndexes($documentName, $visited);
129
    }
130
131
    /**
132
     * @param string $documentName
133
     * @param array $visited
134
     * @return array
135
     */
136 19
    private function doGetDocumentIndexes($documentName, array &$visited)
137
    {
138 19
        if (isset($visited[$documentName])) {
139 1
            return array();
140
        }
141
142 19
        $visited[$documentName] = true;
143
144 19
        $class = $this->dm->getClassMetadata($documentName);
145 19
        $indexes = $this->prepareIndexes($class);
146 19
        $embeddedDocumentIndexes = array();
147
148
        // Add indexes from embedded & referenced documents
149 19
        foreach ($class->fieldMappings as $fieldMapping) {
150 19
            if (isset($fieldMapping['embedded'])) {
151 3
                if (isset($fieldMapping['targetDocument'])) {
152 3
                    $possibleEmbeds = array($fieldMapping['targetDocument']);
153 2
                } elseif (isset($fieldMapping['discriminatorMap'])) {
154 1
                    $possibleEmbeds = array_unique($fieldMapping['discriminatorMap']);
155
                } else {
156 1
                    continue;
157
                }
158 3
                foreach ($possibleEmbeds as $embed) {
159 3
                    if (isset($embeddedDocumentIndexes[$embed])) {
160 2
                        $embeddedIndexes = $embeddedDocumentIndexes[$embed];
161
                    } else {
162 3
                        $embeddedIndexes = $this->doGetDocumentIndexes($embed, $visited);
163 3
                        $embeddedDocumentIndexes[$embed] = $embeddedIndexes;
164
                    }
165 3
                    foreach ($embeddedIndexes as $embeddedIndex) {
166 2
                        foreach ($embeddedIndex['keys'] as $key => $value) {
167 2
                            $embeddedIndex['keys'][$fieldMapping['name'] . '.' . $key] = $value;
168 2
                            unset($embeddedIndex['keys'][$key]);
169
                        }
170 3
                        $indexes[] = $embeddedIndex;
171
                    }
172
                }
173 19
            } elseif (isset($fieldMapping['reference']) && isset($fieldMapping['targetDocument'])) {
174 8
                foreach ($indexes as $idx => $index) {
175 8
                    $newKeys = array();
176 8
                    foreach ($index['keys'] as $key => $v) {
177 8
                        if ($key == $fieldMapping['name']) {
178 2
                            $key = ClassMetadataInfo::getReferenceFieldName($fieldMapping['storeAs'], $key);
179
                        }
180 8
                        $newKeys[$key] = $v;
181
                    }
182 19
                    $indexes[$idx]['keys'] = $newKeys;
183
                }
184
            }
185
        }
186 19
        return $indexes;
187
    }
188
189
    /**
190
     * @param ClassMetadata $class
191
     * @return array
192
     */
193 19
    private function prepareIndexes(ClassMetadata $class)
194
    {
195 19
        $persister = $this->dm->getUnitOfWork()->getDocumentPersister($class->name);
196 19
        $indexes = $class->getIndexes();
197 19
        $newIndexes = array();
198
199 19
        foreach ($indexes as $index) {
200
            $newIndex = array(
201 19
                'keys' => array(),
202 19
                'options' => $index['options']
203
            );
204 19
            foreach ($index['keys'] as $key => $value) {
205 19
                $key = $persister->prepareFieldName($key);
206 19
                if ($class->hasField($key)) {
207 17
                    $mapping = $class->getFieldMapping($key);
208 17
                    $newIndex['keys'][$mapping['name']] = $value;
209
                } else {
210 19
                    $newIndex['keys'][$key] = $value;
211
                }
212
            }
213
214 19
            $newIndexes[] = $newIndex;
215
        }
216
217 19
        return $newIndexes;
218
    }
219
220
    /**
221
     * Ensure the given document's indexes are created.
222
     *
223
     * @param string $documentName
224
     * @param integer $timeout Timeout (ms) for acknowledged index creation
225
     * @throws \InvalidArgumentException
226
     */
227 15
    public function ensureDocumentIndexes($documentName, $timeout = null)
228
    {
229 15
        $class = $this->dm->getClassMetadata($documentName);
230 15
        if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
231
            throw new \InvalidArgumentException('Cannot create document indexes for mapped super classes, embedded documents or query result documents.');
232
        }
233 15
        if ($indexes = $this->getDocumentIndexes($documentName)) {
234 15
            $collection = $this->dm->getDocumentCollection($class->name);
235 15
            foreach ($indexes as $index) {
236 15
                $keys = $index['keys'];
237 15
                $options = $index['options'];
238
239 15
                if ( ! isset($options['timeout']) && isset($timeout)) {
240 1
                    $options['timeout'] = $timeout;
241
                }
242
243 15
                $collection->createIndex($keys, $options);
244
            }
245
        }
246 15
    }
247
248
    /**
249
     * Delete indexes for all documents that can be loaded with the
250
     * metadata factory.
251
     */
252 1 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...
253
    {
254 1
        foreach ($this->metadataFactory->getAllMetadata() as $class) {
255 1
            if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
256 1
                continue;
257
            }
258 1
            $this->deleteDocumentIndexes($class->name);
259
        }
260 1
    }
261
262
    /**
263
     * Delete the given document's indexes.
264
     *
265
     * @param string $documentName
266
     * @throws \InvalidArgumentException
267
     */
268 2 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...
269
    {
270 2
        $class = $this->dm->getClassMetadata($documentName);
271 2
        if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
272
            throw new \InvalidArgumentException('Cannot delete document indexes for mapped super classes, embedded documents or query result documents.');
273
        }
274 2
        $this->dm->getDocumentCollection($documentName)->dropIndexes();
275 2
    }
276
277
    /**
278
     * Create all the mapped document collections in the metadata factory.
279
     */
280 1 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...
281
    {
282 1
        foreach ($this->metadataFactory->getAllMetadata() as $class) {
283 1
            if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
284 1
                continue;
285
            }
286 1
            $this->createDocumentCollection($class->name);
287
        }
288 1
    }
289
290
    /**
291
     * Create the document collection for a mapped class.
292
     *
293
     * @param string $documentName
294
     * @throws \InvalidArgumentException
295
     */
296 3
    public function createDocumentCollection($documentName)
297
    {
298 3
        $class = $this->dm->getClassMetadata($documentName);
299
300 3
        if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
301
            throw new \InvalidArgumentException('Cannot create document collection for mapped super classes, embedded documents or query result documents.');
302
        }
303
304 3
        $this->dm->getDocumentDatabase($documentName)->createCollection(
305 3
            $class->getCollection(),
306
            [
307 3
                'capped' => $class->getCollectionCapped(),
308 3
                'size' => $class->getCollectionSize(),
309 3
                'max' => $class->getCollectionMax(),
310
            ]
311
        );
312 3
    }
313
314
    /**
315
     * Drop all the mapped document collections in the metadata factory.
316
     */
317 1 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...
318
    {
319 1
        foreach ($this->metadataFactory->getAllMetadata() as $class) {
320 1
            if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
321 1
                continue;
322
            }
323 1
            $this->dropDocumentCollection($class->name);
324
        }
325 1
    }
326
327
    /**
328
     * Drop the document collection for a mapped class.
329
     *
330
     * @param string $documentName
331
     * @throws \InvalidArgumentException
332
     */
333 3 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...
334
    {
335 3
        $class = $this->dm->getClassMetadata($documentName);
336 3
        if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
337
            throw new \InvalidArgumentException('Cannot delete document indexes for mapped super classes, embedded documents or query result documents.');
338
        }
339 3
        $this->dm->getDocumentCollection($documentName)->drop();
340 3
    }
341
342
    /**
343
     * Drop all the mapped document databases in the metadata factory.
344
     */
345 1 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...
346
    {
347 1
        foreach ($this->metadataFactory->getAllMetadata() as $class) {
348 1
            if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
349 1
                continue;
350
            }
351 1
            $this->dropDocumentDatabase($class->name);
352
        }
353 1
    }
354
355
    /**
356
     * Drop the document database for a mapped class.
357
     *
358
     * @param string $documentName
359
     * @throws \InvalidArgumentException
360
     */
361 2 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...
362
    {
363 2
        $class = $this->dm->getClassMetadata($documentName);
364 2
        if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
365
            throw new \InvalidArgumentException('Cannot drop document database for mapped super classes, embedded documents or query result documents.');
366
        }
367 2
        $this->dm->getDocumentDatabase($documentName)->drop();
368 2
    }
369
370
    /**
371
     * Determine if an index returned by MongoCollection::getIndexInfo() can be
372
     * considered equivalent to an index in class metadata.
373
     *
374
     * Indexes are considered different if:
375
     *
376
     *   (a) Key/direction pairs differ or are not in the same order
377
     *   (b) Sparse or unique options differ
378
     *   (c) Mongo index is unique without dropDups and mapped index is unique
379
     *       with dropDups
380
     *   (d) Geospatial options differ (bits, max, min)
381
     *   (e) The partialFilterExpression differs
382
     *
383
     * Regarding (c), the inverse case is not a reason to delete and
384
     * recreate the index, since dropDups only affects creation of
385
     * the unique index. Additionally, the background option is only
386
     * relevant to index creation and is not considered.
387
     *
388
     * @param array|IndexInfo $mongoIndex Mongo index data.
389
     * @param array $documentIndex Document index data.
390
     * @return bool True if the indexes are equivalent, otherwise false.
391
     */
392 30
    public function isMongoIndexEquivalentToDocumentIndex($mongoIndex, $documentIndex)
393
    {
394 30
        $documentIndexOptions = $documentIndex['options'];
395
396 30
        if ($mongoIndex['key'] != $documentIndex['keys']) {
397 2
            return false;
398
        }
399
400 28
        if (empty($mongoIndex['sparse']) xor empty($documentIndexOptions['sparse'])) {
401 2
            return false;
402
        }
403
404 26
        if (empty($mongoIndex['unique']) xor empty($documentIndexOptions['unique'])) {
405 2
            return false;
406
        }
407
408 24
        if ( ! empty($mongoIndex['unique']) && empty($mongoIndex['dropDups']) &&
409 24
            ! empty($documentIndexOptions['unique']) && ! empty($documentIndexOptions['dropDups'])) {
410
411 1
            return false;
412
        }
413
414 23
        foreach (array('bits', 'max', 'min') as $option) {
415 23
            if (isset($mongoIndex[$option]) xor isset($documentIndexOptions[$option])) {
416 6
                return false;
417
            }
418
419 21
            if (isset($mongoIndex[$option]) && isset($documentIndexOptions[$option]) &&
420 21
                $mongoIndex[$option] !== $documentIndexOptions[$option]) {
421
422 21
                return false;
423
            }
424
        }
425
426 14
        if (empty($mongoIndex['partialFilterExpression']) xor empty($documentIndexOptions['partialFilterExpression'])) {
427 2
            return false;
428
        }
429
430 12
        if (isset($mongoIndex['partialFilterExpression']) && isset($documentIndexOptions['partialFilterExpression']) &&
431 12
            $mongoIndex['partialFilterExpression'] !== $documentIndexOptions['partialFilterExpression']) {
432
433 1
            return false;
434
        }
435
436 11
        return true;
437
    }
438
439
    /**
440
     * Ensure collections are sharded for all documents that can be loaded with the
441
     * metadata factory.
442
     *
443
     * @param array $indexOptions Options for `ensureIndex` command. It's performed on an existing collections
444
     *
445
     * @throws MongoDBException
446
     */
447
    public function ensureSharding(array $indexOptions = array())
448
    {
449
        foreach ($this->metadataFactory->getAllMetadata() as $class) {
450
            if ($class->isMappedSuperclass || !$class->isSharded()) {
451
                continue;
452
            }
453
454
            $this->ensureDocumentSharding($class->name, $indexOptions);
455
        }
456
    }
457
458
    /**
459
     * Ensure sharding for collection by document name.
460
     *
461
     * @param string $documentName
462
     * @param array  $indexOptions Options for `ensureIndex` command. It's performed on an existing collections.
463
     *
464
     * @throws MongoDBException
465
     */
466 2
    public function ensureDocumentSharding($documentName, array $indexOptions = array())
467
    {
468 2
        $class = $this->dm->getClassMetadata($documentName);
469 2
        if ( ! $class->isSharded()) {
470
            return;
471
        }
472
473 2
        $this->enableShardingForDbByDocumentName($documentName);
474
475 2
        $try = 0;
476
        do {
477
            try {
478 2
                $result = $this->runShardCollectionCommand($documentName);
479 2
                $done = true;
480
481
                // Need to check error message because MongoDB 3.0 does not return a code for this error
482 2
                if ($result['ok'] != 1 && strpos($result['errmsg'], 'please create an index that starts') !== false) {
483
                    // The proposed key is not returned when using mongo-php-adapter with ext-mongodb.
484
                    // See https://github.com/mongodb/mongo-php-driver/issues/296 for details
485
                    $key = $result['proposedKey'] ?? $this->dm->getClassMetadata($documentName)->getShardKey()['keys'];
486
487
                    $this->dm->getDocumentCollection($documentName)->ensureIndex($key, $indexOptions);
0 ignored issues
show
Bug introduced by
The method ensureIndex() does not seem to exist on object<MongoDB\Collection>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
488 2
                    $done = false;
489
                }
490 1
            } catch (RuntimeException $e) {
0 ignored issues
show
Bug introduced by
The class MongoDB\Driver\Exception\RuntimeException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
491 1
                if ($e->getCode() === 20 || $e->getMessage() == 'already sharded') {
492 1
                    return;
493
                }
494
495
                throw $e;
496
            }
497 2
        } while (! $done && $try < 2);
0 ignored issues
show
introduced by
It seems like the condition $try < 2 is always satisfied by any possible value of $try. Are you sure you do not have a deadlock here?
Loading history...
498
499
        // Starting with MongoDB 3.2, this command returns code 20 when a collection is already sharded.
500
        // For older MongoDB versions, check the error message
501 2
        if ($result['ok'] == 1 || (isset($result['code']) && $result['code'] == 20) || $result['errmsg'] == 'already sharded') {
502 2
            return;
503
        }
504
505
        throw MongoDBException::failedToEnsureDocumentSharding($documentName, $result['errmsg']);
506
    }
507
508
    /**
509
     * Enable sharding for database which contains documents with given name.
510
     *
511
     * @param string $documentName
512
     *
513
     * @throws MongoDBException
514
     */
515 2
    public function enableShardingForDbByDocumentName($documentName)
516
    {
517 2
        $dbName = $this->dm->getDocumentDatabase($documentName)->getDatabaseName();
518 2
        $adminDb = $this->dm->getClient()->selectDatabase('admin');
519
520
        try {
521 2
            $adminDb->command(array('enableSharding' => $dbName));
522 1
        } catch (RuntimeException $e) {
0 ignored issues
show
Bug introduced by
The class MongoDB\Driver\Exception\RuntimeException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
523 1
            if ($e->getCode() !== 23 || $e->getMessage() === 'already enabled') {
524
                throw MongoDBException::failedToEnableSharding($dbName, $e->getMessage());
525
            }
526
        }
527 2
    }
528
529
    /**
530
     * @param $documentName
531
     *
532
     * @return array
533
     */
534 2
    private function runShardCollectionCommand($documentName)
535
    {
536 2
        $class = $this->dm->getClassMetadata($documentName);
537 2
        $dbName = $this->dm->getDocumentDatabase($documentName)->getDatabaseName();
538 2
        $shardKey = $class->getShardKey();
539 2
        $adminDb = $this->dm->getClient()->selectDatabase('admin');
540
541 2
        $result = $adminDb->command(
542
            array(
543 2
                'shardCollection' => $dbName . '.' . $class->getCollection(),
544 2
                'key'             => $shardKey['keys']
545
            )
546 2
        )->toArray()[0];
547
548 2
        return $result;
549
    }
550
}
551