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

SchemaManager::dropDocumentCollection()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 5.0342

Importance

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