Completed
Push — master ( bd5dde...8fcee2 )
by Andreas
19:58 queued 10s
created

DocumentManager::createReference()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 44

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 7.0046

Importance

Changes 0
Metric Value
dl 0
loc 44
ccs 21
cts 22
cp 0.9545
rs 8.2826
c 0
b 0
f 0
cc 7
nc 7
nop 2
crap 7.0046
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\Factory\ProxyFactory;
15
use Doctrine\ODM\MongoDB\Proxy\Factory\StaticProxyFactory;
16
use Doctrine\ODM\MongoDB\Proxy\Resolver\CachingClassNameResolver;
17
use Doctrine\ODM\MongoDB\Proxy\Resolver\ClassNameResolver;
18
use Doctrine\ODM\MongoDB\Proxy\Resolver\ProxyManagerClassNameResolver;
19
use Doctrine\ODM\MongoDB\Query\FilterCollection;
20
use Doctrine\ODM\MongoDB\Repository\DocumentRepository;
21
use Doctrine\ODM\MongoDB\Repository\RepositoryFactory;
22
use InvalidArgumentException;
23
use MongoDB\Client;
24
use MongoDB\Collection;
25
use MongoDB\Database;
26
use MongoDB\Driver\ReadPreference;
27
use MongoDB\GridFS\Bucket;
28
use RuntimeException;
29
use function array_search;
30
use function assert;
31
use function get_class;
32
use function gettype;
33
use function is_object;
34
use function ltrim;
35
use function sprintf;
36
37
/**
38
 * The DocumentManager class is the central access point for managing the
39
 * persistence of documents.
40
 *
41
 *     <?php
42
 *
43
 *     $config = new Configuration();
44
 *     $dm = DocumentManager::create(new Connection(), $config);
45
 */
46
class DocumentManager implements ObjectManager
47
{
48
    public const CLIENT_TYPEMAP = ['root' => 'array', 'document' => 'array'];
49
50
    /**
51
     * The Doctrine MongoDB connection instance.
52
     *
53
     * @var Client
54
     */
55
    private $client;
56
57
    /**
58
     * The used Configuration.
59
     *
60
     * @var Configuration
61
     */
62
    private $config;
63
64
    /**
65
     * The metadata factory, used to retrieve the ODM metadata of document classes.
66
     *
67
     * @var ClassMetadataFactory
68
     */
69
    private $metadataFactory;
70
71
    /**
72
     * The UnitOfWork used to coordinate object-level transactions.
73
     *
74
     * @var UnitOfWork
75
     */
76
    private $unitOfWork;
77
78
    /**
79
     * The event manager that is the central point of the event system.
80
     *
81
     * @var EventManager
82
     */
83
    private $eventManager;
84
85
    /**
86
     * The Hydrator factory instance.
87
     *
88
     * @var HydratorFactory
89
     */
90
    private $hydratorFactory;
91
92
    /**
93
     * The Proxy factory instance.
94
     *
95
     * @var ProxyFactory
96
     */
97
    private $proxyFactory;
98
99
    /**
100
     * The repository factory used to create dynamic repositories.
101
     *
102
     * @var RepositoryFactory
103
     */
104
    private $repositoryFactory;
105
106
    /**
107
     * SchemaManager instance
108
     *
109
     * @var SchemaManager
110
     */
111
    private $schemaManager;
112
113
    /**
114
     * Array of cached document database instances that are lazily loaded.
115
     *
116
     * @var Database[]
117
     */
118
    private $documentDatabases = [];
119
120
    /**
121
     * Array of cached document collection instances that are lazily loaded.
122
     *
123
     * @var Collection[]
124
     */
125
    private $documentCollections = [];
126
127
    /**
128
     * Array of cached document bucket instances that are lazily loaded.
129
     *
130
     * @var Bucket[]
131
     */
132
    private $documentBuckets = [];
133
134
    /**
135
     * Whether the DocumentManager is closed or not.
136
     *
137
     * @var bool
138
     */
139
    private $closed = false;
140
141
    /**
142
     * Collection of query filters.
143
     *
144
     * @var FilterCollection
145
     */
146
    private $filterCollection;
147
148
    /** @var ClassNameResolver */
149
    private $classNameResolver;
150
151
    /**
152
     * Creates a new Document that operates on the given Mongo connection
153
     * and uses the given Configuration.
154
     */
155 1773
    protected function __construct(?Client $client = null, ?Configuration $config = null, ?EventManager $eventManager = null)
156
    {
157 1773
        $this->config       = $config ?: new Configuration();
158 1773
        $this->eventManager = $eventManager ?: new EventManager();
159 1773
        $this->client       = $client ?: new Client('mongodb://127.0.0.1', [], ['typeMap' => self::CLIENT_TYPEMAP]);
160
161 1773
        $this->checkTypeMap();
162
163 1773
        $metadataFactoryClassName = $this->config->getClassMetadataFactoryName();
164 1773
        $this->metadataFactory    = new $metadataFactoryClassName();
165 1773
        $this->metadataFactory->setDocumentManager($this);
166 1773
        $this->metadataFactory->setConfiguration($this->config);
167
168 1773
        $cacheDriver = $this->config->getMetadataCacheImpl();
169 1773
        if ($cacheDriver) {
170
            $this->metadataFactory->setCacheDriver($cacheDriver);
171
        }
172
173 1773
        $hydratorDir           = $this->config->getHydratorDir();
174 1773
        $hydratorNs            = $this->config->getHydratorNamespace();
175 1773
        $this->hydratorFactory = new HydratorFactory(
176 1773
            $this,
177 1773
            $this->eventManager,
178 1773
            $hydratorDir,
179 1773
            $hydratorNs,
180 1773
            $this->config->getAutoGenerateHydratorClasses()
181
        );
182
183 1773
        $this->unitOfWork = new UnitOfWork($this, $this->eventManager, $this->hydratorFactory);
184 1773
        $this->hydratorFactory->setUnitOfWork($this->unitOfWork);
185 1773
        $this->schemaManager     = new SchemaManager($this, $this->metadataFactory);
186 1773
        $this->proxyFactory      = new StaticProxyFactory($this);
187 1773
        $this->repositoryFactory = $this->config->getRepositoryFactory();
188 1773
        $this->classNameResolver = new CachingClassNameResolver(new ProxyManagerClassNameResolver($this->config));
189 1773
    }
190
191
    /**
192
     * Gets the proxy factory used by the DocumentManager to create document proxies.
193
     */
194 2
    public function getProxyFactory() : ProxyFactory
195
    {
196 2
        return $this->proxyFactory;
197
    }
198
199
    /**
200
     * Creates a new Document that operates on the given Mongo connection
201
     * and uses the given Configuration.
202
     */
203 1773
    public static function create(?Client $client = null, ?Configuration $config = null, ?EventManager $eventManager = null) : DocumentManager
204
    {
205 1773
        return new static($client, $config, $eventManager);
206
    }
207
208
    /**
209
     * Gets the EventManager used by the DocumentManager.
210
     */
211 1773
    public function getEventManager() : EventManager
212
    {
213 1773
        return $this->eventManager;
214
    }
215
216
    /**
217
     * Gets the MongoDB client instance that this DocumentManager wraps.
218
     */
219 1662
    public function getClient() : Client
220
    {
221 1662
        return $this->client;
222
    }
223
224
    /**
225
     * Gets the metadata factory used to gather the metadata of classes.
226
     *
227
     * @return ClassMetadataFactory
228
     */
229 120
    public function getMetadataFactory()
230
    {
231 120
        return $this->metadataFactory;
232
    }
233
234
    /**
235
     * Helper method to initialize a lazy loading proxy or persistent collection.
236
     *
237
     * This method is a no-op for other objects.
238
     *
239
     * @param object $obj
240
     */
241
    public function initializeObject($obj)
242
    {
243
        $this->unitOfWork->initializeObject($obj);
244
    }
245
246
    /**
247
     * Gets the UnitOfWork used by the DocumentManager to coordinate operations.
248
     */
249 1773
    public function getUnitOfWork() : UnitOfWork
250
    {
251 1773
        return $this->unitOfWork;
252
    }
253
254
    /**
255
     * Gets the Hydrator factory used by the DocumentManager to generate and get hydrators
256
     * for each type of document.
257
     */
258 54
    public function getHydratorFactory() : HydratorFactory
259
    {
260 54
        return $this->hydratorFactory;
261
    }
262
263
    /**
264
     * Returns SchemaManager, used to create/drop indexes/collections/databases.
265
     */
266 141
    public function getSchemaManager() : SchemaManager
267
    {
268 141
        return $this->schemaManager;
269
    }
270
271
    /** Returns the class name resolver which is used to resolve real class names for proxy objects. */
272 1548
    public function getClassNameResolver() : ClassNameResolver
273
    {
274 1548
        return $this->classNameResolver;
275
    }
276
277
    /**
278
     * Returns the metadata for a class.
279
     *
280
     * @internal Performance-sensitive method.
281
     *
282
     * @param string $className The class name.
283
     */
284 1488
    public function getClassMetadata($className) : ClassMetadata
285
    {
286 1488
        return $this->metadataFactory->getMetadataFor($className);
287
    }
288
289
    /**
290
     * Returns the MongoDB instance for a class.
291
     */
292 1411
    public function getDocumentDatabase(string $className) : Database
293
    {
294 1411
        $className = $this->classNameResolver->getRealClass($className);
295
296 1411
        if (isset($this->documentDatabases[$className])) {
297 50
            return $this->documentDatabases[$className];
298
        }
299
300 1411
        $metadata = $this->metadataFactory->getMetadataFor($className);
301 1411
        assert($metadata instanceof ClassMetadata);
302
303 1411
        $db                                  = $metadata->getDatabase();
304 1411
        $db                                  = $db ?: $this->config->getDefaultDB();
305 1411
        $db                                  = $db ?: 'doctrine';
306 1411
        $this->documentDatabases[$className] = $this->client->selectDatabase($db);
307
308 1411
        return $this->documentDatabases[$className];
309
    }
310
311
    /**
312
     * Gets the array of instantiated document database instances.
313
     *
314
     * @return Database[]
315
     */
316
    public function getDocumentDatabases() : array
317
    {
318
        return $this->documentDatabases;
319
    }
320
321
    /**
322
     * Returns the collection instance for a class.
323
     *
324
     * @throws MongoDBException When the $className param is not mapped to a collection.
325
     */
326 1387
    public function getDocumentCollection(string $className) : Collection
327
    {
328 1387
        $className = $this->classNameResolver->getRealClass($className);
329
330
        /** @var ClassMetadata $metadata */
331 1387
        $metadata = $this->metadataFactory->getMetadataFor($className);
332 1387
        assert($metadata instanceof ClassMetadata);
333 1387
        if ($metadata->isFile) {
334 33
            return $this->getDocumentBucket($className)->getFilesCollection();
335
        }
336
337 1370
        $collectionName = $metadata->getCollection();
338
339 1370
        if (! $collectionName) {
340
            throw MongoDBException::documentNotMappedToCollection($className);
341
        }
342
343 1370
        if (! isset($this->documentCollections[$className])) {
344 1370
            $db = $this->getDocumentDatabase($className);
345
346 1370
            $options = [];
347 1370
            if ($metadata->readPreference !== null) {
348 3
                $options['readPreference'] = new ReadPreference($metadata->readPreference, $metadata->readPreferenceTags);
349
            }
350
351 1370
            $this->documentCollections[$className] = $db->selectCollection($collectionName, $options);
352
        }
353
354 1370
        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 33
    public function getDocumentBucket(string $className) : Bucket
363
    {
364 33
        $className = $this->classNameResolver->getRealClass($className);
365
366
        /** @var ClassMetadata $metadata */
367 33
        $metadata = $this->metadataFactory->getMetadataFor($className);
368 33
        if (! $metadata->isFile) {
369
            throw MongoDBException::documentBucketOnlyAvailableForGridFSFiles($className);
370
        }
371
372 33
        $bucketName = $metadata->getBucketName();
373
374 33
        if (! $bucketName) {
375
            throw MongoDBException::documentNotMappedToCollection($className);
376
        }
377
378 33
        if (! isset($this->documentBuckets[$className])) {
379 33
            $db = $this->getDocumentDatabase($className);
380
381 33
            $options = ['bucketName' => $bucketName];
382 33
            if ($metadata->readPreference !== null) {
383
                $options['readPreference'] = new ReadPreference($metadata->readPreference, $metadata->readPreferenceTags);
384
            }
385
386 33
            $this->documentBuckets[$className] = $db->selectGridFSBucket($options);
387
        }
388
389 33
        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 181
    public function createQueryBuilder($documentName = null) : Query\Builder
408
    {
409 181
        return new Query\Builder($this, $documentName);
410
    }
411
412
    /**
413
     * Creates a new aggregation builder instance for a class.
414
     */
415 42
    public function createAggregationBuilder(string $documentName) : Aggregation\Builder
416
    {
417 42
        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 639
    public function persist($document)
434
    {
435 639
        if (! is_object($document)) {
436 1
            throw new InvalidArgumentException(gettype($document));
437
        }
438 638
        $this->errorIfClosed();
439 637
        $this->unitOfWork->persist($document);
440 633
    }
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
516 11
        return $this->unitOfWork->merge($document);
517
    }
518
519
    /**
520
     * Acquire a lock on the given document.
521
     *
522
     * @throws InvalidArgumentException
523
     * @throws LockException
524
     */
525 8
    public function lock(object $document, int $lockMode, ?int $lockVersion = null) : void
526
    {
527 8
        $this->unitOfWork->lock($document, $lockMode, $lockVersion);
528 5
    }
529
530
    /**
531
     * Releases a lock on the given document.
532
     */
533 1
    public function unlock(object $document) : void
534
    {
535 1
        $this->unitOfWork->unlock($document);
536 1
    }
537
538
    /**
539
     * Gets the repository for a document class.
540
     *
541
     * @param string $documentName The name of the Document.
542
     *
543
     * @return ObjectRepository  The repository.
544
     */
545 355
    public function getRepository($documentName)
546
    {
547 355
        return $this->repositoryFactory->getRepository($this, $documentName);
548
    }
549
550
    /**
551
     * Flushes all changes to objects that have been queued up to now to the database.
552
     * This effectively synchronizes the in-memory state of managed objects with the
553
     * database.
554
     *
555
     * @param array $options Array of options to be used with batchInsert(), update() and remove()
556
     *
557
     * @throws MongoDBException
558
     */
559 600
    public function flush(array $options = [])
560
    {
561 600
        $this->errorIfClosed();
562 599
        $this->unitOfWork->commit($options);
563 584
    }
564
565
    /**
566
     * Gets a reference to the document identified by the given type and identifier
567
     * without actually loading it.
568
     *
569
     * If partial objects are allowed, this method will return a partial object that only
570
     * has its identifier populated. Otherwise a proxy is returned that automatically
571
     * loads itself on first access.
572
     *
573
     * @param mixed $identifier
574
     */
575 129
    public function getReference(string $documentName, $identifier) : object
576
    {
577
        /** @var ClassMetadata $class */
578 129
        $class    = $this->metadataFactory->getMetadataFor(ltrim($documentName, '\\'));
579 129
        $document = $this->unitOfWork->tryGetById($identifier, $class);
580
581
        // Check identity map first, if its already in there just return it.
582 129
        if ($document) {
583 57
            return $document;
584
        }
585
586 100
        $document = $this->proxyFactory->getProxy($class, $identifier);
587 100
        $this->unitOfWork->registerManaged($document, $identifier, []);
588
589 100
        return $document;
590
    }
591
592
    /**
593
     * Gets a partial reference to the document identified by the given type and identifier
594
     * without actually loading it, if the document is not yet loaded.
595
     *
596
     * The returned reference may be a partial object if the document is not yet loaded/managed.
597
     * If it is a partial object it will not initialize the rest of the document state on access.
598
     * Thus you can only ever safely access the identifier of a document obtained through
599
     * this method.
600
     *
601
     * The use-cases for partial references involve maintaining bidirectional associations
602
     * without loading one side of the association or to update a document without loading it.
603
     * Note, however, that in the latter case the original (persistent) document data will
604
     * never be visible to the application (especially not event listeners) as it will
605
     * never be loaded in the first place.
606
     *
607
     * @param mixed $identifier The document identifier.
608
     */
609 1
    public function getPartialReference(string $documentName, $identifier) : object
610
    {
611 1
        $class = $this->metadataFactory->getMetadataFor(ltrim($documentName, '\\'));
612 1
        assert($class instanceof ClassMetadata);
613 1
        $document = $this->unitOfWork->tryGetById($identifier, $class);
614
615
        // Check identity map first, if its already in there just return it.
616 1
        if ($document) {
617
            return $document;
618
        }
619 1
        $document = $class->newInstance();
620 1
        $class->setIdentifierValue($document, $identifier);
621 1
        $this->unitOfWork->registerManaged($document, $identifier, []);
622
623 1
        return $document;
624
    }
625
626
    /**
627
     * Finds a Document by its identifier.
628
     *
629
     * This is just a convenient shortcut for getRepository($documentName)->find($id).
630
     *
631
     * @param string $documentName
632
     * @param mixed  $identifier
633
     * @param int    $lockMode
634
     * @param int    $lockVersion
635
     */
636 175
    public function find($documentName, $identifier, $lockMode = LockMode::NONE, $lockVersion = null) : ?object
637
    {
638 175
        $repository = $this->getRepository($documentName);
639 175
        if ($repository instanceof DocumentRepository) {
640 175
            return $repository->find($identifier, $lockMode, $lockVersion);
641
        }
642
643
        return $repository->find($identifier);
644
    }
645
646
    /**
647
     * Clears the DocumentManager.
648
     *
649
     * All documents that are currently managed by this DocumentManager become
650
     * detached.
651
     *
652
     * @param string|null $documentName if given, only documents of this type will get detached
653
     */
654 380
    public function clear($documentName = null)
655
    {
656 380
        $this->unitOfWork->clear($documentName);
657 380
    }
658
659
    /**
660
     * Closes the DocumentManager. All documents that are currently managed
661
     * by this DocumentManager become detached. The DocumentManager may no longer
662
     * be used after it is closed.
663
     */
664 6
    public function close()
665
    {
666 6
        $this->clear();
667 6
        $this->closed = true;
668 6
    }
669
670
    /**
671
     * Determines whether a document instance is managed in this DocumentManager.
672
     *
673
     * @param object $document
674
     *
675
     * @return bool TRUE if this DocumentManager currently manages the given document, FALSE otherwise.
676
     *
677
     * @throws InvalidArgumentException When the $document param is not an object.
678
     */
679 3
    public function contains($document)
680
    {
681 3
        if (! is_object($document)) {
682
            throw new InvalidArgumentException(gettype($document));
683
        }
684
685 3
        return $this->unitOfWork->isScheduledForInsert($document) ||
686 3
            $this->unitOfWork->isInIdentityMap($document) &&
687 3
            ! $this->unitOfWork->isScheduledForDelete($document);
688
    }
689
690
    /**
691
     * Gets the Configuration used by the DocumentManager.
692
     */
693 1773
    public function getConfiguration() : Configuration
694
    {
695 1773
        return $this->config;
696
    }
697
698
    /**
699
     * Returns a reference to the supplied document.
700
     *
701
     * @return mixed The reference for the document in question, according to the desired mapping
702
     *
703
     * @throws MappingException
704
     * @throws RuntimeException
705
     */
706 239
    public function createReference(object $document, array $referenceMapping)
707
    {
708 239
        $class = $this->getClassMetadata(get_class($document));
709 239
        $id    = $this->unitOfWork->getDocumentIdentifier($document);
710
711 239
        if ($id === null) {
712 1
            throw new RuntimeException(
713 1
                sprintf('Cannot create a DBRef for class %s without an identifier. Have you forgotten to persist/merge the document first?', $class->name)
714
            );
715
        }
716
717 238
        $storeAs = $referenceMapping['storeAs'] ?? null;
718 238
        switch ($storeAs) {
719
            case ClassMetadata::REFERENCE_STORE_AS_ID:
720 46
                if ($class->inheritanceType === ClassMetadata::INHERITANCE_TYPE_SINGLE_COLLECTION) {
721 1
                    throw MappingException::simpleReferenceMustNotTargetDiscriminatedDocument($referenceMapping['targetDocument']);
722
                }
723
724 45
                return $class->getDatabaseIdentifierValue($id);
725
            case ClassMetadata::REFERENCE_STORE_AS_REF:
726 20
                $reference = ['id' => $class->getDatabaseIdentifierValue($id)];
727 20
                break;
728
729
            case ClassMetadata::REFERENCE_STORE_AS_DB_REF:
730
                $reference = [
731 193
                    '$ref' => $class->getCollection(),
732 193
                    '$id'  => $class->getDatabaseIdentifierValue($id),
733
                ];
734 193
                break;
735
736
            case ClassMetadata::REFERENCE_STORE_AS_DB_REF_WITH_DB:
737
                $reference = [
738 18
                    '$ref' => $class->getCollection(),
739 18
                    '$id'  => $class->getDatabaseIdentifierValue($id),
740 18
                    '$db'  => $this->getDocumentDatabase($class->name)->getDatabaseName(),
741
                ];
742 18
                break;
743
744
            default:
745
                throw new InvalidArgumentException(sprintf('Reference type %s is invalid.', $storeAs));
746
        }
747
748 216
        return $reference + $this->getDiscriminatorData($referenceMapping, $class);
749
    }
750
751
    /**
752
     * Build discriminator portion of reference for specified reference mapping and class metadata.
753
     *
754
     * @param array         $referenceMapping Mappings of reference for which discriminator data is created.
755
     * @param ClassMetadata $class            Metadata of reference document class.
756
     *
757
     * @return array with next structure [{discriminator field} => {discriminator value}]
758
     *
759
     * @throws MappingException When discriminator map is present and reference class in not registered in it.
760
     */
761 216
    private function getDiscriminatorData(array $referenceMapping, ClassMetadata $class) : array
762
    {
763 216
        $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...
764 216
        $discriminatorValue = null;
765 216
        $discriminatorMap   = null;
766
767 216
        if (isset($referenceMapping['discriminatorField'])) {
768 40
            $discriminatorField = $referenceMapping['discriminatorField'];
769
770 40
            if (isset($referenceMapping['discriminatorMap'])) {
771 40
                $discriminatorMap = $referenceMapping['discriminatorMap'];
772
            }
773
        } else {
774 190
            $discriminatorField = $class->discriminatorField;
775 190
            $discriminatorValue = $class->discriminatorValue;
776 190
            $discriminatorMap   = $class->discriminatorMap;
777
        }
778
779 216
        if ($discriminatorField === null) {
780 176
            return [];
781
        }
782
783 54
        if ($discriminatorValue === null) {
784 44
            if (! empty($discriminatorMap)) {
785 13
                $pos = array_search($class->name, $discriminatorMap);
786
787 13
                if ($pos !== false) {
788 13
                    $discriminatorValue = $pos;
789
                }
790
            } else {
791 32
                $discriminatorValue = $class->name;
792
            }
793
        }
794
795 54
        if ($discriminatorValue === null) {
796 6
            throw MappingException::unlistedClassInDiscriminatorMap($class->name);
797
        }
798
799 50
        return [$discriminatorField => $discriminatorValue];
800
    }
801
802
    /**
803
     * Throws an exception if the DocumentManager is closed or currently not active.
804
     *
805
     * @throws MongoDBException If the DocumentManager is closed.
806
     */
807 644
    private function errorIfClosed() : void
808
    {
809 644
        if ($this->closed) {
810 5
            throw MongoDBException::documentManagerClosed();
811
        }
812 639
    }
813
814
    /**
815
     * Check if the Document manager is open or closed.
816
     */
817 1
    public function isOpen() : bool
818
    {
819 1
        return ! $this->closed;
820
    }
821
822
    /**
823
     * Gets the filter collection.
824
     */
825 533
    public function getFilterCollection() : FilterCollection
826
    {
827 533
        if ($this->filterCollection === null) {
828 533
            $this->filterCollection = new FilterCollection($this);
829
        }
830
831 533
        return $this->filterCollection;
832
    }
833
834 1773
    private function checkTypeMap() : void
835
    {
836 1773
        $typeMap = $this->client->getTypeMap();
837
838 1773
        foreach (self::CLIENT_TYPEMAP as $part => $expectedType) {
839 1773
            if (! isset($typeMap[$part]) || $typeMap[$part] !== $expectedType) {
840 3
                throw MongoDBException::invalidTypeMap($part, $expectedType);
841
            }
842
        }
843 1773
    }
844
}
845