Completed
Pull Request — master (#1519)
by Maciej
18:24
created

DocumentManager::createDBRef()   C

Complexity

Conditions 12
Paths 34

Size

Total Lines 65
Code Lines 30

Duplication

Lines 23
Ratio 35.38 %

Code Coverage

Tests 34
CRAP Score 12.0033

Importance

Changes 0
Metric Value
dl 23
loc 65
ccs 34
cts 35
cp 0.9714
rs 5.9833
c 0
b 0
f 0
cc 12
eloc 30
nc 34
nop 2
crap 12.0033

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ODM\MongoDB;
21
22
use Doctrine\Common\EventManager;
23
use Doctrine\Common\Persistence\ObjectManager;
24
use Doctrine\MongoDB\Connection;
25
use Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo;
26
use Doctrine\ODM\MongoDB\Mapping\MappingException;
27
use Doctrine\ODM\MongoDB\Hydrator\HydratorFactory;
28
use Doctrine\ODM\MongoDB\Proxy\ProxyFactory;
29
use Doctrine\ODM\MongoDB\Query\FilterCollection;
30
use Doctrine\ODM\MongoDB\Repository\RepositoryFactory;
31
32
/**
33
 * The DocumentManager class is the central access point for managing the
34
 * persistence of documents.
35
 *
36
 *     <?php
37
 *
38
 *     $config = new Configuration();
39
 *     $dm = DocumentManager::create(new Connection(), $config);
40
 *
41
 * @since       1.0
42
 */
43
class DocumentManager implements ObjectManager
44
{
45
    /**
46
     * The Doctrine MongoDB connection instance.
47
     *
48
     * @var \Doctrine\MongoDB\Connection
49
     */
50
    private $connection;
51
52
    /**
53
     * The used Configuration.
54
     *
55
     * @var \Doctrine\ODM\MongoDB\Configuration
56
     */
57
    private $config;
58
59
    /**
60
     * The metadata factory, used to retrieve the ODM metadata of document classes.
61
     *
62
     * @var \Doctrine\ODM\MongoDB\Mapping\ClassMetadataFactory
63
     */
64
    private $metadataFactory;
65
66
    /**
67
     * The UnitOfWork used to coordinate object-level transactions.
68
     *
69
     * @var UnitOfWork
70
     */
71
    private $unitOfWork;
72
73
    /**
74
     * The event manager that is the central point of the event system.
75
     *
76
     * @var \Doctrine\Common\EventManager
77
     */
78
    private $eventManager;
79
80
    /**
81
     * The Hydrator factory instance.
82
     *
83
     * @var HydratorFactory
84
     */
85
    private $hydratorFactory;
86
87
    /**
88
     * The Proxy factory instance.
89
     *
90
     * @var ProxyFactory
91
     */
92
    private $proxyFactory;
93
94
    /**
95
     * The repository factory used to create dynamic repositories.
96
     *
97
     * @var RepositoryFactory
98
     */
99
    private $repositoryFactory;
100
101
    /**
102
     * SchemaManager instance
103
     *
104
     * @var SchemaManager
105
     */
106
    private $schemaManager;
107
108
    /**
109
     * Array of cached document database instances that are lazily loaded.
110
     *
111
     * @var array
112
     */
113
    private $documentDatabases = array();
114
115
    /**
116
     * Array of cached document collection instances that are lazily loaded.
117
     *
118
     * @var array
119
     */
120
    private $documentCollections = array();
121
122
    /**
123
     * Whether the DocumentManager is closed or not.
124
     *
125
     * @var bool
126
     */
127
    private $closed = false;
128
129
    /**
130
     * Collection of query filters.
131
     *
132
     * @var \Doctrine\ODM\MongoDB\Query\FilterCollection
133
     */
134
    private $filterCollection;
135
136
    /**
137
     * Creates a new Document that operates on the given Mongo connection
138
     * and uses the given Configuration.
139
     *
140
     * @param \Doctrine\MongoDB\Connection|null $conn
141
     * @param Configuration|null $config
142
     * @param \Doctrine\Common\EventManager|null $eventManager
143
     */
144 1074
    protected function __construct(Connection $conn = null, Configuration $config = null, EventManager $eventManager = null)
145
    {
146 1074
        $this->config = $config ?: new Configuration();
147 1074
        $this->eventManager = $eventManager ?: new EventManager();
148 1074
        $this->connection = $conn ?: new Connection(null, array(), $this->config, $this->eventManager);
149
150 1074
        $metadataFactoryClassName = $this->config->getClassMetadataFactoryName();
151 1074
        $this->metadataFactory = new $metadataFactoryClassName();
152 1074
        $this->metadataFactory->setDocumentManager($this);
153 1074
        $this->metadataFactory->setConfiguration($this->config);
154 1074
        if ($cacheDriver = $this->config->getMetadataCacheImpl()) {
155
            $this->metadataFactory->setCacheDriver($cacheDriver);
156
        }
157
158 1074
        $hydratorDir = $this->config->getHydratorDir();
159 1074
        $hydratorNs = $this->config->getHydratorNamespace();
160 1074
        $this->hydratorFactory = new HydratorFactory(
161 1074
            $this,
162 1074
            $this->eventManager,
163 1074
            $hydratorDir,
164 1074
            $hydratorNs,
165 1074
            $this->config->getAutoGenerateHydratorClasses()
0 ignored issues
show
Bug introduced by
It seems like $this->config->getAutoGenerateHydratorClasses() targeting Doctrine\ODM\MongoDB\Con...nerateHydratorClasses() can also be of type boolean; however, Doctrine\ODM\MongoDB\Hyd...rFactory::__construct() does only seem to accept integer, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
166 1074
        );
167
168 1074
        $this->unitOfWork = new UnitOfWork($this, $this->eventManager, $this->hydratorFactory);
169 1074
        $this->hydratorFactory->setUnitOfWork($this->unitOfWork);
170 1074
        $this->schemaManager = new SchemaManager($this, $this->metadataFactory);
171 1074
        $this->proxyFactory = new ProxyFactory($this,
172 1074
            $this->config->getProxyDir(),
173 1074
            $this->config->getProxyNamespace(),
174 1074
            $this->config->getAutoGenerateProxyClasses()
0 ignored issues
show
Bug introduced by
It seems like $this->config->getAutoGenerateProxyClasses() targeting Doctrine\ODM\MongoDB\Con...oGenerateProxyClasses() can also be of type boolean; however, Doctrine\ODM\MongoDB\Pro...yFactory::__construct() does only seem to accept integer, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
175 1074
        );
176 1074
        $this->repositoryFactory = $this->config->getRepositoryFactory();
177 1074
    }
178
179
    /**
180
     * Gets the proxy factory used by the DocumentManager to create document proxies.
181
     *
182
     * @return ProxyFactory
183
     */
184 1
    public function getProxyFactory()
185
    {
186 1
        return $this->proxyFactory;
187
    }
188
189
    /**
190
     * Creates a new Document that operates on the given Mongo connection
191
     * and uses the given Configuration.
192
     *
193
     * @static
194
     * @param \Doctrine\MongoDB\Connection|null $conn
195
     * @param Configuration|null $config
196
     * @param \Doctrine\Common\EventManager|null $eventManager
197
     * @return DocumentManager
198
     */
199 1074
    public static function create(Connection $conn = null, Configuration $config = null, EventManager $eventManager = null)
200
    {
201 1074
        return new static($conn, $config, $eventManager);
202
    }
203
204
    /**
205
     * Gets the EventManager used by the DocumentManager.
206
     *
207
     * @return \Doctrine\Common\EventManager
208
     */
209 1124
    public function getEventManager()
210
    {
211 1124
        return $this->eventManager;
212
    }
213
214
    /**
215
     * Gets the PHP Mongo instance that this DocumentManager wraps.
216
     *
217
     * @return \Doctrine\MongoDB\Connection
218
     */
219 1080
    public function getConnection()
220
    {
221 1080
        return $this->connection;
222
    }
223
224
    /**
225
     * Gets the metadata factory used to gather the metadata of classes.
226
     *
227
     * @return \Doctrine\ODM\MongoDB\Mapping\ClassMetadataFactory
228
     */
229 1074
    public function getMetadataFactory()
230
    {
231 1074
        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
     * @return UnitOfWork
250
     */
251 1080
    public function getUnitOfWork()
252
    {
253 1080
        return $this->unitOfWork;
254
    }
255
256
    /**
257
     * Gets the Hydrator factory used by the DocumentManager to generate and get hydrators
258
     * for each type of document.
259
     *
260
     * @return \Doctrine\ODM\MongoDB\Hydrator\HydratorInterface
261
     */
262 71
    public function getHydratorFactory()
263
    {
264 71
        return $this->hydratorFactory;
265
    }
266
267
    /**
268
     * Returns SchemaManager, used to create/drop indexes/collections/databases.
269
     *
270
     * @return \Doctrine\ODM\MongoDB\SchemaManager
271
     */
272 55
    public function getSchemaManager()
273
    {
274 55
        return $this->schemaManager;
275 1
    }
276
277
    /**
278
     * Returns the metadata for a class.
279
     *
280
     * @param string $className The class name.
281
     * @return \Doctrine\ODM\MongoDB\Mapping\ClassMetadata
282
     * @internal Performance-sensitive method.
283
     */
284 841
    public function getClassMetadata($className)
285
    {
286 841
        return $this->metadataFactory->getMetadataFor(ltrim($className, '\\'));
287
    }
288
289
    /**
290
     * Returns the MongoDB instance for a class.
291
     *
292
     * @param string $className The class name.
293
     * @return \Doctrine\MongoDB\Database
294
     */
295 776
    public function getDocumentDatabase($className)
296
    {
297 776
        $className = ltrim($className, '\\');
298
299 776
        if (isset($this->documentDatabases[$className])) {
300 216
            return $this->documentDatabases[$className];
301
        }
302
303 765
        $metadata = $this->metadataFactory->getMetadataFor($className);
304 765
        $db = $metadata->getDatabase();
305 765
        $db = $db ?: $this->config->getDefaultDB();
306 765
        $db = $db ?: 'doctrine';
307 765
        $this->documentDatabases[$className] = $this->connection->selectDatabase($db);
308
309 765
        return $this->documentDatabases[$className];
310
    }
311
312
    /**
313
     * Gets the array of instantiated document database instances.
314
     *
315
     * @return array
316
     */
317
    public function getDocumentDatabases()
318
    {
319
        return $this->documentDatabases;
320
    }
321
322
    /**
323
     * Returns the MongoCollection instance for a class.
324
     *
325
     * @param string $className The class name.
326
     * @throws MongoDBException When the $className param is not mapped to a collection
327
     * @return \Doctrine\MongoDB\Collection
328
     */
329 772
    public function getDocumentCollection($className)
330
    {
331 772
        $className = ltrim($className, '\\');
332
333 772
        $metadata = $this->metadataFactory->getMetadataFor($className);
334 772
        $collectionName = $metadata->getCollection();
335
336 772
        if ( ! $collectionName) {
337
            throw MongoDBException::documentNotMappedToCollection($className);
338
        }
339
340 772
        if ( ! isset($this->documentCollections[$className])) {
341 761
            $db = $this->getDocumentDatabase($className);
342
343 761
            $this->documentCollections[$className] = $metadata->isFile()
344 761
                ? $db->getGridFS($collectionName)
345 761
                : $db->selectCollection($collectionName);
346 761
        }
347
348 772
        $collection = $this->documentCollections[$className];
349
350 772
        if ($metadata->slaveOkay !== null) {
0 ignored issues
show
Bug introduced by
Accessing slaveOkay on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
351 2
            $collection->setSlaveOkay($metadata->slaveOkay);
0 ignored issues
show
Bug introduced by
Accessing slaveOkay on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
352 2
        }
353
354 772
        return $this->documentCollections[$className];
355
    }
356
357
    /**
358
     * Gets the array of instantiated document collection instances.
359
     *
360
     * @return array
361
     */
362 1
    public function getDocumentCollections()
363 1
    {
364
        return $this->documentCollections;
365
    }
366
367
    /**
368
     * Create a new Query instance for a class.
369
     *
370
     * @param string $documentName The document class name.
371
     * @return Query\Builder
372
     */
373 223
    public function createQueryBuilder($documentName = null)
374
    {
375 223
        return new Query\Builder($this, $documentName);
376
    }
377
378
    /**
379
     * Creates a new aggregation builder instance for a class.
380
     *
381
     * @param string $documentName The document class name.
382
     * @return Aggregation\Builder
383
     */
384 11
    public function createAggregationBuilder($documentName)
385
    {
386 11
        return new Aggregation\Builder($this, $documentName);
387
    }
388
389
    /**
390
     * Tells the DocumentManager to make an instance managed and persistent.
391
     *
392
     * The document will be entered into the database at or before transaction
393
     * commit or as a result of the flush operation.
394
     *
395
     * NOTE: The persist operation always considers documents that are not yet known to
396
     * this DocumentManager as NEW. Do not pass detached documents to the persist operation.
397
     *
398
     * @param object $document The instance to make managed and persistent.
399
     * @throws \InvalidArgumentException When the given $document param is not an object
400
     */
401 623 View Code Duplication
    public function persist($document)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
402
    {
403 623
        if ( ! is_object($document)) {
404 1
            throw new \InvalidArgumentException(gettype($document));
405
        }
406 622
        $this->errorIfClosed();
407 621
        $this->unitOfWork->persist($document);
408 617
    }
409
410
    /**
411
     * Removes a document instance.
412
     *
413
     * A removed document will be removed from the database at or before transaction commit
414
     * or as a result of the flush operation.
415
     *
416
     * @param object $document The document instance to remove.
417
     * @throws \InvalidArgumentException when the $document param is not an object
418
     */
419 25 View Code Duplication
    public function remove($document)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
420
    {
421 25
        if ( ! is_object($document)) {
422 1
            throw new \InvalidArgumentException(gettype($document));
423
        }
424 24
        $this->errorIfClosed();
425 23
        $this->unitOfWork->remove($document);
426 23
    }
427
428
    /**
429
     * Refreshes the persistent state of a document from the database,
430
     * overriding any local changes that have not yet been persisted.
431
     *
432
     * @param object $document The document to refresh.
433
     * @throws \InvalidArgumentException When the given $document param is not an object
434
     */
435 24 View Code Duplication
    public function refresh($document)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
436
    {
437 24
        if ( ! is_object($document)) {
438 1
            throw new \InvalidArgumentException(gettype($document));
439
        }
440 23
        $this->errorIfClosed();
441 22
        $this->unitOfWork->refresh($document);
442 21
    }
443
444
    /**
445
     * Detaches a document from the DocumentManager, causing a managed document to
446
     * become detached.  Unflushed changes made to the document if any
447
     * (including removal of the document), will not be synchronized to the database.
448
     * Documents which previously referenced the detached document will continue to
449
     * reference it.
450
     *
451
     * @param object $document The document to detach.
452
     * @throws \InvalidArgumentException when the $document param is not an object
453
     */
454 12
    public function detach($document)
455
    {
456 12
        if ( ! is_object($document)) {
457 1
            throw new \InvalidArgumentException(gettype($document));
458
        }
459 11
        $this->unitOfWork->detach($document);
460 11
    }
461
462
    /**
463
     * Merges the state of a detached document into the persistence context
464
     * of this DocumentManager and returns the managed copy of the document.
465
     * The document passed to merge will not become associated/managed with this DocumentManager.
466
     *
467
     * @param object $document The detached document to merge into the persistence context.
468
     * @throws LockException
469
     * @throws \InvalidArgumentException if the $document param is not an object
470
     * @return object The managed copy of the document.
471
     */
472 17 View Code Duplication
    public function merge($document)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
473
    {
474 17
        if ( ! is_object($document)) {
475 1
            throw new \InvalidArgumentException(gettype($document));
476
        }
477 16
        $this->errorIfClosed();
478 15
        return $this->unitOfWork->merge($document);
479
    }
480
481
    /**
482
     * Acquire a lock on the given document.
483
     *
484
     * @param object $document
485
     * @param int $lockMode
486
     * @param int $lockVersion
487
     * @throws \InvalidArgumentException
488
     */
489 9
    public function lock($document, $lockMode, $lockVersion = null)
490
    {
491 9
        if ( ! is_object($document)) {
492
            throw new \InvalidArgumentException(gettype($document));
493
        }
494 9
        $this->unitOfWork->lock($document, $lockMode, $lockVersion);
495 6
    }
496
497
    /**
498
     * Releases a lock on the given document.
499
     *
500
     * @param object $document
501
     * @throws \InvalidArgumentException if the $document param is not an object
502
     */
503 1
    public function unlock($document)
504
    {
505 1
        if ( ! is_object($document)) {
506
            throw new \InvalidArgumentException(gettype($document));
507
        }
508 1
        $this->unitOfWork->unlock($document);
509 1
    }
510
511
    /**
512
     * Gets the repository for a document class.
513
     *
514
     * @param string $documentName  The name of the Document.
515
     * @return DocumentRepository  The repository.
516
     */
517 356
    public function getRepository($documentName)
518
    {
519 356
        return $this->repositoryFactory->getRepository($this, $documentName);
520
    }
521
522
    /**
523
     * Flushes all changes to objects that have been queued up to now to the database.
524
     * This effectively synchronizes the in-memory state of managed objects with the
525
     * database.
526
     *
527
     * @param object $document
528
     * @param array $options Array of options to be used with batchInsert(), update() and remove()
529
     * @throws \InvalidArgumentException
530
     */
531 599
    public function flush($document = null, array $options = array())
532
    {
533 599
        if (null !== $document && ! is_object($document) && ! is_array($document)) {
534
            throw new \InvalidArgumentException(gettype($document));
535
        }
536 599
        $this->errorIfClosed();
537 598
        $this->unitOfWork->commit($document, $options);
0 ignored issues
show
Bug introduced by
It seems like $document can also be of type array; however, Doctrine\ODM\MongoDB\UnitOfWork::commit() does only seem to accept object|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
538 595
    }
539
540
    /**
541
     * Gets a reference to the document identified by the given type and identifier
542
     * without actually loading it.
543
     *
544
     * If partial objects are allowed, this method will return a partial object that only
545
     * has its identifier populated. Otherwise a proxy is returned that automatically
546
     * loads itself on first access.
547
     *
548
     * @param string $documentName
549
     * @param string|object $identifier
550
     * @return mixed|object The document reference.
551
     */
552 120
    public function getReference($documentName, $identifier)
553
    {
554
        /* @var $class \Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo */
555 120
        $class = $this->metadataFactory->getMetadataFor(ltrim($documentName, '\\'));
556
557
        // Check identity map first, if its already in there just return it.
558 120
        if ($document = $this->unitOfWork->tryGetById($identifier, $class)) {
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\ODM\Mong...ping\ClassMetadataInfo> is not a sub-type of object<Doctrine\ODM\Mong...\Mapping\ClassMetadata>. It seems like you assume a child class of the class Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
559 45
            return $document;
560
        }
561
562 94
        $document = $this->proxyFactory->getProxy($class->name, array($class->identifier => $identifier));
563 94
        $this->unitOfWork->registerManaged($document, $identifier, array());
0 ignored issues
show
Documentation introduced by
$identifier is of type string|object, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
564
565 94
        return $document;
566
    }
567
568
    /**
569
     * Gets a partial reference to the document identified by the given type and identifier
570
     * without actually loading it, if the document is not yet loaded.
571
     *
572
     * The returned reference may be a partial object if the document is not yet loaded/managed.
573
     * If it is a partial object it will not initialize the rest of the document state on access.
574
     * Thus you can only ever safely access the identifier of a document obtained through
575
     * this method.
576
     *
577
     * The use-cases for partial references involve maintaining bidirectional associations
578
     * without loading one side of the association or to update a document without loading it.
579
     * Note, however, that in the latter case the original (persistent) document data will
580
     * never be visible to the application (especially not event listeners) as it will
581
     * never be loaded in the first place.
582
     *
583
     * @param string $documentName The name of the document type.
584
     * @param mixed $identifier The document identifier.
585
     * @return object The (partial) document reference.
586
     */
587 1
    public function getPartialReference($documentName, $identifier)
588
    {
589 1
        $class = $this->metadataFactory->getMetadataFor(ltrim($documentName, '\\'));
590
591
        // Check identity map first, if its already in there just return it.
592 1
        if ($document = $this->unitOfWork->tryGetById($identifier, $class)) {
0 ignored issues
show
Compatibility introduced by
$class of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ODM\Mong...\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
593
            return $document;
594
        }
595 1
        $document = $class->newInstance();
596 1
        $class->setIdentifierValue($document, $identifier);
0 ignored issues
show
Bug introduced by
The method setIdentifierValue() does not exist on Doctrine\Common\Persistence\Mapping\ClassMetadata. Did you maybe mean getIdentifierValues()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
597 1
        $this->unitOfWork->registerManaged($document, $identifier, array());
598
599 1
        return $document;
600
    }
601
602
    /**
603
     * Finds a Document by its identifier.
604
     *
605
     * This is just a convenient shortcut for getRepository($documentName)->find($id).
606
     *
607
     * @param string $documentName
608
     * @param mixed $identifier
609
     * @param int $lockMode
610
     * @param int $lockVersion
611
     * @return object $document
612
     */
613 186
    public function find($documentName, $identifier, $lockMode = LockMode::NONE, $lockVersion = null)
614
    {
615 186
        return $this->getRepository($documentName)->find($identifier, $lockMode, $lockVersion);
616
    }
617
618
    /**
619
     * Clears the DocumentManager.
620
     *
621
     * All documents that are currently managed by this DocumentManager become
622
     * detached.
623
     *
624
     * @param string|null $documentName if given, only documents of this type will get detached
625
     */
626 411
    public function clear($documentName = null)
627
    {
628 411
        $this->unitOfWork->clear($documentName);
629 411
    }
630
631
    /**
632
     * Closes the DocumentManager. All documents that are currently managed
633
     * by this DocumentManager become detached. The DocumentManager may no longer
634
     * be used after it is closed.
635
     */
636 6
    public function close()
637
    {
638 6
        $this->clear();
639 6
        $this->closed = true;
640 6
    }
641
642
    /**
643
     * Determines whether a document instance is managed in this DocumentManager.
644
     *
645
     * @param object $document
646
     * @throws \InvalidArgumentException When the $document param is not an object
647
     * @return boolean TRUE if this DocumentManager currently manages the given document, FALSE otherwise.
648
     */
649 6
    public function contains($document)
650
    {
651 6
        if ( ! is_object($document)) {
652
            throw new \InvalidArgumentException(gettype($document));
653
        }
654 6
        return $this->unitOfWork->isScheduledForInsert($document) ||
655 6
            $this->unitOfWork->isInIdentityMap($document) &&
656 6
            ! $this->unitOfWork->isScheduledForDelete($document);
657
    }
658
659
    /**
660
     * Gets the Configuration used by the DocumentManager.
661
     *
662
     * @return Configuration
663
     */
664 758
    public function getConfiguration()
665
    {
666 758
        return $this->config;
667
    }
668
669
    /**
670
     * Returns a DBRef array for the supplied document.
671
     *
672
     * @param mixed $document A document object
673
     * @param array $referenceMapping Mapping for the field that references the document
674
     *
675
     * @throws \InvalidArgumentException
676
     * @return array A DBRef array
677
     */
678 216
    public function createDBRef($document, array $referenceMapping = null)
679
    {
680 216
        if ( ! is_object($document)) {
681
            throw new \InvalidArgumentException('Cannot create a DBRef, the document is not an object');
682
        }
683
684 216
        $class = $this->getClassMetadata(get_class($document));
685 216
        $id = $this->unitOfWork->getDocumentIdentifier($document);
686
687 216
        if ($id === null) {
688 1
            throw new \RuntimeException(
689 1
                sprintf('Cannot create a DBRef for class %s without an identifier. Have you forgotten to persist/merge the document first?', $class->name)
690 1
            );
691
        }
692
693 215
        if ($referenceMapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID) {
694 27
            if ($class->inheritanceType === ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_COLLECTION) {
695 1
                throw MappingException::simpleReferenceMustNotTargetDiscriminatedDocument($referenceMapping['targetDocument']);
696
            }
697 26
            return $class->getDatabaseIdentifierValue($id);
698
        }
699
700
        $dbRef = array(
701 195
            '$ref' => $class->getCollection(),
702 195
            '$id'  => $class->getDatabaseIdentifierValue($id),
703 195
        );
704
705 195
        if ($referenceMapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_DB_REF_WITH_DB) {
706 191
            $dbRef['$db'] = $this->getDocumentDatabase($class->name)->getName();
707 191
        }
708
709
        /* If the class has a discriminator (field and value), use it. A child
710
         * class that is not defined in the discriminator map may only have a
711
         * discriminator field and no value, so default to the full class name.
712
         */
713 195 View Code Duplication
        if (isset($class->discriminatorField)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
714 18
            $dbRef[$class->discriminatorField] = isset($class->discriminatorValue)
715 18
                ? $class->discriminatorValue
716 18
                : $class->name;
717 18
        }
718
719
        /* Add a discriminator value if the referenced document is not mapped
720
         * explicitly to a targetDocument class.
721
         */
722 195 View Code Duplication
        if ($referenceMapping !== null && ! isset($referenceMapping['targetDocument'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
723 30
            $discriminatorField = $referenceMapping['discriminatorField'];
724 30
            $discriminatorValue = isset($referenceMapping['discriminatorMap'])
725 30
                ? array_search($class->name, $referenceMapping['discriminatorMap'])
726 30
                : $class->name;
727
728
            /* If the discriminator value was not found in the map, use the full
729
             * class name. In the future, it may be preferable to throw an
730
             * exception here (perhaps based on some strictness option).
731
             *
732
             * @see PersistenceBuilder::prepareEmbeddedDocumentValue()
733
             */
734 30
            if ($discriminatorValue === false) {
735 2
                $discriminatorValue = $class->name;
736 2
            }
737
738 30
            $dbRef[$discriminatorField] = $discriminatorValue;
739 30
        }
740
741 195
        return $dbRef;
742
    }
743
744
    /**
745
     * Throws an exception if the DocumentManager is closed or currently not active.
746
     *
747
     * @throws MongoDBException If the DocumentManager is closed.
748
     */
749 631
    private function errorIfClosed()
750
    {
751 631
        if ($this->closed) {
752 5
            throw MongoDBException::documentManagerClosed();
753
        }
754 626
    }
755
756
    /**
757
     * Check if the Document manager is open or closed.
758
     *
759
     * @return bool
760
     */
761 1
    public function isOpen()
762
    {
763 1
        return ( ! $this->closed);
764
    }
765
766
    /**
767
     * Gets the filter collection.
768
     *
769
     * @return \Doctrine\ODM\MongoDB\Query\FilterCollection The active filter collection.
770
     */
771 521
    public function getFilterCollection()
772
    {
773 521
        if (null === $this->filterCollection) {
774 521
            $this->filterCollection = new FilterCollection($this);
775 521
        }
776
777 521
        return $this->filterCollection;
778
    }
779
}
780