Completed
Push — master ( a47e46...ae9680 )
by Andreas
15:39
created

DocumentManager::createReference()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 47

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 7.004

Importance

Changes 0
Metric Value
dl 0
loc 47
ccs 22
cts 23
cp 0.9565
rs 8.223
c 0
b 0
f 0
cc 7
nc 7
nop 2
crap 7.004
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
    /**
148
     * Creates a new Document that operates on the given Mongo connection
149
     * and uses the given Configuration.
150
     */
151 1642
    protected function __construct(?Client $client = null, ?Configuration $config = null, ?EventManager $eventManager = null)
152
    {
153 1642
        $this->config       = $config ?: new Configuration();
154 1642
        $this->eventManager = $eventManager ?: new EventManager();
155 1642
        $this->client       = $client ?: new Client('mongodb://127.0.0.1', [], ['typeMap' => self::CLIENT_TYPEMAP]);
156
157 1642
        $this->checkTypeMap();
158
159 1642
        $metadataFactoryClassName = $this->config->getClassMetadataFactoryName();
160 1642
        $this->metadataFactory    = new $metadataFactoryClassName();
161 1642
        $this->metadataFactory->setDocumentManager($this);
162 1642
        $this->metadataFactory->setConfiguration($this->config);
163
164 1642
        $cacheDriver = $this->config->getMetadataCacheImpl();
165 1642
        if ($cacheDriver) {
166
            $this->metadataFactory->setCacheDriver($cacheDriver);
167
        }
168
169 1642
        $hydratorDir           = $this->config->getHydratorDir();
170 1642
        $hydratorNs            = $this->config->getHydratorNamespace();
171 1642
        $this->hydratorFactory = new HydratorFactory(
172 1642
            $this,
173 1642
            $this->eventManager,
174 1642
            $hydratorDir,
175 1642
            $hydratorNs,
176 1642
            $this->config->getAutoGenerateHydratorClasses()
177
        );
178
179 1642
        $this->unitOfWork = new UnitOfWork($this, $this->eventManager, $this->hydratorFactory);
180 1642
        $this->hydratorFactory->setUnitOfWork($this->unitOfWork);
181 1642
        $this->schemaManager     = new SchemaManager($this, $this->metadataFactory);
182 1642
        $this->proxyFactory      = new StaticProxyFactory($this);
183 1642
        $this->repositoryFactory = $this->config->getRepositoryFactory();
184 1642
        $this->classNameResolver = new ClassNameResolver($this->config);
185 1642
    }
186
187
    /**
188
     * Gets the proxy factory used by the DocumentManager to create document proxies.
189
     */
190 1
    public function getProxyFactory() : ProxyFactory
191
    {
192 1
        return $this->proxyFactory;
193
    }
194
195
    /**
196
     * Creates a new Document that operates on the given Mongo connection
197
     * and uses the given Configuration.
198
     */
199 1642
    public static function create(?Client $client = null, ?Configuration $config = null, ?EventManager $eventManager = null) : DocumentManager
200
    {
201 1642
        return new static($client, $config, $eventManager);
202
    }
203
204
    /**
205
     * Gets the EventManager used by the DocumentManager.
206
     */
207 1705
    public function getEventManager() : EventManager
208
    {
209 1705
        return $this->eventManager;
210
    }
211
212
    /**
213
     * Gets the MongoDB client instance that this DocumentManager wraps.
214
     */
215 1642
    public function getClient() : Client
216
    {
217 1642
        return $this->client;
218
    }
219
220
    /**
221
     * Gets the metadata factory used to gather the metadata of classes.
222
     *
223
     * @return ClassMetadataFactory
224
     */
225 5
    public function getMetadataFactory()
226
    {
227 5
        return $this->metadataFactory;
228
    }
229
230
    /**
231
     * Helper method to initialize a lazy loading proxy or persistent collection.
232
     *
233
     * This method is a no-op for other objects.
234
     *
235
     * @param object $obj
236
     */
237
    public function initializeObject($obj)
238
    {
239
        $this->unitOfWork->initializeObject($obj);
240
    }
241
242
    /**
243
     * Gets the UnitOfWork used by the DocumentManager to coordinate operations.
244
     */
245 1649
    public function getUnitOfWork() : UnitOfWork
246
    {
247 1649
        return $this->unitOfWork;
248
    }
249
250
    /**
251
     * Gets the Hydrator factory used by the DocumentManager to generate and get hydrators
252
     * for each type of document.
253
     */
254 67
    public function getHydratorFactory() : HydratorFactory
255
    {
256 67
        return $this->hydratorFactory;
257
    }
258
259
    /**
260
     * Returns SchemaManager, used to create/drop indexes/collections/databases.
261
     */
262 28
    public function getSchemaManager() : SchemaManager
263
    {
264 28
        return $this->schemaManager;
265
    }
266
267
    /** Returns the class name resolver which is used to resolve real class names for proxy objects. */
268 1433
    public function getClassNameResolver() : ClassNameResolver
269
    {
270 1433
        return $this->classNameResolver;
271
    }
272
273
    /**
274
     * Returns the metadata for a class.
275
     *
276
     * @internal Performance-sensitive method.
277
     *
278
     * @param string $className The class name.
279
     */
280 1369
    public function getClassMetadata($className) : ClassMetadata
281
    {
282 1369
        return $this->metadataFactory->getMetadataFor($className);
283
    }
284
285
    /**
286
     * Returns the MongoDB instance for a class.
287
     */
288 1298
    public function getDocumentDatabase(string $className) : Database
289
    {
290 1298
        $className = $this->classNameResolver->getRealClass($className);
291
292 1298
        if (isset($this->documentDatabases[$className])) {
293 46
            return $this->documentDatabases[$className];
294
        }
295
296 1293
        $metadata                            = $this->metadataFactory->getMetadataFor($className);
297 1293
        $db                                  = $metadata->getDatabase();
298 1293
        $db                                  = $db ?: $this->config->getDefaultDB();
299 1293
        $db                                  = $db ?: 'doctrine';
300 1293
        $this->documentDatabases[$className] = $this->client->selectDatabase($db);
301
302 1293
        return $this->documentDatabases[$className];
303
    }
304
305
    /**
306
     * Gets the array of instantiated document database instances.
307
     *
308
     * @return Database[]
309
     */
310
    public function getDocumentDatabases() : array
311
    {
312
        return $this->documentDatabases;
313
    }
314
315
    /**
316
     * Returns the collection instance for a class.
317
     *
318
     * @throws MongoDBException When the $className param is not mapped to a collection.
319
     */
320 1301
    public function getDocumentCollection(string $className) : Collection
321
    {
322 1301
        $className = $this->classNameResolver->getRealClass($className);
323
324
        /** @var ClassMetadata $metadata */
325 1301
        $metadata = $this->metadataFactory->getMetadataFor($className);
326 1301
        if ($metadata->isFile) {
327 16
            return $this->getDocumentBucket($className)->getFilesCollection();
328
        }
329
330 1290
        $collectionName = $metadata->getCollection();
331
332 1290
        if (! $collectionName) {
333
            throw MongoDBException::documentNotMappedToCollection($className);
334
        }
335
336 1290
        if (! isset($this->documentCollections[$className])) {
337 1280
            $db = $this->getDocumentDatabase($className);
338
339 1280
            $options = [];
340 1280
            if ($metadata->readPreference !== null) {
341 3
                $options['readPreference'] = new ReadPreference($metadata->readPreference, $metadata->readPreferenceTags);
342
            }
343
344 1280
            $this->documentCollections[$className] = $db->selectCollection($collectionName, $options);
345
        }
346
347 1290
        return $this->documentCollections[$className];
348
    }
349
350
    /**
351
     * Returns the bucket instance for a class.
352
     *
353
     * @throws MongoDBException When the $className param is not mapped to a collection.
354
     */
355 16
    public function getDocumentBucket(string $className) : Bucket
356
    {
357 16
        $className = $this->classNameResolver->getRealClass($className);
358
359
        /** @var ClassMetadata $metadata */
360 16
        $metadata = $this->metadataFactory->getMetadataFor($className);
361 16
        if (! $metadata->isFile) {
362
            throw MongoDBException::documentBucketOnlyAvailableForGridFSFiles($className);
363
        }
364
365 16
        $bucketName = $metadata->getBucketName();
366
367 16
        if (! $bucketName) {
368
            throw MongoDBException::documentNotMappedToCollection($className);
369
        }
370
371 16
        if (! isset($this->documentBuckets[$className])) {
372 11
            $db = $this->getDocumentDatabase($className);
373
374 11
            $options = ['bucketName' => $bucketName];
375 11
            if ($metadata->readPreference !== null) {
376
                $options['readPreference'] = new ReadPreference($metadata->readPreference, $metadata->readPreferenceTags);
377
            }
378
379 11
            $this->documentBuckets[$className] = $db->selectGridFSBucket($options);
380
        }
381
382 16
        return $this->documentBuckets[$className];
383
    }
384
385
    /**
386
     * Gets the array of instantiated document collection instances.
387
     *
388
     * @return Collection[]
389
     */
390
    public function getDocumentCollections() : array
391
    {
392
        return $this->documentCollections;
393
    }
394
395
    /**
396
     * Create a new Query instance for a class.
397
     *
398
     * @param string[]|string|null $documentName (optional) an array of document names, the document name, or none
399
     */
400 179
    public function createQueryBuilder($documentName = null) : Query\Builder
401
    {
402 179
        return new Query\Builder($this, $documentName);
403
    }
404
405
    /**
406
     * Creates a new aggregation builder instance for a class.
407
     */
408 41
    public function createAggregationBuilder(string $documentName) : Aggregation\Builder
409
    {
410 41
        return new Aggregation\Builder($this, $documentName);
411
    }
412
413
    /**
414
     * Tells the DocumentManager to make an instance managed and persistent.
415
     *
416
     * The document will be entered into the database at or before transaction
417
     * commit or as a result of the flush operation.
418
     *
419
     * NOTE: The persist operation always considers documents that are not yet known to
420
     * this DocumentManager as NEW. Do not pass detached documents to the persist operation.
421
     *
422
     * @param object $document The instance to make managed and persistent.
423
     *
424
     * @throws InvalidArgumentException When the given $document param is not an object.
425
     */
426 616
    public function persist($document)
427
    {
428 616
        if (! is_object($document)) {
429 1
            throw new InvalidArgumentException(gettype($document));
430
        }
431 615
        $this->errorIfClosed();
432 614
        $this->unitOfWork->persist($document);
433 610
    }
434
435
    /**
436
     * Removes a document instance.
437
     *
438
     * A removed document will be removed from the database at or before transaction commit
439
     * or as a result of the flush operation.
440
     *
441
     * @param object $document The document instance to remove.
442
     *
443
     * @throws InvalidArgumentException When the $document param is not an object.
444
     */
445 27
    public function remove($document)
446
    {
447 27
        if (! is_object($document)) {
448 1
            throw new InvalidArgumentException(gettype($document));
449
        }
450 26
        $this->errorIfClosed();
451 25
        $this->unitOfWork->remove($document);
452 25
    }
453
454
    /**
455
     * Refreshes the persistent state of a document from the database,
456
     * overriding any local changes that have not yet been persisted.
457
     *
458
     * @param object $document The document to refresh.
459
     *
460
     * @throws InvalidArgumentException When the given $document param is not an object.
461
     */
462 26
    public function refresh($document)
463
    {
464 26
        if (! is_object($document)) {
465 1
            throw new InvalidArgumentException(gettype($document));
466
        }
467 25
        $this->errorIfClosed();
468 24
        $this->unitOfWork->refresh($document);
469 23
    }
470
471
    /**
472
     * Detaches a document from the DocumentManager, causing a managed document to
473
     * become detached.  Unflushed changes made to the document if any
474
     * (including removal of the document), will not be synchronized to the database.
475
     * Documents which previously referenced the detached document will continue to
476
     * reference it.
477
     *
478
     * @param object $document The document to detach.
479
     *
480
     * @throws InvalidArgumentException When the $document param is not an object.
481
     */
482 11
    public function detach($document)
483
    {
484 11
        if (! is_object($document)) {
485 1
            throw new InvalidArgumentException(gettype($document));
486
        }
487 10
        $this->unitOfWork->detach($document);
488 10
    }
489
490
    /**
491
     * Merges the state of a detached document into the persistence context
492
     * of this DocumentManager and returns the managed copy of the document.
493
     * The document passed to merge will not become associated/managed with this DocumentManager.
494
     *
495
     * @param object $document The detached document to merge into the persistence context.
496
     *
497
     * @return object The managed copy of the document.
498
     *
499
     * @throws LockException
500
     * @throws InvalidArgumentException If the $document param is not an object.
501
     */
502 13
    public function merge($document)
503
    {
504 13
        if (! is_object($document)) {
505 1
            throw new InvalidArgumentException(gettype($document));
506
        }
507 12
        $this->errorIfClosed();
508 11
        return $this->unitOfWork->merge($document);
509
    }
510
511
    /**
512
     * Acquire a lock on the given document.
513
     *
514
     * @throws InvalidArgumentException
515
     * @throws LockException
516
     */
517 8
    public function lock(object $document, int $lockMode, ?int $lockVersion = null) : void
518
    {
519 8
        $this->unitOfWork->lock($document, $lockMode, $lockVersion);
520 5
    }
521
522
    /**
523
     * Releases a lock on the given document.
524
     */
525 1
    public function unlock(object $document) : void
526
    {
527 1
        $this->unitOfWork->unlock($document);
528 1
    }
529
530
    /**
531
     * Gets the repository for a document class.
532
     *
533
     * @param string $documentName The name of the Document.
534
     *
535
     * @return ObjectRepository  The repository.
536
     */
537 345
    public function getRepository($documentName)
538
    {
539 345
        return $this->repositoryFactory->getRepository($this, $documentName);
540
    }
541
542
    /**
543
     * Flushes all changes to objects that have been queued up to now to the database.
544
     * This effectively synchronizes the in-memory state of managed objects with the
545
     * database.
546
     *
547
     * @param array $options Array of options to be used with batchInsert(), update() and remove()
548
     *
549
     * @throws MongoDBException
550
     */
551 588
    public function flush(array $options = [])
552
    {
553 588
        $this->errorIfClosed();
554 587
        $this->unitOfWork->commit($options);
555 572
    }
556
557
    /**
558
     * Gets a reference to the document identified by the given type and identifier
559
     * without actually loading it.
560
     *
561
     * If partial objects are allowed, this method will return a partial object that only
562
     * has its identifier populated. Otherwise a proxy is returned that automatically
563
     * loads itself on first access.
564
     *
565
     * @param string|object $identifier
566
     */
567 127
    public function getReference(string $documentName, $identifier) : object
568
    {
569
        /** @var ClassMetadata $class */
570 127
        $class    = $this->metadataFactory->getMetadataFor(ltrim($documentName, '\\'));
571 127
        $document = $this->unitOfWork->tryGetById($identifier, $class);
572
573
        // Check identity map first, if its already in there just return it.
574 127
        if ($document) {
575 56
            return $document;
576
        }
577
578 98
        $document = $this->proxyFactory->getProxy($class, $identifier);
579 98
        $this->unitOfWork->registerManaged($document, $identifier, []);
580
581 98
        return $document;
582
    }
583
584
    /**
585
     * Gets a partial reference to the document identified by the given type and identifier
586
     * without actually loading it, if the document is not yet loaded.
587
     *
588
     * The returned reference may be a partial object if the document is not yet loaded/managed.
589
     * If it is a partial object it will not initialize the rest of the document state on access.
590
     * Thus you can only ever safely access the identifier of a document obtained through
591
     * this method.
592
     *
593
     * The use-cases for partial references involve maintaining bidirectional associations
594
     * without loading one side of the association or to update a document without loading it.
595
     * Note, however, that in the latter case the original (persistent) document data will
596
     * never be visible to the application (especially not event listeners) as it will
597
     * never be loaded in the first place.
598
     *
599
     * @param mixed $identifier The document identifier.
600
     */
601 1
    public function getPartialReference(string $documentName, $identifier) : object
602
    {
603 1
        $class    = $this->metadataFactory->getMetadataFor(ltrim($documentName, '\\'));
604 1
        $document = $this->unitOfWork->tryGetById($identifier, $class);
605
606
        // Check identity map first, if its already in there just return it.
607 1
        if ($document) {
608
            return $document;
609
        }
610 1
        $document = $class->newInstance();
611 1
        $class->setIdentifierValue($document, $identifier);
612 1
        $this->unitOfWork->registerManaged($document, $identifier, []);
613
614 1
        return $document;
615
    }
616
617
    /**
618
     * Finds a Document by its identifier.
619
     *
620
     * This is just a convenient shortcut for getRepository($documentName)->find($id).
621
     *
622
     * @param string $documentName
623
     * @param mixed  $identifier
624
     * @param int    $lockMode
625
     * @param int    $lockVersion
626
     *
627
     * @return object $document
628
     */
629 174
    public function find($documentName, $identifier, $lockMode = LockMode::NONE, $lockVersion = null)
630
    {
631 174
        return $this->getRepository($documentName)->find($identifier, $lockMode, $lockVersion);
632
    }
633
634
    /**
635
     * Clears the DocumentManager.
636
     *
637
     * All documents that are currently managed by this DocumentManager become
638
     * detached.
639
     *
640
     * @param string|null $documentName if given, only documents of this type will get detached
641
     */
642 377
    public function clear($documentName = null)
643
    {
644 377
        $this->unitOfWork->clear($documentName);
645 377
    }
646
647
    /**
648
     * Closes the DocumentManager. All documents that are currently managed
649
     * by this DocumentManager become detached. The DocumentManager may no longer
650
     * be used after it is closed.
651
     */
652 6
    public function close()
653
    {
654 6
        $this->clear();
655 6
        $this->closed = true;
656 6
    }
657
658
    /**
659
     * Determines whether a document instance is managed in this DocumentManager.
660
     *
661
     * @param object $document
662
     *
663
     * @return bool TRUE if this DocumentManager currently manages the given document, FALSE otherwise.
664
     *
665
     * @throws InvalidArgumentException When the $document param is not an object.
666
     */
667 3
    public function contains($document)
668
    {
669 3
        if (! is_object($document)) {
670
            throw new InvalidArgumentException(gettype($document));
671
        }
672 3
        return $this->unitOfWork->isScheduledForInsert($document) ||
673 3
            $this->unitOfWork->isInIdentityMap($document) &&
674 3
            ! $this->unitOfWork->isScheduledForDelete($document);
675
    }
676
677
    /**
678
     * Gets the Configuration used by the DocumentManager.
679
     */
680 1705
    public function getConfiguration() : Configuration
681
    {
682 1705
        return $this->config;
683
    }
684
685
    /**
686
     * Returns a reference to the supplied document.
687
     *
688
     * @return mixed The reference for the document in question, according to the desired mapping
689
     *
690
     * @throws MappingException
691
     * @throws RuntimeException
692
     */
693 225
    public function createReference(object $document, array $referenceMapping)
694
    {
695 225
        $class = $this->getClassMetadata(get_class($document));
696 225
        $id    = $this->unitOfWork->getDocumentIdentifier($document);
697
698 225
        if ($id === null) {
699 1
            throw new RuntimeException(
700 1
                sprintf('Cannot create a DBRef for class %s without an identifier. Have you forgotten to persist/merge the document first?', $class->name)
701
            );
702
        }
703
704 224
        $storeAs   = $referenceMapping['storeAs'] ?? null;
705 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...
706 224
        switch ($storeAs) {
707
            case ClassMetadata::REFERENCE_STORE_AS_ID:
708 46
                if ($class->inheritanceType === ClassMetadata::INHERITANCE_TYPE_SINGLE_COLLECTION) {
709 1
                    throw MappingException::simpleReferenceMustNotTargetDiscriminatedDocument($referenceMapping['targetDocument']);
710
                }
711
712 45
                return $class->getDatabaseIdentifierValue($id);
713
                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...
714
715
            case ClassMetadata::REFERENCE_STORE_AS_REF:
716 20
                $reference = ['id' => $class->getDatabaseIdentifierValue($id)];
717 20
                break;
718
719
            case ClassMetadata::REFERENCE_STORE_AS_DB_REF:
720
                $reference = [
721 180
                    '$ref' => $class->getCollection(),
722 180
                    '$id'  => $class->getDatabaseIdentifierValue($id),
723
                ];
724 180
                break;
725
726
            case ClassMetadata::REFERENCE_STORE_AS_DB_REF_WITH_DB:
727
                $reference = [
728 17
                    '$ref' => $class->getCollection(),
729 17
                    '$id'  => $class->getDatabaseIdentifierValue($id),
730 17
                    '$db'  => $this->getDocumentDatabase($class->name)->getDatabaseName(),
731
                ];
732 17
                break;
733
734
            default:
735
                throw new InvalidArgumentException(sprintf('Reference type %s is invalid.', $storeAs));
736
        }
737
738 202
        return $reference + $this->getDiscriminatorData($referenceMapping, $class);
739
    }
740
741
    /**
742
     * Build discriminator portion of reference for specified reference mapping and class metadata.
743
     *
744
     * @param array         $referenceMapping Mappings of reference for which discriminator data is created.
745
     * @param ClassMetadata $class            Metadata of reference document class.
746
     *
747
     * @return array with next structure [{discriminator field} => {discriminator value}]
748
     *
749
     * @throws MappingException When discriminator map is present and reference class in not registered in it.
750
     */
751 202
    private function getDiscriminatorData(array $referenceMapping, ClassMetadata $class) : array
752
    {
753 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...
754 202
        $discriminatorValue = null;
755 202
        $discriminatorData  = [];
756 202
        if (isset($referenceMapping['discriminatorField'])) {
757 33
            $discriminatorField = $referenceMapping['discriminatorField'];
758 33
            if (isset($referenceMapping['discriminatorMap'])) {
759 8
                $pos = array_search($class->name, $referenceMapping['discriminatorMap']);
760 8
                if ($pos !== false) {
761 8
                    $discriminatorValue = $pos;
762
                }
763
            } else {
764 33
                $discriminatorValue = $class->name;
765
            }
766
        } else {
767 183
            $discriminatorField = $class->discriminatorField;
768 183
            $discriminatorValue = $class->discriminatorValue;
769
        }
770
771 202
        if ($discriminatorField !== null) {
772 44
            if ($discriminatorValue === null) {
773 4
                throw MappingException::unlistedClassInDiscriminatorMap($class->name);
774
            }
775 42
            $discriminatorData = [$discriminatorField => $discriminatorValue];
776 172
        } elseif (! isset($referenceMapping['targetDocument'])) {
777
            $discriminatorField = $referenceMapping['discriminatorField'];
778
779
            $discriminatorMap = null;
780
            if (isset($referenceMapping['discriminatorMap'])) {
781
                $discriminatorMap = $referenceMapping['discriminatorMap'];
782
            }
783
            if ($discriminatorMap === null) {
784
                $discriminatorValue = $class->name;
785
            } else {
786
                $discriminatorValue = array_search($class->name, $discriminatorMap);
787
788
                if ($discriminatorValue === false) {
789
                    throw MappingException::unlistedClassInDiscriminatorMap($class->name);
790
                }
791
            }
792
            $discriminatorData = [$discriminatorField => $discriminatorValue];
793
        }
794
795 200
        return $discriminatorData;
796
    }
797
798
    /**
799
     * Throws an exception if the DocumentManager is closed or currently not active.
800
     *
801
     * @throws MongoDBException If the DocumentManager is closed.
802
     */
803 621
    private function errorIfClosed() : void
804
    {
805 621
        if ($this->closed) {
806 5
            throw MongoDBException::documentManagerClosed();
807
        }
808 616
    }
809
810
    /**
811
     * Check if the Document manager is open or closed.
812
     */
813 1
    public function isOpen() : bool
814
    {
815 1
        return ! $this->closed;
816
    }
817
818
    /**
819
     * Gets the filter collection.
820
     */
821 523
    public function getFilterCollection() : FilterCollection
822
    {
823 523
        if ($this->filterCollection === null) {
824 523
            $this->filterCollection = new FilterCollection($this);
825
        }
826
827 523
        return $this->filterCollection;
828
    }
829
830 1642
    private function checkTypeMap() : void
831
    {
832 1642
        $typeMap = $this->client->getTypeMap();
833
834 1642
        foreach (self::CLIENT_TYPEMAP as $part => $expectedType) {
835 1642
            if (! isset($typeMap[$part]) || $typeMap[$part] !== $expectedType) {
836 1642
                throw MongoDBException::invalidTypeMap($part, $expectedType);
837
            }
838
        }
839 1642
    }
840
}
841