Completed
Pull Request — master (#1790)
by Andreas
20:58
created

SchemaManager::deleteDocumentIndexes()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 2
cts 2
cp 1
rs 9.2
c 0
b 0
f 0
cc 4
eloc 5
nc 2
nop 1
crap 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ODM\MongoDB;
6
7
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
8
use Doctrine\ODM\MongoDB\Mapping\ClassMetadataFactory;
9
use MongoDB\Driver\Exception\RuntimeException;
10
use MongoDB\Model\IndexInfo;
11
use function array_filter;
12
use function array_unique;
13
use function iterator_to_array;
14
use function strpos;
15
16
class SchemaManager
17
{
18
    private const GRIDFS_FILE_COLLECTION_INDEX = ['files_id' => 1, 'n' => 1];
19
20
    private const GRIDFS_CHUNKS_COLLECTION_INDEX = ['filename' => 1, 'uploadDate' => 1];
21
22
    /** @var DocumentManager */
23
    protected $dm;
24 1627
25
    /** @var ClassMetadataFactory */
26 1627
    protected $metadataFactory;
27 1627
28 1627
    public function __construct(DocumentManager $dm, ClassMetadataFactory $cmf)
29
    {
30
        $this->dm = $dm;
31
        $this->metadataFactory = $cmf;
32
    }
33
34
    /**
35
     * Ensure indexes are created for all documents that can be loaded with the
36 1
     * metadata factory.
37
     *
38 1
     * @param int $timeout Timeout (ms) for acknowledged index creation
39 1
     */
40 1
    public function ensureIndexes($timeout = null)
41
    {
42 1
        foreach ($this->metadataFactory->getAllMetadata() as $class) {
43
            if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
44 1
                continue;
45
            }
46
47
            $this->ensureDocumentIndexes($class->name, $timeout);
48
        }
49
    }
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 int $timeout Timeout (ms) for acknowledged index creation
58
     */
59
    public function updateIndexes($timeout = null)
60
    {
61
        foreach ($this->metadataFactory->getAllMetadata() as $class) {
62
            if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
63
                continue;
64
            }
65
66
            $this->updateDocumentIndexes($class->name, $timeout);
67
        }
68
    }
69
70
    /**
71
     * Ensure indexes exist for the mapped document class.
72
     *
73
     * Indexes that exist in MongoDB but not the document metadata will be
74 3
     * deleted.
75
     *
76 3
     * @param string $documentName
77
     * @param int    $timeout      Timeout (ms) for acknowledged index creation
78 3
     * @throws \InvalidArgumentException
79
     */
80
    public function updateDocumentIndexes($documentName, $timeout = null)
81
    {
82 3
        $class = $this->dm->getClassMetadata($documentName);
83 3
84 3
        if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
85
            throw new \InvalidArgumentException('Cannot update document indexes for mapped super classes, embedded documents or aggregation result documents.');
86
        }
87
88
        $documentIndexes = $this->getDocumentIndexes($documentName);
89 3
        $collection = $this->dm->getDocumentCollection($documentName);
90
        $mongoIndexes = iterator_to_array($collection->listIndexes());
91 1
92
        /* Determine which Mongo indexes should be deleted. Exclude the ID index
93
         * and those that are equivalent to any in the class metadata.
94
         */
95 1
        $self = $this;
96 1
        $mongoIndexes = array_filter($mongoIndexes, function (IndexInfo $mongoIndex) use ($documentIndexes, $self) {
97 1
            if ($mongoIndex['name'] === '_id_') {
98
                return false;
99
            }
100
101 1
            foreach ($documentIndexes as $documentIndex) {
102 3
                if ($self->isMongoIndexEquivalentToDocumentIndex($mongoIndex, $documentIndex)) {
103
                    return false;
104
                }
105 3
            }
106 1
107
            return true;
108
        });
109
110 1
        // Delete indexes that do not exist in class metadata
111
        foreach ($mongoIndexes as $mongoIndex) {
112
            if (! isset($mongoIndex['name'])) {
113 3
                continue;
114 3
            }
115
116
            $collection->dropIndex($mongoIndex['name']);
117
        }
118
119
        $this->ensureDocumentIndexes($documentName, $timeout);
120 19
    }
121
122 19
    /**
123 19
     * @param string $documentName
124
     * @return array
125
     */
126
    public function getDocumentIndexes($documentName)
127
    {
128
        $visited = [];
129
        return $this->doGetDocumentIndexes($documentName, $visited);
130
    }
131 19
132
    /**
133 19
     * @param string $documentName
134 1
     * @param array  $visited
135
     * @return array
136
     */
137 19
    private function doGetDocumentIndexes($documentName, array &$visited)
138
    {
139 19
        if (isset($visited[$documentName])) {
140 19
            return [];
141 19
        }
142
143
        $visited[$documentName] = true;
144 19
145 19
        $class = $this->dm->getClassMetadata($documentName);
146 3
        $indexes = $this->prepareIndexes($class);
147 3
        $embeddedDocumentIndexes = [];
148 2
149 1
        // Add indexes from embedded & referenced documents
150
        foreach ($class->fieldMappings as $fieldMapping) {
151 1
            if (isset($fieldMapping['embedded'])) {
152
                if (isset($fieldMapping['targetDocument'])) {
153 3
                    $possibleEmbeds = [$fieldMapping['targetDocument']];
154 3
                } elseif (isset($fieldMapping['discriminatorMap'])) {
155 2
                    $possibleEmbeds = array_unique($fieldMapping['discriminatorMap']);
156
                } else {
157 3
                    continue;
158 3
                }
159
160 3
                foreach ($possibleEmbeds as $embed) {
161 2
                    if (isset($embeddedDocumentIndexes[$embed])) {
162 2
                        $embeddedIndexes = $embeddedDocumentIndexes[$embed];
163 2
                    } else {
164
                        $embeddedIndexes = $this->doGetDocumentIndexes($embed, $visited);
165 3
                        $embeddedDocumentIndexes[$embed] = $embeddedIndexes;
166
                    }
167
168 19
                    foreach ($embeddedIndexes as $embeddedIndex) {
169 8
                        foreach ($embeddedIndex['keys'] as $key => $value) {
170 8
                            $embeddedIndex['keys'][$fieldMapping['name'] . '.' . $key] = $value;
171 8
                            unset($embeddedIndex['keys'][$key]);
172 8
                        }
173 2
174
                        $indexes[] = $embeddedIndex;
175 8
                    }
176
                }
177 19
            } elseif (isset($fieldMapping['reference']) && isset($fieldMapping['targetDocument'])) {
178
                foreach ($indexes as $idx => $index) {
179
                    $newKeys = [];
180
                    foreach ($index['keys'] as $key => $v) {
181 19
                        if ($key === $fieldMapping['name']) {
182
                            $key = ClassMetadata::getReferenceFieldName($fieldMapping['storeAs'], $key);
183
                        }
184
185
                        $newKeys[$key] = $v;
186
                    }
187 19
188
                    $indexes[$idx]['keys'] = $newKeys;
189 19
                }
190 19
            }
191 19
        }
192
193 19
        return $indexes;
194
    }
195 19
196 19
    /**
197
     * @return array
198 19
     */
199 19
    private function prepareIndexes(ClassMetadata $class)
200 19
    {
201 17
        $persister = $this->dm->getUnitOfWork()->getDocumentPersister($class->name);
202 17
        $indexes = $class->getIndexes();
203
        $newIndexes = [];
204 19
205
        foreach ($indexes as $index) {
206
            $newIndex = [
207
                'keys' => [],
208 19
                'options' => $index['options'],
209
            ];
210
211 19
            foreach ($index['keys'] as $key => $value) {
212
                $key = $persister->prepareFieldName($key);
213
                if ($class->hasField($key)) {
214
                    $mapping = $class->getFieldMapping($key);
215
                    $newIndex['keys'][$mapping['name']] = $value;
216
                } else {
217
                    $newIndex['keys'][$key] = $value;
218
                }
219
            }
220
221 15
            $newIndexes[] = $newIndex;
222
        }
223 15
224 15
        return $newIndexes;
225
    }
226
227
    /**
228 15
     * Ensure the given document's indexes are created.
229 15
     *
230 3
     * @param string $documentName
231
     * @param int    $timeout      Timeout (ms) for acknowledged index creation
232
     * @throws \InvalidArgumentException
233 15
     */
234 15
    public function ensureDocumentIndexes($documentName, $timeout = null)
235 15
    {
236 15
        $class = $this->dm->getClassMetadata($documentName);
237
        if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
238 15
            throw new \InvalidArgumentException('Cannot create document indexes for mapped super classes, embedded documents or query result documents.');
239 1
        }
240
241
        if ($class->isFile) {
242 15
            $this->ensureGridFSIndexes($class);
243
        }
244 15
245
        $indexes = $this->getDocumentIndexes($documentName);
246
        if (! $indexes) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $indexes 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...
247
            return;
248
        }
249
250 1
        $collection = $this->dm->getDocumentCollection($class->name);
251
        foreach ($indexes as $index) {
252 1
            $keys = $index['keys'];
253 1
            $options = $index['options'];
254 1
255
            if (! isset($options['timeout']) && isset($timeout)) {
256 1
                $options['timeout'] = $timeout;
257
            }
258 1
259
            $collection->createIndex($keys, $options);
260
        }
261
    }
262
263
    /**
264
     * Delete indexes for all documents that can be loaded with the
265
     * metadata factory.
266 2
     */
267
    public function deleteIndexes()
268 2
    {
269 2
        foreach ($this->metadataFactory->getAllMetadata() as $class) {
270
            if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
271
                continue;
272 2
            }
273 2
274
            $this->deleteDocumentIndexes($class->name);
275
        }
276
    }
277
278 1
    /**
279
     * Delete the given document's indexes.
280 1
     *
281 1
     * @param string $documentName
282 1
     * @throws \InvalidArgumentException
283
     */
284 1
    public function deleteDocumentIndexes($documentName)
285
    {
286 1
        $class = $this->dm->getClassMetadata($documentName);
287
        if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
288
            throw new \InvalidArgumentException('Cannot delete document indexes for mapped super classes, embedded documents or query result documents.');
289
        }
290
291
        $this->dm->getDocumentCollection($documentName)->dropIndexes();
292
    }
293
294 4
    /**
295
     * Create all the mapped document collections in the metadata factory.
296 4
     */
297
    public function createCollections()
298 4
    {
299
        foreach ($this->metadataFactory->getAllMetadata() as $class) {
300
            if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
301
                continue;
302 4
            }
303 4
            $this->createDocumentCollection($class->name);
304
        }
305 4
    }
306 4
307 4
    /**
308
     * Create the document collection for a mapped class.
309
     *
310 4
     * @param string $documentName
311
     * @throws \InvalidArgumentException
312
     */
313
    public function createDocumentCollection($documentName)
314
    {
315 1
        $class = $this->dm->getClassMetadata($documentName);
316
317 1
        if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
318 1
            throw new \InvalidArgumentException('Cannot create document collection for mapped super classes, embedded documents or query result documents.');
319 1
        }
320
321 1
        if ($class->isFile) {
322
            $this->dm->getDocumentDatabase($documentName)->createCollection($class->getBucketName() . '.files');
323 1
            $this->dm->getDocumentDatabase($documentName)->createCollection($class->getBucketName() . '.chunks');
324
325
            return;
326
        }
327
328
        $this->dm->getDocumentDatabase($documentName)->createCollection(
329
            $class->getCollection(),
330
            [
331 4
                'capped' => $class->getCollectionCapped(),
332
                'size' => $class->getCollectionSize(),
333 4
                'max' => $class->getCollectionMax(),
334 4
            ]
335
        );
336
    }
337 4
338 4
    /**
339
     * Drop all the mapped document collections in the metadata factory.
340
     */
341
    public function dropCollections()
342
    {
343 1
        foreach ($this->metadataFactory->getAllMetadata() as $class) {
344
            if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
345 1
                continue;
346 1
            }
347 1
348
            $this->dropDocumentCollection($class->name);
349 1
        }
350
    }
351 1
352
    /**
353
     * Drop the document collection for a mapped class.
354
     *
355
     * @param string $documentName
356
     * @throws \InvalidArgumentException
357
     */
358
    public function dropDocumentCollection($documentName)
359 2
    {
360
        $class = $this->dm->getClassMetadata($documentName);
361 2
        if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
362 2
            throw new \InvalidArgumentException('Cannot delete document indexes for mapped super classes, embedded documents or query result documents.');
363
        }
364
365 2
        $this->dm->getDocumentCollection($documentName)->drop();
366 2
367
        if (! $class->isFile) {
368
            return;
369
        }
370
371
        $this->dm->getDocumentBucket($documentName)->getChunksCollection()->drop();
372
    }
373
374
    /**
375
     * Drop all the mapped document databases in the metadata factory.
376
     */
377
    public function dropDatabases()
378
    {
379
        foreach ($this->metadataFactory->getAllMetadata() as $class) {
380
            if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
381
                continue;
382
            }
383
384
            $this->dropDocumentDatabase($class->name);
385
        }
386
    }
387
388
    /**
389
     * Drop the document database for a mapped class.
390 30
     *
391
     * @param string $documentName
392 30
     * @throws \InvalidArgumentException
393
     */
394 30
    public function dropDocumentDatabase($documentName)
395 2
    {
396
        $class = $this->dm->getClassMetadata($documentName);
397
        if ($class->isMappedSuperclass || $class->isEmbeddedDocument || $class->isQueryResultDocument) {
398 28
            throw new \InvalidArgumentException('Cannot drop document database for mapped super classes, embedded documents or query result documents.');
399 2
        }
400
401
        $this->dm->getDocumentDatabase($documentName)->drop();
402 26
    }
403 2
404
    /**
405
     * Determine if an index returned by MongoCollection::getIndexInfo() can be
406 24
     * considered equivalent to an index in class metadata.
407 24
     *
408 1
     * Indexes are considered different if:
409
     *
410
     *   (a) Key/direction pairs differ or are not in the same order
411 23
     *   (b) Sparse or unique options differ
412 23
     *   (c) Mongo index is unique without dropDups and mapped index is unique
413 6
     *       with dropDups
414
     *   (d) Geospatial options differ (bits, max, min)
415
     *   (e) The partialFilterExpression differs
416 21
     *
417 21
     * Regarding (c), the inverse case is not a reason to delete and
418 21
     * recreate the index, since dropDups only affects creation of
419
     * the unique index. Additionally, the background option is only
420
     * relevant to index creation and is not considered.
421
     *
422 14
     * @param array|IndexInfo $mongoIndex    Mongo index data.
423 2
     * @param array           $documentIndex Document index data.
424
     * @return bool True if the indexes are equivalent, otherwise false.
425
     */
426 12
    public function isMongoIndexEquivalentToDocumentIndex($mongoIndex, $documentIndex)
427 12
    {
428 1
        $documentIndexOptions = $documentIndex['options'];
429
430
        if ($mongoIndex['key'] !== $documentIndex['keys']) {
431 11
            return false;
432
        }
433
434
        if (empty($mongoIndex['sparse']) xor empty($documentIndexOptions['sparse'])) {
435
            return false;
436
        }
437
438
        if (empty($mongoIndex['unique']) xor empty($documentIndexOptions['unique'])) {
439
            return false;
440
        }
441
442
        if (! empty($mongoIndex['unique']) && empty($mongoIndex['dropDups']) &&
443
            ! empty($documentIndexOptions['unique']) && ! empty($documentIndexOptions['dropDups'])) {
444
            return false;
445
        }
446
447
        foreach (['bits', 'max', 'min'] as $option) {
448
            if (isset($mongoIndex[$option]) xor isset($documentIndexOptions[$option])) {
449
                return false;
450
            }
451
452
            if (isset($mongoIndex[$option]) && isset($documentIndexOptions[$option]) &&
453
                $mongoIndex[$option] !== $documentIndexOptions[$option]) {
454
                return false;
455
            }
456
        }
457
458
        if (empty($mongoIndex['partialFilterExpression']) xor empty($documentIndexOptions['partialFilterExpression'])) {
459
            return false;
460
        }
461 2
462
        if (isset($mongoIndex['partialFilterExpression']) && isset($documentIndexOptions['partialFilterExpression']) &&
463 2
            $mongoIndex['partialFilterExpression'] !== $documentIndexOptions['partialFilterExpression']) {
464 2
            return false;
465
        }
466
467
        return true;
468 2
    }
469
470 2
    /**
471
     * Ensure collections are sharded for all documents that can be loaded with the
472
     * metadata factory.
473 2
     *
474 2
     * @param array $indexOptions Options for `ensureIndex` command. It's performed on an existing collections
475
     *
476
     * @throws MongoDBException
477 2
     */
478
    public function ensureSharding(array $indexOptions = [])
479
    {
480
        foreach ($this->metadataFactory->getAllMetadata() as $class) {
481
            if ($class->isMappedSuperclass || ! $class->isSharded()) {
482
                continue;
483 2
            }
484
485 1
            $this->ensureDocumentSharding($class->name, $indexOptions);
486 1
        }
487 1
    }
488
489
    /**
490
     * Ensure sharding for collection by document name.
491
     *
492 2
     * @param string $documentName
493
     * @param array  $indexOptions Options for `ensureIndex` command. It's performed on an existing collections.
494
     *
495
     * @throws MongoDBException
496 2
     */
497 2
    public function ensureDocumentSharding($documentName, array $indexOptions = [])
498
    {
499
        $class = $this->dm->getClassMetadata($documentName);
500
        if (! $class->isSharded()) {
501
            return;
502
        }
503
504
        $this->enableShardingForDbByDocumentName($documentName);
505
506
        $try = 0;
507
        do {
508
            try {
509
                $result = $this->runShardCollectionCommand($documentName);
510 2
                $done = true;
511
512 2
                // Need to check error message because MongoDB 3.0 does not return a code for this error
513 2
                if (! (bool) $result['ok'] && strpos($result['errmsg'], 'please create an index that starts') !== false) {
514
                    // The proposed key is not returned when using mongo-php-adapter with ext-mongodb.
515
                    // See https://github.com/mongodb/mongo-php-driver/issues/296 for details
516 2
                    $key = $result['proposedKey'] ?? $this->dm->getClassMetadata($documentName)->getShardKey()['keys'];
517 1
518 1
                    $this->dm->getDocumentCollection($documentName)->ensureIndex($key, $indexOptions);
519
                    $done = false;
520
                }
521
            } 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...
522 2
                if ($e->getCode() === 20 || $e->getCode() === 23 || $e->getMessage() === 'already sharded') {
523
                    return;
524
                }
525
526
                throw $e;
527
            }
528
        } 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...
529 2
530
        // Starting with MongoDB 3.2, this command returns code 20 when a collection is already sharded.
531 2
        // For older MongoDB versions, check the error message
532 2
        if ((bool) $result['ok'] || (isset($result['code']) && $result['code'] === 20) || $result['errmsg'] === 'already sharded') {
533 2
            return;
534 2
        }
535
536 2
        throw MongoDBException::failedToEnsureDocumentSharding($documentName, $result['errmsg']);
537
    }
538 2
539 2
    /**
540
     * Enable sharding for database which contains documents with given name.
541 2
     *
542
     * @param string $documentName
543 2
     *
544
     * @throws MongoDBException
545
     */
546
    public function enableShardingForDbByDocumentName($documentName)
547
    {
548
        $dbName = $this->dm->getDocumentDatabase($documentName)->getDatabaseName();
549
        $adminDb = $this->dm->getClient()->selectDatabase('admin');
550
551
        try {
552
            $adminDb->command(['enableSharding' => $dbName]);
553
        } 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...
554
            if ($e->getCode() !== 23 || $e->getMessage() === 'already enabled') {
555
                throw MongoDBException::failedToEnableSharding($dbName, $e->getMessage());
556
            }
557
        }
558
    }
559
560
    /**
561
     * @param string $documentName
562
     *
563
     * @return array
564
     */
565
    private function runShardCollectionCommand($documentName)
566
    {
567
        $class = $this->dm->getClassMetadata($documentName);
568
        $dbName = $this->dm->getDocumentDatabase($documentName)->getDatabaseName();
569
        $shardKey = $class->getShardKey();
570
        $adminDb = $this->dm->getClient()->selectDatabase('admin');
571
572
        $result = $adminDb->command(
573
            [
574
                'shardCollection' => $dbName . '.' . $class->getCollection(),
575
                'key'             => $shardKey['keys'],
576
            ]
577
        )->toArray()[0];
578
579
        return $result;
580
    }
581
582
    private function ensureGridFSIndexes(ClassMetadata $class): void
583
    {
584
        $this->ensureChunksIndex($class);
585
        $this->ensureFilesIndex($class);
586
    }
587
588
    private function ensureChunksIndex(ClassMetadata $class): void
589
    {
590
        $chunksCollection = $this->dm->getDocumentBucket($class->getName())->getChunksCollection();
0 ignored issues
show
Bug introduced by
Consider using $class->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
591
        foreach ($chunksCollection->listIndexes() as $index) {
592
            if ($index->isUnique() && $index->getKey() === self::GRIDFS_FILE_COLLECTION_INDEX) {
593
                return;
594
            }
595
        }
596
597
        $chunksCollection->createIndex(self::GRIDFS_FILE_COLLECTION_INDEX, ['unique' => true]);
598
    }
599
600
    private function ensureFilesIndex(ClassMetadata $class): void
601
    {
602
        $filesCollection = $this->dm->getDocumentCollection($class->getName());
0 ignored issues
show
Bug introduced by
Consider using $class->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
603
        foreach ($filesCollection->listIndexes() as $index) {
604
            if ($index->getKey() === self::GRIDFS_CHUNKS_COLLECTION_INDEX) {
605
                return;
606
            }
607
        }
608
609
        $filesCollection->createIndex(self::GRIDFS_CHUNKS_COLLECTION_INDEX);
610
    }
611
}
612