Failed Conditions
Pull Request — master (#7123)
by Michael
11:30
created

EntityManager::getCache()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ORM;
6
7
use Doctrine\Common\EventManager;
8
use Doctrine\Common\Persistence\Mapping\MappingException;
9
use Doctrine\Common\Persistence\ObjectRepository;
10
use Doctrine\DBAL\Connection;
11
use Doctrine\DBAL\LockMode;
12
use Doctrine\ORM\Mapping\ClassMetadataFactory;
13
use Doctrine\ORM\Proxy\Factory\ProxyFactory;
14
use Doctrine\ORM\Proxy\Factory\StaticProxyFactory;
15
use Doctrine\ORM\Query\Expr;
16
use Doctrine\ORM\Query\FilterCollection;
17
use Doctrine\ORM\Query\ResultSetMapping;
18
use Doctrine\ORM\Repository\RepositoryFactory;
19
use Doctrine\ORM\Utility\IdentifierFlattener;
20
use Doctrine\ORM\Utility\StaticClassNameConverter;
21
use function array_keys;
22
use function is_array;
23
use function is_object;
24
use function ltrim;
25
26
/**
27
 * The EntityManager is the central access point to ORM functionality.
28
 *
29
 * It is a facade to all different ORM subsystems such as UnitOfWork,
30
 * Query Language and Repository API. Instantiation is done through
31
 * the static create() method. The quickest way to obtain a fully
32
 * configured EntityManager is:
33
 *
34
 *     use Doctrine\DBAL\DriverManager;
35
 *     use Doctrine\ORM\EntityManager;
36
 *     use Doctrine\ORM\Tools\Setup;
37
 *
38
 *     $paths = ['/path/to/entity/mapping/files'];
39
 *
40
 *     $configuration = Setup::createAnnotationMetadataConfiguration($paths);
41
 *     $connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'memory' => true]);
42
 *     $entityManager = EntityManager::create($connection, $configuration);
43
 *
44
 * For more information see
45
 * {@link http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/configuration.html}
46
 *
47
 * You should never attempt to inherit from the EntityManager: Inheritance
48
 * is not a valid extension point for the EntityManager. Instead you
49
 * should take a look at the {@see \Doctrine\ORM\Decorator\EntityManagerDecorator}
50
 * and wrap your entity manager in a decorator.
51
 */
52
final class EntityManager implements EntityManagerInterface
53
{
54
    /**
55
     * The used Configuration.
56
     *
57
     * @var Configuration
58
     */
59
    private $config;
60
61
    /**
62
     * The database connection used by the EntityManager.
63
     *
64
     * @var Connection
65
     */
66
    private $conn;
67
68
    /**
69
     * The metadata factory, used to retrieve the ORM metadata of entity classes.
70
     *
71
     * @var ClassMetadataFactory
72
     */
73
    private $metadataFactory;
74
75
    /**
76
     * The UnitOfWork used to coordinate object-level transactions.
77
     *
78
     * @var UnitOfWork
79
     */
80
    private $unitOfWork;
81
82
    /**
83
     * The event manager that is the central point of the event system.
84
     *
85
     * @var EventManager
86
     */
87
    private $eventManager;
88
89
    /**
90
     * The proxy factory used to create dynamic proxies.
91
     *
92
     * @var ProxyFactory
93
     */
94
    private $proxyFactory;
95
96
    /**
97
     * The repository factory used to create dynamic repositories.
98
     *
99
     * @var RepositoryFactory
100
     */
101
    private $repositoryFactory;
102
103
    /**
104
     * The expression builder instance used to generate query expressions.
105
     *
106
     * @var Expr
107
     */
108
    private $expressionBuilder;
109
110
    /**
111
     * The IdentifierFlattener used for manipulating identifiers
112
     *
113
     * @var IdentifierFlattener
114
     */
115
    private $identifierFlattener;
116
117
    /**
118
     * Whether the EntityManager is closed or not.
119
     *
120
     * @var bool
121
     */
122
    private $closed = false;
123
124
    /**
125
     * Collection of query filters.
126
     *
127
     * @var FilterCollection
128
     */
129
    private $filterCollection;
130
131
    /** @var Cache The second level cache regions API. */
132
    private $cache;
133
134
    /**
135
     * Creates a new EntityManager that operates on the given database connection
136
     * and uses the given Configuration and EventManager implementations.
137
     *
138
     */
139 2246
    protected function __construct(Connection $conn, Configuration $config, EventManager $eventManager)
140
    {
141 2246
        $this->conn         = $conn;
142 2246
        $this->config       = $config;
143 2246
        $this->eventManager = $eventManager;
144
145 2246
        $metadataFactoryClassName = $config->getClassMetadataFactoryName();
146
147 2246
        $this->metadataFactory = new $metadataFactoryClassName();
148
149 2246
        $this->metadataFactory->setEntityManager($this);
150 2246
        $this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl());
151
152 2246
        $this->repositoryFactory   = $config->getRepositoryFactory();
153 2246
        $this->unitOfWork          = new UnitOfWork($this);
154 2246
        $this->proxyFactory        = new StaticProxyFactory($this, $this->config->buildGhostObjectFactory());
155 2246
        $this->identifierFlattener = new IdentifierFlattener($this->unitOfWork, $this->metadataFactory);
156
157 2246
        if ($config->isSecondLevelCacheEnabled()) {
158 280
            $cacheConfig  = $config->getSecondLevelCacheConfiguration();
159 280
            $cacheFactory = $cacheConfig->getCacheFactory();
160 280
            $this->cache  = $cacheFactory->createCache($this);
161
        }
162 2246
    }
163
164
    /**
165
     * {@inheritDoc}
166
     */
167 1781
    public function getConnection()
168
    {
169 1781
        return $this->conn;
170
    }
171
172
    /**
173
     * Gets the metadata factory used to gather the metadata of classes.
174
     *
175
     * @return ClassMetadataFactory
176
     */
177 812
    public function getMetadataFactory()
178
    {
179 812
        return $this->metadataFactory;
180
    }
181
182
    /**
183
     * {@inheritDoc}
184
     */
185 17
    public function getExpressionBuilder()
186
    {
187 17
        if ($this->expressionBuilder === null) {
188 17
            $this->expressionBuilder = new Query\Expr();
189
        }
190
191 17
        return $this->expressionBuilder;
192
    }
193
194 1094
    public function getIdentifierFlattener() : IdentifierFlattener
195
    {
196 1094
        return $this->identifierFlattener;
197
    }
198
199
    /**
200
     * {@inheritDoc}
201
     */
202 1
    public function beginTransaction()
203
    {
204 1
        $this->conn->beginTransaction();
205 1
    }
206
207
    /**
208
     * {@inheritDoc}
209
     */
210 212
    public function getCache()
211
    {
212 212
        return $this->cache;
213
    }
214
215
    /**
216
     * {@inheritDoc}
217
     */
218 6
    public function transactional(callable $func)
219
    {
220 6
        $this->conn->beginTransaction();
221
222
        try {
223 6
            $return = $func($this);
224
225 5
            $this->flush();
226 5
            $this->conn->commit();
227
228 5
            return $return;
229 1
        } catch (\Throwable $e) {
230 1
            $this->close();
231 1
            $this->conn->rollBack();
232
233 1
            throw $e;
234
        }
235
    }
236
237
    /**
238
     * {@inheritDoc}
239
     */
240 1
    public function commit()
241
    {
242 1
        $this->conn->commit();
243 1
    }
244
245
    /**
246
     * {@inheritDoc}
247
     */
248
    public function rollback()
249
    {
250
        $this->conn->rollBack();
251
    }
252
253
    /**
254
     * Returns the ORM metadata descriptor for a class.
255
     *
256
     * The class name must be the fully-qualified class name without a leading backslash
257
     * (as it is returned by get_class($obj)) or an aliased class name.
258
     *
259
     * Examples:
260
     * MyProject\Domain\User
261
     * sales:PriceRequest
262
     *
263
     * {@internal Performance-sensitive method. }}
264
     *
265
     * @param string $className
266
     *
267
     * @throws \ReflectionException
268
     * @throws \InvalidArgumentException
269
     * @throws MappingException
270
     */
271 1894
    public function getClassMetadata($className) : Mapping\ClassMetadata
272
    {
273 1894
        return $this->metadataFactory->getMetadataFor($className);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->metadataFa...MetadataFor($className) returns the type Doctrine\ORM\Mapping\ClassMetadata which is incompatible with the return type mandated by Doctrine\Common\Persiste...ger::getClassMetadata() of Doctrine\Common\Persistence\Mapping\ClassMetadata.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
274
    }
275
276
    /**
277
     * {@inheritDoc}
278
     */
279 954
    public function createQuery($dql = '')
280
    {
281 954
        $query = new Query($this);
282
283 954
        if (! empty($dql)) {
284 949
            $query->setDQL($dql);
285
        }
286
287 954
        return $query;
288
    }
289
290
    /**
291
     * {@inheritDoc}
292
     */
293 13
    public function createNativeQuery($sql, ResultSetMapping $rsm)
294
    {
295 13
        $query = new NativeQuery($this);
296
297 13
        $query->setSQL($sql);
298 13
        $query->setResultSetMapping($rsm);
299
300 13
        return $query;
301
    }
302
303
    /**
304
     * {@inheritDoc}
305
     */
306 128
    public function createQueryBuilder()
307
    {
308 128
        return new QueryBuilder($this);
309
    }
310
311
    /**
312
     * {@inheritDoc}
313
     *
314
     * @deprecated
315
     */
316
    public function merge($object)
317
    {
318
        throw new \BadMethodCallException('@TODO method disabled - will be removed in 3.0 with a release of doctrine/common');
319
    }
320
321
    /**
322
     * {@inheritDoc}
323
     *
324
     * @deprecated
325
     */
326
    public function detach($object)
327
    {
328
        throw new \BadMethodCallException('@TODO method disabled - will be removed in 3.0 with a release of doctrine/common');
329
    }
330
331
    /**
332
     * Flushes all changes to objects that have been queued up to now to the database.
333
     * This effectively synchronizes the in-memory state of managed objects with the
334
     * database.
335
     *
336
     * If an entity is explicitly passed to this method only this entity and
337
     * the cascade-persist semantics + scheduled inserts/removals are synchronized.
338
     *
339
     * @throws OptimisticLockException If a version check on an entity that
340
     *         makes use of optimistic locking fails.
341
     * @throws ORMException
342
     */
343 1005
    public function flush()
344
    {
345 1005
        $this->errorIfClosed();
346
347 1004
        $this->unitOfWork->commit();
348 994
    }
349
350
    /**
351
     * Finds an Entity by its identifier.
352
     *
353
     * @param string   $entityName  The class name of the entity to find.
354
     * @param mixed    $id          The identity of the entity to find.
355
     * @param int|null $lockMode    One of the \Doctrine\DBAL\LockMode::* constants
356
     *                              or NULL if no specific lock mode should be used
357
     *                              during the search.
358
     * @param int|null $lockVersion The version of the entity to find when using
359
     *                              optimistic locking.
360
     *
361
     * @return object|null The entity instance or NULL if the entity can not be found.
362
     *
363
     * @throws OptimisticLockException
364
     * @throws ORMInvalidArgumentException
365
     * @throws TransactionRequiredException
366
     * @throws ORMException
367
     */
368 403
    public function find($entityName, $id, $lockMode = null, $lockVersion = null)
369
    {
370 403
        $class     = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
371 403
        $className = $class->getClassName();
372
373 403
        if (! is_array($id)) {
374 371
            if ($class->isIdentifierComposite()) {
375
                throw ORMInvalidArgumentException::invalidCompositeIdentifier();
376
            }
377
378 371
            $id = [$class->identifier[0] => $id];
379
        }
380
381 403
        foreach ($id as $i => $value) {
382 403
            if (is_object($value) && $this->metadataFactory->hasMetadataFor(StaticClassNameConverter::getClass($value))) {
383 10
                $id[$i] = $this->unitOfWork->getSingleIdentifierValue($value);
384
385 10
                if ($id[$i] === null) {
386 403
                    throw ORMInvalidArgumentException::invalidIdentifierBindingEntity();
387
                }
388
            }
389
        }
390
391 402
        $sortedId = [];
392
393 402
        foreach ($class->identifier as $identifier) {
394 402
            if (! isset($id[$identifier])) {
395 1
                throw ORMException::missingIdentifierField($className, $identifier);
396
            }
397
398 401
            $sortedId[$identifier] = $id[$identifier];
399 401
            unset($id[$identifier]);
400
        }
401
402 401
        if ($id) {
403 1
            throw ORMException::unrecognizedIdentifierFields($className, array_keys($id));
404
        }
405
406 400
        $unitOfWork = $this->getUnitOfWork();
407
408
        // Check identity map first
409 400
        $entity = $unitOfWork->tryGetById($sortedId, $class->getRootClassName());
410 400
        if ($entity !== false) {
411 45
            if (! ($entity instanceof $className)) {
412 1
                return null;
413
            }
414
415
            switch (true) {
416 44
                case $lockMode === LockMode::OPTIMISTIC:
417 1
                    $this->lock($entity, $lockMode, $lockVersion);
418
                    break;
419
420 44
                case $lockMode === LockMode::NONE:
421 44
                case $lockMode === LockMode::PESSIMISTIC_READ:
422 44
                case $lockMode === LockMode::PESSIMISTIC_WRITE:
423
                    $persister = $unitOfWork->getEntityPersister($className);
424
                    $persister->refresh($sortedId, $entity, $lockMode);
0 ignored issues
show
Bug introduced by
It seems like $entity can also be of type true; however, parameter $entity of Doctrine\ORM\Persisters\...ityPersister::refresh() does only seem to accept object, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

424
                    $persister->refresh($sortedId, /** @scrutinizer ignore-type */ $entity, $lockMode);
Loading history...
425
                    break;
426
            }
427
428 44
            return $entity; // Hit!
0 ignored issues
show
Bug Best Practice introduced by
The expression return $entity also could return the type true which is incompatible with the documented return type object|null.
Loading history...
429
        }
430
431 379
        $persister = $unitOfWork->getEntityPersister($className);
432
433
        switch (true) {
434 379
            case $lockMode === LockMode::OPTIMISTIC:
435 1
                if (! $class->isVersioned()) {
436 1
                    throw OptimisticLockException::notVersioned($className);
437
                }
438
439
                $entity = $persister->load($sortedId);
440
441
                $unitOfWork->lock($entity, $lockMode, $lockVersion);
442
443
                return $entity;
444
445 378
            case $lockMode === LockMode::PESSIMISTIC_READ:
446 377
            case $lockMode === LockMode::PESSIMISTIC_WRITE:
447 2
                if (! $this->getConnection()->isTransactionActive()) {
448 2
                    throw TransactionRequiredException::transactionRequired();
449
                }
450
451
                return $persister->load($sortedId, null, null, [], $lockMode);
452
453
            default:
454 376
                return $persister->loadById($sortedId);
455
        }
456
    }
457
458
    /**
459
     * {@inheritDoc}
460
     */
461 90
    public function getReference($entityName, $id)
462
    {
463 90
        $class     = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
464 90
        $className = $class->getClassName();
465
466 90
        if (! is_array($id)) {
467 39
            if ($class->isIdentifierComposite()) {
468
                throw ORMInvalidArgumentException::invalidCompositeIdentifier();
469
            }
470
471 39
            $id = [$class->identifier[0] => $id];
472
        }
473
474 90
        $scalarId = [];
475
476 90
        foreach ($id as $i => $value) {
477 90
            $scalarId[$i] = $value;
478
479 90
            if (is_object($value) && $this->metadataFactory->hasMetadataFor(StaticClassNameConverter::getClass($value))) {
480 2
                $scalarId[$i] = $this->unitOfWork->getSingleIdentifierValue($value);
481
482 2
                if ($scalarId[$i] === null) {
483 90
                    throw ORMInvalidArgumentException::invalidIdentifierBindingEntity();
484
                }
485
            }
486
        }
487
488 90
        $sortedId = [];
489
490 90
        foreach ($class->identifier as $identifier) {
491 90
            if (! isset($scalarId[$identifier])) {
492
                throw ORMException::missingIdentifierField($className, $identifier);
493
            }
494
495 90
            $sortedId[$identifier] = $scalarId[$identifier];
496 90
            unset($scalarId[$identifier]);
497
        }
498
499 90
        if ($scalarId) {
500 1
            throw ORMException::unrecognizedIdentifierFields($className, array_keys($scalarId));
501
        }
502
503
        // Check identity map first, if its already in there just return it.
504 89
        $entity = $this->unitOfWork->tryGetById($sortedId, $class->getRootClassName());
505 89
        if ($entity !== false) {
506 29
            return ($entity instanceof $className) ? $entity : null;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $entity instanceo...ssName ? $entity : null also could return the type true which is incompatible with the return type mandated by Doctrine\ORM\EntityManag...terface::getReference() of object|null|ProxyManager...xy\GhostObjectInterface.
Loading history...
507
        }
508
509 84
        if ($class->getSubClasses()) {
510 2
            return $this->find($entityName, $sortedId);
511
        }
512
513 84
        $entity = $this->proxyFactory->getProxy($class, $id);
514
515 84
        $this->unitOfWork->registerManaged($entity, $sortedId, []);
516
517 84
        if ($entity instanceof EntityManagerAware) {
518 3
            $entity->injectEntityManager($this, $class);
519
        }
520
521 84
        return $entity;
522
    }
523
524
    /**
525
     * {@inheritDoc}
526
     */
527 4
    public function getPartialReference($entityName, $id)
528
    {
529 4
        $class     = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
530 4
        $className = $class->getClassName();
531
532 4
        if (! is_array($id)) {
533 4
            if ($class->isIdentifierComposite()) {
534
                throw ORMInvalidArgumentException::invalidCompositeIdentifier();
535
            }
536
537 4
            $id = [$class->identifier[0] => $id];
538
        }
539
540 4
        foreach ($id as $i => $value) {
541 4
            if (is_object($value) && $this->metadataFactory->hasMetadataFor(StaticClassNameConverter::getClass($value))) {
542
                $id[$i] = $this->unitOfWork->getSingleIdentifierValue($value);
543
544
                if ($id[$i] === null) {
545 4
                    throw ORMInvalidArgumentException::invalidIdentifierBindingEntity();
546
                }
547
            }
548
        }
549
550 4
        $sortedId = [];
551
552 4
        foreach ($class->identifier as $identifier) {
553 4
            if (! isset($id[$identifier])) {
554
                throw ORMException::missingIdentifierField($className, $identifier);
555
            }
556
557 4
            $sortedId[$identifier] = $id[$identifier];
558 4
            unset($id[$identifier]);
559
        }
560
561 4
        if ($id) {
562
            throw ORMException::unrecognizedIdentifierFields($className, array_keys($id));
563
        }
564
565
        // Check identity map first, if its already in there just return it.
566 4
        $entity = $this->unitOfWork->tryGetById($sortedId, $class->getRootClassName());
567 4
        if ($entity !== false) {
568 1
            return ($entity instanceof $className) ? $entity : null;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $entity instanceo...ssName ? $entity : null also could return the type true which is incompatible with the return type mandated by Doctrine\ORM\EntityManag...::getPartialReference() of object.
Loading history...
569
        }
570
571 3
        $persister = $this->unitOfWork->getEntityPersister($class->getClassName());
572 3
        $entity    = $this->unitOfWork->newInstance($class);
573
574 3
        $persister->setIdentifier($entity, $sortedId);
575
576 3
        $this->unitOfWork->registerManaged($entity, $sortedId, []);
577 3
        $this->unitOfWork->markReadOnly($entity);
578
579 3
        return $entity;
580
    }
581
582
    /**
583
     * Clears the EntityManager. All entities that are currently managed
584
     * by this EntityManager become detached.
585
     *
586
     * @param null $entityName Unused. @todo Remove from ObjectManager.
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $entityName is correct as it would always require null to be passed?
Loading history...
587
     *
588
     */
589 1197
    public function clear($entityName = null)
590
    {
591 1197
        $this->unitOfWork->clear();
592
593 1197
        $this->unitOfWork = new UnitOfWork($this);
594
595 1197
        if ($this->eventManager->hasListeners(Events::onClear)) {
596 9
            $this->eventManager->dispatchEvent(Events::onClear, new Event\OnClearEventArgs($this));
597
        }
598 1197
    }
599
600
    /**
601
     * {@inheritDoc}
602
     */
603 18
    public function close()
604
    {
605 18
        $this->clear();
606
607 18
        $this->closed = true;
608 18
    }
609
610
    /**
611
     * Tells the EntityManager to make an instance managed and persistent.
612
     *
613
     * The entity will be entered into the database at or before transaction
614
     * commit or as a result of the flush operation.
615
     *
616
     * NOTE: The persist operation always considers entities that are not yet known to
617
     * this EntityManager as NEW. Do not pass detached entities to the persist operation.
618
     *
619
     * @param object $entity The instance to make managed and persistent.
620
     *
621
     * @throws ORMInvalidArgumentException
622
     * @throws ORMException
623
     */
624 999
    public function persist($entity)
625
    {
626 999
        if (! is_object($entity)) {
627 1
            throw ORMInvalidArgumentException::invalidObject('EntityManager#persist()', $entity);
628
        }
629
630 998
        $this->errorIfClosed();
631
632 997
        $this->unitOfWork->persist($entity);
633 996
    }
634
635
    /**
636
     * Removes an entity instance.
637
     *
638
     * A removed entity will be removed from the database at or before transaction commit
639
     * or as a result of the flush operation.
640
     *
641
     * @param object $entity The entity instance to remove.
642
     *
643
     * @throws ORMInvalidArgumentException
644
     * @throws ORMException
645
     */
646 49
    public function remove($entity)
647
    {
648 49
        if (! is_object($entity)) {
649 1
            throw ORMInvalidArgumentException::invalidObject('EntityManager#remove()', $entity);
650
        }
651
652 48
        $this->errorIfClosed();
653
654 47
        $this->unitOfWork->remove($entity);
655 47
    }
656
657
    /**
658
     * Refreshes the persistent state of an entity from the database,
659
     * overriding any local changes that have not yet been persisted.
660
     *
661
     * @param object $entity The entity to refresh.
662
     *
663
     * @throws ORMInvalidArgumentException
664
     * @throws ORMException
665
     */
666 17
    public function refresh($entity)
667
    {
668 17
        if (! is_object($entity)) {
669 1
            throw ORMInvalidArgumentException::invalidObject('EntityManager#refresh()', $entity);
670
        }
671
672 16
        $this->errorIfClosed();
673
674 15
        $this->unitOfWork->refresh($entity);
675 15
    }
676
677
    /**
678
     * {@inheritDoc}
679
     */
680 9
    public function lock($entity, $lockMode, $lockVersion = null)
681
    {
682 9
        $this->unitOfWork->lock($entity, $lockMode, $lockVersion);
683 2
    }
684
685
    /**
686
     * Gets the repository for an entity class.
687
     *
688
     * @param string $entityName The name of the entity.
689
     *
690
     * @return ObjectRepository|EntityRepository The repository class.
691
     */
692 137
    public function getRepository($entityName)
693
    {
694 137
        return $this->repositoryFactory->getRepository($this, $entityName);
695
    }
696
697
    /**
698
     * Determines whether an entity instance is managed in this EntityManager.
699
     *
700
     * @param object $entity
701
     *
702
     * @return bool TRUE if this EntityManager currently manages the given entity, FALSE otherwise.
703
     */
704 15
    public function contains($entity)
705
    {
706 15
        return $this->unitOfWork->isScheduledForInsert($entity)
707 15
            || ($this->unitOfWork->isInIdentityMap($entity) && ! $this->unitOfWork->isScheduledForDelete($entity));
708
    }
709
710
    /**
711
     * {@inheritDoc}
712
     */
713 2246
    public function getEventManager()
714
    {
715 2246
        return $this->eventManager;
716
    }
717
718
    /**
719
     * {@inheritDoc}
720
     */
721 2246
    public function getConfiguration()
722
    {
723 2246
        return $this->config;
724
    }
725
726
    /**
727
     * Throws an exception if the EntityManager is closed or currently not active.
728
     *
729
     * @throws ORMException If the EntityManager is closed.
730
     */
731 1010
    private function errorIfClosed()
732
    {
733 1010
        if ($this->closed) {
734 4
            throw ORMException::entityManagerClosed();
735
        }
736 1006
    }
737
738
    /**
739
     * {@inheritDoc}
740
     */
741 2
    public function isOpen()
742
    {
743 2
        return ! $this->closed;
744
    }
745
746
    /**
747
     * {@inheritDoc}
748
     */
749 1350
    public function getUnitOfWork()
750
    {
751 1350
        return $this->unitOfWork;
752
    }
753
754
    /**
755
     * {@inheritDoc}
756
     */
757
    public function getHydrator($hydrationMode)
758
    {
759
        return $this->newHydrator($hydrationMode);
760
    }
761
762
    /**
763
     * {@inheritDoc}
764
     */
765 883
    public function newHydrator($hydrationMode)
766
    {
767 883
        switch ($hydrationMode) {
768
            case Query::HYDRATE_OBJECT:
769 614
                return new Internal\Hydration\ObjectHydrator($this);
770
771
            case Query::HYDRATE_ARRAY:
772 45
                return new Internal\Hydration\ArrayHydrator($this);
773
774
            case Query::HYDRATE_SCALAR:
775 85
                return new Internal\Hydration\ScalarHydrator($this);
776
777
            case Query::HYDRATE_SINGLE_SCALAR:
778 13
                return new Internal\Hydration\SingleScalarHydrator($this);
779
780
            case Query::HYDRATE_SIMPLEOBJECT:
781 407
                return new Internal\Hydration\SimpleObjectHydrator($this);
782
783
            default:
784 1
                $class = $this->config->getCustomHydrationMode($hydrationMode);
785 1
                if ($class !== null) {
786 1
                    return new $class($this);
787
                }
788
        }
789
790
        throw ORMException::invalidHydrationMode($hydrationMode);
791
    }
792
793
    /**
794
     * {@inheritDoc}
795
     */
796 166
    public function getProxyFactory()
797
    {
798 166
        return $this->proxyFactory;
799
    }
800
801
    /**
802
     * {@inheritDoc}
803
     */
804
    public function initializeObject($obj)
805
    {
806
        $this->unitOfWork->initializeObject($obj);
807
    }
808
809
    /**
810
     * Factory method to create EntityManager instances.
811
     *
812
     * @param Connection    $connection   The Connection instance to use.
813
     * @param Configuration $config       The Configuration instance to use.
814
     * @param EventManager  $eventManager The EventManager instance to use.
815
     *
816
     * @return EntityManager The created EntityManager.
817
     *
818
     * @throws \InvalidArgumentException
819
     * @throws ORMException
820
     */
821 2246
    public static function create(Connection $connection, Configuration $config, ?EventManager $eventManager = null)
822
    {
823 2246
        if (! $config->getMetadataDriverImpl()) {
824
            throw ORMException::missingMappingDriverImpl();
825
        }
826
827 2246
        if ($eventManager !== null && $connection->getEventManager() !== $eventManager) {
828
            throw ORMException::mismatchedEventManager();
829
        }
830
831 2246
        return new EntityManager($connection, $config, $eventManager ?? $connection->getEventManager());
832
    }
833
834
    /**
835
     * {@inheritDoc}
836
     */
837 588
    public function getFilters()
838
    {
839 588
        if ($this->filterCollection === null) {
840 588
            $this->filterCollection = new FilterCollection($this);
841
        }
842
843 588
        return $this->filterCollection;
844
    }
845
846
    /**
847
     * {@inheritDoc}
848
     */
849 40
    public function isFiltersStateClean()
850
    {
851 40
        return $this->filterCollection === null || $this->filterCollection->isClean();
852
    }
853
854
    /**
855
     * {@inheritDoc}
856
     */
857 765
    public function hasFilters()
858
    {
859 765
        return $this->filterCollection !== null;
860
    }
861
}
862