Completed
Pull Request — master (#1803)
by Maciej
15:26 queued 06:04
created

DocumentManager::unlock()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

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