Completed
Pull Request — master (#1908)
by
unknown
15:50
created

DocumentManager::getDocumentCollection()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 5.0073

Importance

Changes 0
Metric Value
dl 0
loc 29
ccs 14
cts 15
cp 0.9333
rs 9.1448
c 0
b 0
f 0
cc 5
nc 5
nop 1
crap 5.0073
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ODM\MongoDB;
6
7
use Doctrine\Common\EventManager;
8
use Doctrine\Common\Persistence\ObjectManager;
9
use Doctrine\Common\Persistence\ObjectRepository;
10
use Doctrine\ODM\MongoDB\Hydrator\HydratorFactory;
11
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
12
use Doctrine\ODM\MongoDB\Mapping\ClassMetadataFactory;
13
use Doctrine\ODM\MongoDB\Mapping\MappingException;
14
use Doctrine\ODM\MongoDB\Proxy\ClassNameResolver;
15
use Doctrine\ODM\MongoDB\Proxy\Factory\ProxyFactory;
16
use Doctrine\ODM\MongoDB\Proxy\Factory\StaticProxyFactory;
17
use Doctrine\ODM\MongoDB\Query\FilterCollection;
18
use Doctrine\ODM\MongoDB\Repository\RepositoryFactory;
19
use InvalidArgumentException;
20
use MongoDB\Client;
21
use MongoDB\Collection;
22
use MongoDB\Database;
23
use MongoDB\Driver\ReadPreference;
24
use MongoDB\GridFS\Bucket;
25
use RuntimeException;
26
use function array_search;
27
use function get_class;
28
use function gettype;
29
use function is_object;
30
use function ltrim;
31
use function sprintf;
32
33
/**
34
 * The DocumentManager class is the central access point for managing the
35
 * persistence of documents.
36
 *
37
 *     <?php
38
 *
39
 *     $config = new Configuration();
40
 *     $dm = DocumentManager::create(new Connection(), $config);
41
 */
42
class DocumentManager implements ObjectManager
43
{
44
    public const CLIENT_TYPEMAP = ['root' => 'array', 'document' => 'array'];
45
46
    /**
47
     * The Doctrine MongoDB connection instance.
48
     *
49
     * @var Client
50
     */
51
    private $client;
52
53
    /**
54
     * The used Configuration.
55
     *
56
     * @var Configuration
57
     */
58
    private $config;
59
60
    /**
61
     * The metadata factory, used to retrieve the ODM metadata of document classes.
62
     *
63
     * @var ClassMetadataFactory
64
     */
65
    private $metadataFactory;
66
67
    /**
68
     * The UnitOfWork used to coordinate object-level transactions.
69
     *
70
     * @var UnitOfWork
71
     */
72
    private $unitOfWork;
73
74
    /**
75
     * The event manager that is the central point of the event system.
76
     *
77
     * @var EventManager
78
     */
79
    private $eventManager;
80
81
    /**
82
     * The Hydrator factory instance.
83
     *
84
     * @var HydratorFactory
85
     */
86
    private $hydratorFactory;
87
88
    /**
89
     * The Proxy factory instance.
90
     *
91
     * @var ProxyFactory
92
     */
93
    private $proxyFactory;
94
95
    /**
96
     * The repository factory used to create dynamic repositories.
97
     *
98
     * @var RepositoryFactory
99
     */
100
    private $repositoryFactory;
101
102
    /**
103
     * SchemaManager instance
104
     *
105
     * @var SchemaManager
106
     */
107
    private $schemaManager;
108
109
    /**
110
     * Array of cached document database instances that are lazily loaded.
111
     *
112
     * @var Database[]
113
     */
114
    private $documentDatabases = [];
115
116
    /**
117
     * Array of cached document collection instances that are lazily loaded.
118
     *
119
     * @var Collection[]
120
     */
121
    private $documentCollections = [];
122
123
    /**
124
     * Array of cached document bucket instances that are lazily loaded.
125
     *
126
     * @var Bucket[]
127
     */
128
    private $documentBuckets = [];
129
130
    /**
131
     * Whether the DocumentManager is closed or not.
132
     *
133
     * @var bool
134
     */
135
    private $closed = false;
136
137
    /**
138
     * Collection of query filters.
139
     *
140
     * @var FilterCollection
141
     */
142
    private $filterCollection;
143
144
    /** @var ClassNameResolver */
145
    private $classNameResolver;
146
147
    /** @var ClassMetadata[]  */
148
    private $classMetadataCache = [];
149
150
    /**
151
     * Creates a new Document that operates on the given Mongo connection
152
     * and uses the given Configuration.
153
     */
154 1642
    protected function __construct(?Client $client = null, ?Configuration $config = null, ?EventManager $eventManager = null)
155
    {
156 1642
        $this->config       = $config ?: new Configuration();
157 1642
        $this->eventManager = $eventManager ?: new EventManager();
158 1642
        $this->client       = $client ?: new Client('mongodb://127.0.0.1', [], ['typeMap' => self::CLIENT_TYPEMAP]);
159
160 1642
        $this->checkTypeMap();
161
162 1642
        $metadataFactoryClassName = $this->config->getClassMetadataFactoryName();
163 1642
        $this->metadataFactory    = new $metadataFactoryClassName();
164 1642
        $this->metadataFactory->setDocumentManager($this);
165 1642
        $this->metadataFactory->setConfiguration($this->config);
166
167 1642
        $cacheDriver = $this->config->getMetadataCacheImpl();
168 1642
        if ($cacheDriver) {
169
            $this->metadataFactory->setCacheDriver($cacheDriver);
170
        }
171
172 1642
        $hydratorDir           = $this->config->getHydratorDir();
173 1642
        $hydratorNs            = $this->config->getHydratorNamespace();
174 1642
        $this->hydratorFactory = new HydratorFactory(
175 1642
            $this,
176 1642
            $this->eventManager,
177 1642
            $hydratorDir,
178 1642
            $hydratorNs,
179 1642
            $this->config->getAutoGenerateHydratorClasses()
180
        );
181
182 1642
        $this->unitOfWork = new UnitOfWork($this, $this->eventManager, $this->hydratorFactory);
183 1642
        $this->hydratorFactory->setUnitOfWork($this->unitOfWork);
184 1642
        $this->schemaManager     = new SchemaManager($this, $this->metadataFactory);
185 1642
        $this->proxyFactory      = new StaticProxyFactory($this);
186 1642
        $this->repositoryFactory = $this->config->getRepositoryFactory();
187 1642
        $this->classNameResolver = new ClassNameResolver($this->config);
188 1642
    }
189
190
    /**
191
     * Gets the proxy factory used by the DocumentManager to create document proxies.
192
     */
193 1
    public function getProxyFactory() : ProxyFactory
194
    {
195 1
        return $this->proxyFactory;
196
    }
197
198
    /**
199
     * Creates a new Document that operates on the given Mongo connection
200
     * and uses the given Configuration.
201
     */
202 1642
    public static function create(?Client $client = null, ?Configuration $config = null, ?EventManager $eventManager = null) : DocumentManager
203
    {
204 1642
        return new static($client, $config, $eventManager);
205
    }
206
207
    /**
208
     * Gets the EventManager used by the DocumentManager.
209
     */
210 1705
    public function getEventManager() : EventManager
211
    {
212 1705
        return $this->eventManager;
213
    }
214
215
    /**
216
     * Gets the MongoDB client instance that this DocumentManager wraps.
217
     */
218 1642
    public function getClient() : Client
219
    {
220 1642
        return $this->client;
221
    }
222
223
    /**
224
     * Gets the metadata factory used to gather the metadata of classes.
225
     *
226
     * @return ClassMetadataFactory
227
     */
228 5
    public function getMetadataFactory()
229
    {
230 5
        return $this->metadataFactory;
231
    }
232
233
    /**
234
     * Helper method to initialize a lazy loading proxy or persistent collection.
235
     *
236
     * This method is a no-op for other objects.
237
     *
238
     * @param object $obj
239
     */
240
    public function initializeObject($obj)
241
    {
242
        $this->unitOfWork->initializeObject($obj);
243
    }
244
245
    /**
246
     * Gets the UnitOfWork used by the DocumentManager to coordinate operations.
247
     */
248 1649
    public function getUnitOfWork() : UnitOfWork
249
    {
250 1649
        return $this->unitOfWork;
251
    }
252
253
    /**
254
     * Gets the Hydrator factory used by the DocumentManager to generate and get hydrators
255
     * for each type of document.
256
     */
257 67
    public function getHydratorFactory() : HydratorFactory
258
    {
259 67
        return $this->hydratorFactory;
260
    }
261
262
    /**
263
     * Returns SchemaManager, used to create/drop indexes/collections/databases.
264
     */
265 28
    public function getSchemaManager() : SchemaManager
266
    {
267 28
        return $this->schemaManager;
268
    }
269
270
    /** Returns the class name resolver which is used to resolve real class names for proxy objects. */
271 1433
    public function getClassNameResolver() : ClassNameResolver
272
    {
273 1433
        return $this->classNameResolver;
274
    }
275
276
    /**
277
     * Returns the metadata for a class.
278
     *
279
     * @internal Performance-sensitive method.
280
     *
281
     * @param string $className The class name.
282
     */
283 1369
    public function getClassMetadata($className) : ClassMetadata
284
    {
285 1369
        if (empty($this->classMetadataCache[$className])) {
286 1369
            $this->classMetadataCache[$className] = $this->metadataFactory->getMetadataFor($className);
287
        }
288
289 1366
        return $this->classMetadataCache[$className];
290
    }
291
292
    /**
293
     * Returns the MongoDB instance for a class.
294
     */
295 1298
    public function getDocumentDatabase(string $className) : Database
296
    {
297 1298
        $className = $this->classNameResolver->getRealClass($className);
298
299 1298
        if (isset($this->documentDatabases[$className])) {
300 46
            return $this->documentDatabases[$className];
301
        }
302
303 1293
        $metadata                            = $this->metadataFactory->getMetadataFor($className);
304 1293
        $db                                  = $metadata->getDatabase();
305 1293
        $db                                  = $db ?: $this->config->getDefaultDB();
306 1293
        $db                                  = $db ?: 'doctrine';
307 1293
        $this->documentDatabases[$className] = $this->client->selectDatabase($db);
308
309 1293
        return $this->documentDatabases[$className];
310
    }
311
312
    /**
313
     * Gets the array of instantiated document database instances.
314
     *
315
     * @return Database[]
316
     */
317
    public function getDocumentDatabases() : array
318
    {
319
        return $this->documentDatabases;
320
    }
321
322
    /**
323
     * Returns the collection instance for a class.
324
     *
325
     * @throws MongoDBException When the $className param is not mapped to a collection.
326
     */
327 1301
    public function getDocumentCollection(string $className) : Collection
328
    {
329 1301
        $className = $this->classNameResolver->getRealClass($className);
330
331
        /** @var ClassMetadata $metadata */
332 1301
        $metadata = $this->metadataFactory->getMetadataFor($className);
333 1301
        if ($metadata->isFile) {
334 16
            return $this->getDocumentBucket($className)->getFilesCollection();
335
        }
336
337 1290
        $collectionName = $metadata->getCollection();
338
339 1290
        if (! $collectionName) {
340
            throw MongoDBException::documentNotMappedToCollection($className);
341
        }
342
343 1290
        if (! isset($this->documentCollections[$className])) {
344 1280
            $db = $this->getDocumentDatabase($className);
345
346 1280
            $options = [];
347 1280
            if ($metadata->readPreference !== null) {
348 3
                $options['readPreference'] = new ReadPreference($metadata->readPreference, $metadata->readPreferenceTags);
349
            }
350
351 1280
            $this->documentCollections[$className] = $db->selectCollection($collectionName, $options);
352
        }
353
354 1290
        return $this->documentCollections[$className];
355
    }
356
357
    /**
358
     * Returns the bucket instance for a class.
359
     *
360
     * @throws MongoDBException When the $className param is not mapped to a collection.
361
     */
362 16
    public function getDocumentBucket(string $className) : Bucket
363
    {
364 16
        $className = $this->classNameResolver->getRealClass($className);
365
366
        /** @var ClassMetadata $metadata */
367 16
        $metadata = $this->metadataFactory->getMetadataFor($className);
368 16
        if (! $metadata->isFile) {
369
            throw MongoDBException::documentBucketOnlyAvailableForGridFSFiles($className);
370
        }
371
372 16
        $bucketName = $metadata->getBucketName();
373
374 16
        if (! $bucketName) {
375
            throw MongoDBException::documentNotMappedToCollection($className);
376
        }
377
378 16
        if (! isset($this->documentBuckets[$className])) {
379 11
            $db = $this->getDocumentDatabase($className);
380
381 11
            $options = ['bucketName' => $bucketName];
382 11
            if ($metadata->readPreference !== null) {
383
                $options['readPreference'] = new ReadPreference($metadata->readPreference, $metadata->readPreferenceTags);
384
            }
385
386 11
            $this->documentBuckets[$className] = $db->selectGridFSBucket($options);
387
        }
388
389 16
        return $this->documentBuckets[$className];
390
    }
391
392
    /**
393
     * Gets the array of instantiated document collection instances.
394
     *
395
     * @return Collection[]
396
     */
397
    public function getDocumentCollections() : array
398
    {
399
        return $this->documentCollections;
400
    }
401
402
    /**
403
     * Create a new Query instance for a class.
404
     *
405
     * @param string[]|string|null $documentName (optional) an array of document names, the document name, or none
406
     */
407 179
    public function createQueryBuilder($documentName = null) : Query\Builder
408
    {
409 179
        return new Query\Builder($this, $documentName);
410
    }
411
412
    /**
413
     * Creates a new aggregation builder instance for a class.
414
     */
415 41
    public function createAggregationBuilder(string $documentName) : Aggregation\Builder
416
    {
417 41
        return new Aggregation\Builder($this, $documentName);
418
    }
419
420
    /**
421
     * Tells the DocumentManager to make an instance managed and persistent.
422
     *
423
     * The document will be entered into the database at or before transaction
424
     * commit or as a result of the flush operation.
425
     *
426
     * NOTE: The persist operation always considers documents that are not yet known to
427
     * this DocumentManager as NEW. Do not pass detached documents to the persist operation.
428
     *
429
     * @param object $document The instance to make managed and persistent.
430
     *
431
     * @throws InvalidArgumentException When the given $document param is not an object.
432
     */
433 616
    public function persist($document)
434
    {
435 616
        if (! is_object($document)) {
436 1
            throw new InvalidArgumentException(gettype($document));
437
        }
438 615
        $this->errorIfClosed();
439 614
        $this->unitOfWork->persist($document);
440 610
    }
441
442
    /**
443
     * Removes a document instance.
444
     *
445
     * A removed document will be removed from the database at or before transaction commit
446
     * or as a result of the flush operation.
447
     *
448
     * @param object $document The document instance to remove.
449
     *
450
     * @throws InvalidArgumentException When the $document param is not an object.
451
     */
452 27
    public function remove($document)
453
    {
454 27
        if (! is_object($document)) {
455 1
            throw new InvalidArgumentException(gettype($document));
456
        }
457 26
        $this->errorIfClosed();
458 25
        $this->unitOfWork->remove($document);
459 25
    }
460
461
    /**
462
     * Refreshes the persistent state of a document from the database,
463
     * overriding any local changes that have not yet been persisted.
464
     *
465
     * @param object $document The document to refresh.
466
     *
467
     * @throws InvalidArgumentException When the given $document param is not an object.
468
     */
469 26
    public function refresh($document)
470
    {
471 26
        if (! is_object($document)) {
472 1
            throw new InvalidArgumentException(gettype($document));
473
        }
474 25
        $this->errorIfClosed();
475 24
        $this->unitOfWork->refresh($document);
476 23
    }
477
478
    /**
479
     * Detaches a document from the DocumentManager, causing a managed document to
480
     * become detached.  Unflushed changes made to the document if any
481
     * (including removal of the document), will not be synchronized to the database.
482
     * Documents which previously referenced the detached document will continue to
483
     * reference it.
484
     *
485
     * @param object $document The document to detach.
486
     *
487
     * @throws InvalidArgumentException When the $document param is not an object.
488
     */
489 11
    public function detach($document)
490
    {
491 11
        if (! is_object($document)) {
492 1
            throw new InvalidArgumentException(gettype($document));
493
        }
494 10
        $this->unitOfWork->detach($document);
495 10
    }
496
497
    /**
498
     * Merges the state of a detached document into the persistence context
499
     * of this DocumentManager and returns the managed copy of the document.
500
     * The document passed to merge will not become associated/managed with this DocumentManager.
501
     *
502
     * @param object $document The detached document to merge into the persistence context.
503
     *
504
     * @return object The managed copy of the document.
505
     *
506
     * @throws LockException
507
     * @throws InvalidArgumentException If the $document param is not an object.
508
     */
509 13
    public function merge($document)
510
    {
511 13
        if (! is_object($document)) {
512 1
            throw new InvalidArgumentException(gettype($document));
513
        }
514 12
        $this->errorIfClosed();
515 11
        return $this->unitOfWork->merge($document);
516
    }
517
518
    /**
519
     * Acquire a lock on the given document.
520
     *
521
     * @throws InvalidArgumentException
522
     * @throws LockException
523
     */
524 8
    public function lock(object $document, int $lockMode, ?int $lockVersion = null) : void
525
    {
526 8
        $this->unitOfWork->lock($document, $lockMode, $lockVersion);
527 5
    }
528
529
    /**
530
     * Releases a lock on the given document.
531
     */
532 1
    public function unlock(object $document) : void
533
    {
534 1
        $this->unitOfWork->unlock($document);
535 1
    }
536
537
    /**
538
     * Gets the repository for a document class.
539
     *
540
     * @param string $documentName The name of the Document.
541
     *
542
     * @return ObjectRepository  The repository.
543
     */
544 345
    public function getRepository($documentName)
545
    {
546 345
        return $this->repositoryFactory->getRepository($this, $documentName);
547
    }
548
549
    /**
550
     * Flushes all changes to objects that have been queued up to now to the database.
551
     * This effectively synchronizes the in-memory state of managed objects with the
552
     * database.
553
     *
554
     * @param array $options Array of options to be used with batchInsert(), update() and remove()
555
     *
556
     * @throws MongoDBException
557
     */
558 588
    public function flush(array $options = [])
559
    {
560 588
        $this->errorIfClosed();
561 587
        $this->unitOfWork->commit($options);
562 572
    }
563
564
    /**
565
     * Gets a reference to the document identified by the given type and identifier
566
     * without actually loading it.
567
     *
568
     * If partial objects are allowed, this method will return a partial object that only
569
     * has its identifier populated. Otherwise a proxy is returned that automatically
570
     * loads itself on first access.
571
     *
572
     * @param string|object $identifier
573
     */
574 127
    public function getReference(string $documentName, $identifier) : object
575
    {
576
        /** @var ClassMetadata $class */
577 127
        $class    = $this->metadataFactory->getMetadataFor(ltrim($documentName, '\\'));
578 127
        $document = $this->unitOfWork->tryGetById($identifier, $class);
579
580
        // Check identity map first, if its already in there just return it.
581 127
        if ($document) {
582 56
            return $document;
583
        }
584
585 98
        $document = $this->proxyFactory->getProxy($class, $identifier);
586 98
        $this->unitOfWork->registerManaged($document, $identifier, []);
587
588 98
        return $document;
589
    }
590
591
    /**
592
     * Gets a partial reference to the document identified by the given type and identifier
593
     * without actually loading it, if the document is not yet loaded.
594
     *
595
     * The returned reference may be a partial object if the document is not yet loaded/managed.
596
     * If it is a partial object it will not initialize the rest of the document state on access.
597
     * Thus you can only ever safely access the identifier of a document obtained through
598
     * this method.
599
     *
600
     * The use-cases for partial references involve maintaining bidirectional associations
601
     * without loading one side of the association or to update a document without loading it.
602
     * Note, however, that in the latter case the original (persistent) document data will
603
     * never be visible to the application (especially not event listeners) as it will
604
     * never be loaded in the first place.
605
     *
606
     * @param mixed $identifier The document identifier.
607
     */
608 1
    public function getPartialReference(string $documentName, $identifier) : object
609
    {
610 1
        $class    = $this->metadataFactory->getMetadataFor(ltrim($documentName, '\\'));
611 1
        $document = $this->unitOfWork->tryGetById($identifier, $class);
612
613
        // Check identity map first, if its already in there just return it.
614 1
        if ($document) {
615
            return $document;
616
        }
617 1
        $document = $class->newInstance();
618 1
        $class->setIdentifierValue($document, $identifier);
619 1
        $this->unitOfWork->registerManaged($document, $identifier, []);
620
621 1
        return $document;
622
    }
623
624
    /**
625
     * Finds a Document by its identifier.
626
     *
627
     * This is just a convenient shortcut for getRepository($documentName)->find($id).
628
     *
629
     * @param string $documentName
630
     * @param mixed  $identifier
631
     * @param int    $lockMode
632
     * @param int    $lockVersion
633
     *
634
     * @return object $document
635
     */
636 174
    public function find($documentName, $identifier, $lockMode = LockMode::NONE, $lockVersion = null)
637
    {
638 174
        return $this->getRepository($documentName)->find($identifier, $lockMode, $lockVersion);
639
    }
640
641
    /**
642
     * Clears the DocumentManager.
643
     *
644
     * All documents that are currently managed by this DocumentManager become
645
     * detached.
646
     *
647
     * @param string|null $documentName if given, only documents of this type will get detached
648
     */
649 377
    public function clear($documentName = null)
650
    {
651 377
        $this->unitOfWork->clear($documentName);
652 377
    }
653
654
    /**
655
     * Closes the DocumentManager. All documents that are currently managed
656
     * by this DocumentManager become detached. The DocumentManager may no longer
657
     * be used after it is closed.
658
     */
659 6
    public function close()
660
    {
661 6
        $this->clear();
662 6
        $this->closed = true;
663 6
    }
664
665
    /**
666
     * Determines whether a document instance is managed in this DocumentManager.
667
     *
668
     * @param object $document
669
     *
670
     * @return bool TRUE if this DocumentManager currently manages the given document, FALSE otherwise.
671
     *
672
     * @throws InvalidArgumentException When the $document param is not an object.
673
     */
674 3
    public function contains($document)
675
    {
676 3
        if (! is_object($document)) {
677
            throw new InvalidArgumentException(gettype($document));
678
        }
679 3
        return $this->unitOfWork->isScheduledForInsert($document) ||
680 3
            $this->unitOfWork->isInIdentityMap($document) &&
681 3
            ! $this->unitOfWork->isScheduledForDelete($document);
682
    }
683
684
    /**
685
     * Gets the Configuration used by the DocumentManager.
686
     */
687 1705
    public function getConfiguration() : Configuration
688
    {
689 1705
        return $this->config;
690
    }
691
692
    /**
693
     * Returns a reference to the supplied document.
694
     *
695
     * @return mixed The reference for the document in question, according to the desired mapping
696
     *
697
     * @throws MappingException
698
     * @throws RuntimeException
699
     */
700 225
    public function createReference(object $document, array $referenceMapping)
701
    {
702 225
        $class = $this->getClassMetadata(get_class($document));
703 225
        $id    = $this->unitOfWork->getDocumentIdentifier($document);
704
705 225
        if ($id === null) {
706 1
            throw new RuntimeException(
707 1
                sprintf('Cannot create a DBRef for class %s without an identifier. Have you forgotten to persist/merge the document first?', $class->name)
708
            );
709
        }
710
711 224
        $storeAs   = $referenceMapping['storeAs'] ?? null;
712 224
        $reference = [];
0 ignored issues
show
Unused Code introduced by
$reference is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
713 224
        switch ($storeAs) {
714
            case ClassMetadata::REFERENCE_STORE_AS_ID:
715 46
                if ($class->inheritanceType === ClassMetadata::INHERITANCE_TYPE_SINGLE_COLLECTION) {
716 1
                    throw MappingException::simpleReferenceMustNotTargetDiscriminatedDocument($referenceMapping['targetDocument']);
717
                }
718
719 45
                return $class->getDatabaseIdentifierValue($id);
720
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
721
722
            case ClassMetadata::REFERENCE_STORE_AS_REF:
723 20
                $reference = ['id' => $class->getDatabaseIdentifierValue($id)];
724 20
                break;
725
726
            case ClassMetadata::REFERENCE_STORE_AS_DB_REF:
727
                $reference = [
728 180
                    '$ref' => $class->getCollection(),
729 180
                    '$id'  => $class->getDatabaseIdentifierValue($id),
730
                ];
731 180
                break;
732
733
            case ClassMetadata::REFERENCE_STORE_AS_DB_REF_WITH_DB:
734
                $reference = [
735 17
                    '$ref' => $class->getCollection(),
736 17
                    '$id'  => $class->getDatabaseIdentifierValue($id),
737 17
                    '$db'  => $this->getDocumentDatabase($class->name)->getDatabaseName(),
738
                ];
739 17
                break;
740
741
            default:
742
                throw new InvalidArgumentException(sprintf('Reference type %s is invalid.', $storeAs));
743
        }
744
745 202
        return $reference + $this->getDiscriminatorData($referenceMapping, $class);
746
    }
747
748
    /**
749
     * Build discriminator portion of reference for specified reference mapping and class metadata.
750
     *
751
     * @param array         $referenceMapping Mappings of reference for which discriminator data is created.
752
     * @param ClassMetadata $class            Metadata of reference document class.
753
     *
754
     * @return array with next structure [{discriminator field} => {discriminator value}]
755
     *
756
     * @throws MappingException When discriminator map is present and reference class in not registered in it.
757
     */
758 202
    private function getDiscriminatorData(array $referenceMapping, ClassMetadata $class) : array
759
    {
760 202
        $discriminatorField = null;
0 ignored issues
show
Unused Code introduced by
$discriminatorField is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
761 202
        $discriminatorValue = null;
762 202
        $discriminatorData  = [];
763 202
        if (isset($referenceMapping['discriminatorField'])) {
764 33
            $discriminatorField = $referenceMapping['discriminatorField'];
765 33
            if (isset($referenceMapping['discriminatorMap'])) {
766 8
                $pos = array_search($class->name, $referenceMapping['discriminatorMap']);
767 8
                if ($pos !== false) {
768 8
                    $discriminatorValue = $pos;
769
                }
770
            } else {
771 33
                $discriminatorValue = $class->name;
772
            }
773
        } else {
774 183
            $discriminatorField = $class->discriminatorField;
775 183
            $discriminatorValue = $class->discriminatorValue;
776
        }
777
778 202
        if ($discriminatorField !== null) {
779 44
            if ($discriminatorValue === null) {
780 4
                throw MappingException::unlistedClassInDiscriminatorMap($class->name);
781
            }
782 42
            $discriminatorData = [$discriminatorField => $discriminatorValue];
783 172
        } elseif (! isset($referenceMapping['targetDocument'])) {
784
            $discriminatorField = $referenceMapping['discriminatorField'];
785
786
            $discriminatorMap = null;
787
            if (isset($referenceMapping['discriminatorMap'])) {
788
                $discriminatorMap = $referenceMapping['discriminatorMap'];
789
            }
790
            if ($discriminatorMap === null) {
791
                $discriminatorValue = $class->name;
792
            } else {
793
                $discriminatorValue = array_search($class->name, $discriminatorMap);
794
795
                if ($discriminatorValue === false) {
796
                    throw MappingException::unlistedClassInDiscriminatorMap($class->name);
797
                }
798
            }
799
            $discriminatorData = [$discriminatorField => $discriminatorValue];
800
        }
801
802 200
        return $discriminatorData;
803
    }
804
805
    /**
806
     * Throws an exception if the DocumentManager is closed or currently not active.
807
     *
808
     * @throws MongoDBException If the DocumentManager is closed.
809
     */
810 621
    private function errorIfClosed() : void
811
    {
812 621
        if ($this->closed) {
813 5
            throw MongoDBException::documentManagerClosed();
814
        }
815 616
    }
816
817
    /**
818
     * Check if the Document manager is open or closed.
819
     */
820 1
    public function isOpen() : bool
821
    {
822 1
        return ! $this->closed;
823
    }
824
825
    /**
826
     * Gets the filter collection.
827
     */
828 523
    public function getFilterCollection() : FilterCollection
829
    {
830 523
        if ($this->filterCollection === null) {
831 523
            $this->filterCollection = new FilterCollection($this);
832
        }
833
834 523
        return $this->filterCollection;
835
    }
836
837 1642
    private function checkTypeMap() : void
838
    {
839 1642
        $typeMap = $this->client->getTypeMap();
840
841 1642
        foreach (self::CLIENT_TYPEMAP as $part => $expectedType) {
842 1642
            if (! isset($typeMap[$part]) || $typeMap[$part] !== $expectedType) {
843 1642
                throw MongoDBException::invalidTypeMap($part, $expectedType);
844
            }
845
        }
846 1642
    }
847
}
848