Failed Conditions
Pull Request — master (#7130)
by Michael
13:25 queued 18s
created

EntityManager::refresh()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 9
ccs 4
cts 5
cp 0.8
crap 2.032
rs 9.6666
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\ClassMetadataFactory as CommonClassMetadataFactory;
9
use Doctrine\Common\Persistence\Mapping\MappingException;
10
use Doctrine\Common\Persistence\ObjectRepository;
11
use Doctrine\DBAL\Connection;
12
use Doctrine\DBAL\DriverManager;
13
use Doctrine\DBAL\LockMode;
14
use Doctrine\ORM\Internal\Hydration\AbstractHydrator;
15
use Doctrine\ORM\Mapping\ClassMetadata;
16
use Doctrine\ORM\Mapping\ClassMetadataFactory;
17
use Doctrine\ORM\Proxy\Factory\ProxyFactory;
18
use Doctrine\ORM\Proxy\Factory\StaticProxyFactory;
19
use Doctrine\ORM\Query\Expr;
20
use Doctrine\ORM\Query\FilterCollection;
21
use Doctrine\ORM\Query\ResultSetMapping;
22
use Doctrine\ORM\Repository\RepositoryFactory;
23
use Doctrine\ORM\Utility\IdentifierFlattener;
24
use Doctrine\ORM\Utility\StaticClassNameConverter;
25
use function array_keys;
26
use function get_class;
27
use function gettype;
28
use function is_array;
29
use function is_object;
30
use function ltrim;
31
use function sprintf;
32
33
/**
34
 * The EntityManager is the central access point to ORM functionality.
35
 *
36
 * It is a facade to all different ORM subsystems such as UnitOfWork,
37
 * Query Language and Repository API. Instantiation is done through
38
 * the static create() method. The quickest way to obtain a fully
39
 * configured EntityManager is:
40
 *
41
 *     use Doctrine\ORM\Tools\Setup;
42
 *     use Doctrine\ORM\EntityManager;
43
 *
44
 *     $paths = array('/path/to/entity/mapping/files');
45
 *
46
 *     $config = Setup::createAnnotationMetadataConfiguration($paths);
47
 *     $dbParams = array('driver' => 'pdo_sqlite', 'memory' => true);
48
 *     $entityManager = EntityManager::create($dbParams, $config);
49
 *
50
 * For more information see
51
 * {@link http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/configuration.html}
52
 *
53
 * You should never attempt to inherit from the EntityManager: Inheritance
54
 * is not a valid extension point for the EntityManager. Instead you
55
 * should take a look at the {@see \Doctrine\ORM\Decorator\EntityManagerDecorator}
56
 * and wrap your entity manager in a decorator.
57
 */
58
final class EntityManager implements EntityManagerInterface
59
{
60
    /**
61
     * The used Configuration.
62
     *
63
     * @var Configuration
64
     */
65
    private $config;
66
67
    /**
68
     * The database connection used by the EntityManager.
69
     *
70
     * @var Connection
71
     */
72
    private $conn;
73
74
    /**
75
     * The metadata factory, used to retrieve the ORM metadata of entity classes.
76
     *
77
     * @var ClassMetadataFactory
78
     */
79
    private $metadataFactory;
80
81
    /**
82
     * The UnitOfWork used to coordinate object-level transactions.
83
     *
84
     * @var UnitOfWork
85
     */
86
    private $unitOfWork;
87
88
    /**
89
     * The event manager that is the central point of the event system.
90
     *
91
     * @var EventManager
92
     */
93
    private $eventManager;
94
95
    /**
96
     * The proxy factory used to create dynamic proxies.
97
     *
98
     * @var ProxyFactory
99
     */
100
    private $proxyFactory;
101
102
    /**
103
     * The repository factory used to create dynamic repositories.
104
     *
105
     * @var RepositoryFactory
106
     */
107
    private $repositoryFactory;
108
109
    /**
110
     * The expression builder instance used to generate query expressions.
111
     *
112
     * @var Expr
113
     */
114
    private $expressionBuilder;
115
116
    /**
117
     * The IdentifierFlattener used for manipulating identifiers
118
     *
119
     * @var IdentifierFlattener
120
     */
121
    private $identifierFlattener;
122
123
    /**
124
     * Whether the EntityManager is closed or not.
125
     *
126
     * @var bool
127
     */
128
    private $closed = false;
129
130
    /**
131
     * Collection of query filters.
132
     *
133
     * @var FilterCollection
134
     */
135
    private $filterCollection;
136
137
    /** @var Cache The second level cache regions API. */
138
    private $cache;
139
140
    /**
141
     * Creates a new EntityManager that operates on the given database connection
142
     * and uses the given Configuration and EventManager implementations.
143
     *
144
     */
145 2242
    protected function __construct(Connection $conn, Configuration $config, EventManager $eventManager)
146
    {
147 2242
        $this->conn         = $conn;
148 2242
        $this->config       = $config;
149 2242
        $this->eventManager = $eventManager;
150
151 2242
        $metadataFactoryClassName = $config->getClassMetadataFactoryName();
152
153 2242
        $this->metadataFactory = new $metadataFactoryClassName();
154
155 2242
        $this->metadataFactory->setEntityManager($this);
156 2242
        $this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl());
157
158 2242
        $this->repositoryFactory   = $config->getRepositoryFactory();
159 2242
        $this->unitOfWork          = new UnitOfWork($this);
160 2242
        $this->proxyFactory        = new StaticProxyFactory($this, $this->config->buildGhostObjectFactory());
161 2242
        $this->identifierFlattener = new IdentifierFlattener($this->unitOfWork, $this->metadataFactory);
162
163 2242
        if ($config->isSecondLevelCacheEnabled()) {
164 280
            $cacheConfig  = $config->getSecondLevelCacheConfiguration();
165 280
            $cacheFactory = $cacheConfig->getCacheFactory();
166 280
            $this->cache  = $cacheFactory->createCache($this);
167
        }
168 2242
    }
169
170
    /**
171
     * {@inheritDoc}
172
     */
173 1780
    public function getConnection() : Connection
174
    {
175 1780
        return $this->conn;
176
    }
177
178
    /**
179
     * Gets the metadata factory used to gather the metadata of classes.
180
     */
181 812
    public function getMetadataFactory() : CommonClassMetadataFactory
182
    {
183 812
        return $this->metadataFactory;
184
    }
185
186
    /**
187
     * {@inheritDoc}
188
     */
189 17
    public function getExpressionBuilder() : Expr
190
    {
191 17
        if ($this->expressionBuilder === null) {
192 17
            $this->expressionBuilder = new Query\Expr();
193
        }
194
195 17
        return $this->expressionBuilder;
196
    }
197
198 1094
    public function getIdentifierFlattener() : IdentifierFlattener
199
    {
200 1094
        return $this->identifierFlattener;
201
    }
202
203
    /**
204
     * {@inheritDoc}
205
     */
206 1
    public function beginTransaction() : void
207
    {
208 1
        $this->conn->beginTransaction();
209 1
    }
210
211
    /**
212
     * {@inheritDoc}
213
     */
214 212
    public function getCache() : ?Cache
215
    {
216 212
        return $this->cache;
217
    }
218
219
    /**
220
     * {@inheritDoc}
221
     */
222 6
    public function transactional(callable $func)
223
    {
224 6
        $this->conn->beginTransaction();
225
226
        try {
227 6
            $return = $func($this);
228
229 5
            $this->flush();
230 5
            $this->conn->commit();
231
232 5
            return $return;
233 1
        } catch (\Throwable $e) {
234 1
            $this->close();
235 1
            $this->conn->rollBack();
236
237 1
            throw $e;
238
        }
239
    }
240
241
    /**
242
     * {@inheritDoc}
243
     */
244 1
    public function commit() : void
245
    {
246 1
        $this->conn->commit();
247 1
    }
248
249
    /**
250
     * {@inheritDoc}
251
     */
252
    public function rollback() : void
253
    {
254
        $this->conn->rollBack();
255
    }
256
257
    /**
258
     * Returns the ORM metadata descriptor for a class.
259
     *
260
     * The class name must be the fully-qualified class name without a leading backslash
261
     * (as it is returned by get_class($obj)) or an aliased class name.
262
     *
263
     * Examples:
264
     * MyProject\Domain\User
265
     * sales:PriceRequest
266
     *
267
     * {@internal Performance-sensitive method. }}
268
     *
269
     * @throws MappingException
270
     * @throws \ReflectionException
271
     */
272 1893
    public function getClassMetadata(string $className) : ClassMetadata
273
    {
274 1893
        return $this->metadataFactory->getMetadataFor($className);
275
    }
276
277
    /**
278
     * {@inheritDoc}
279
     */
280 954
    public function createQuery(string $dql = '') : Query
281
    {
282 954
        $query = new Query($this);
283
284 954
        if (! empty($dql)) {
285 949
            $query->setDQL($dql);
286
        }
287
288 954
        return $query;
289
    }
290
291
    /**
292
     * {@inheritDoc}
293
     */
294 13
    public function createNativeQuery(string $sql, ResultSetMapping $rsm) : NativeQuery
295
    {
296 13
        $query = new NativeQuery($this);
297
298 13
        $query->setSQL($sql);
299 13
        $query->setResultSetMapping($rsm);
300
301 13
        return $query;
302
    }
303
304
    /**
305
     * {@inheritDoc}
306
     */
307 128
    public function createQueryBuilder() : QueryBuilder
308
    {
309 128
        return new QueryBuilder($this);
310
    }
311
312
    /**
313
     * {@inheritDoc}
314
     *
315
     * @deprecated
316
     */
317
    public function merge(object $object) : object
318
    {
319
        throw new \BadMethodCallException('@TODO method disabled - will be removed in 3.0 with a release of doctrine/common');
320
    }
321
322
    /**
323
     * {@inheritDoc}
324
     *
325
     * @deprecated
326
     */
327
    public function detach(object $object) : void
328
    {
329
        throw new \BadMethodCallException('@TODO method disabled - will be removed in 3.0 with a release of doctrine/common');
330
    }
331
332
    /**
333
     * Flushes all changes to objects that have been queued up to now to the database.
334
     * This effectively synchronizes the in-memory state of managed objects with the
335
     * database.
336
     *
337
     * If an entity is explicitly passed to this method only this entity and
338
     * the cascade-persist semantics + scheduled inserts/removals are synchronized.
339
     *
340
     * @throws OptimisticLockException If a version check on an entity that
341
     *         makes use of optimistic locking fails.
342
     * @throws ORMException
343
     * @throws \Exception
344
     */
345 1005
    public function flush() : void
346
    {
347 1005
        $this->errorIfClosed();
348
349 1004
        $this->unitOfWork->commit();
350 994
    }
351
352
    /**
353
     * Finds an Entity by its identifier.
354
     *
355
     * @param string   $entityName  The class name of the entity to find.
356
     * @param mixed    $id          The identity of the entity to find.
357
     * @param int|null $lockMode    One of the \Doctrine\DBAL\LockMode::* constants
358
     *                              or NULL if no specific lock mode should be used
359
     *                              during the search.
360
     * @param int|null $lockVersion The version of the entity to find when using
361
     *                              optimistic locking.
362
     *
363
     * @return object|null The entity instance or NULL if the entity can not be found.
364
     *
365
     * @throws OptimisticLockException
366
     * @throws ORMInvalidArgumentException
367
     * @throws TransactionRequiredException
368
     * @throws ORMException
369
     */
370 403
    public function find(string $className, $id, ?int $lockMode = null, ?int $lockVersion = null) : ?object
371
    {
372 403
        $class     = $this->metadataFactory->getMetadataFor(ltrim($className, '\\'));
373 403
        $className = $class->getClassName();
374
375 403
        if (! is_array($id)) {
376 371
            if ($class->isIdentifierComposite()) {
377
                throw ORMInvalidArgumentException::invalidCompositeIdentifier();
378
            }
379
380 371
            $id = [$class->identifier[0] => $id];
381
        }
382
383 403
        foreach ($id as $i => $value) {
384 403
            if (is_object($value) && $this->metadataFactory->hasMetadataFor(StaticClassNameConverter::getClass($value))) {
385 10
                $id[$i] = $this->unitOfWork->getSingleIdentifierValue($value);
386
387 10
                if ($id[$i] === null) {
388 403
                    throw ORMInvalidArgumentException::invalidIdentifierBindingEntity();
389
                }
390
            }
391
        }
392
393 402
        $sortedId = [];
394
395 402
        foreach ($class->identifier as $identifier) {
396 402
            if (! isset($id[$identifier])) {
397 1
                throw ORMException::missingIdentifierField($className, $identifier);
398
            }
399
400 401
            $sortedId[$identifier] = $id[$identifier];
401 401
            unset($id[$identifier]);
402
        }
403
404 401
        if ($id) {
405 1
            throw ORMException::unrecognizedIdentifierFields($className, array_keys($id));
406
        }
407
408 400
        $unitOfWork = $this->getUnitOfWork();
409
410
        // Check identity map first
411 400
        $entity = $unitOfWork->tryGetById($sortedId, $class->getRootClassName());
412 400
        if ($entity !== false) {
413 45
            if (! ($entity instanceof $className)) {
414 1
                return null;
415
            }
416
417
            switch (true) {
418 44
                case $lockMode === LockMode::OPTIMISTIC:
419 1
                    $this->lock($entity, $lockMode, $lockVersion);
0 ignored issues
show
Bug introduced by
It seems like $entity can also be of type true; however, parameter $entity of Doctrine\ORM\EntityManager::lock() 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

419
                    $this->lock(/** @scrutinizer ignore-type */ $entity, $lockMode, $lockVersion);
Loading history...
420
                    break;
421
422 44
                case $lockMode === LockMode::NONE:
423 44
                case $lockMode === LockMode::PESSIMISTIC_READ:
424 44
                case $lockMode === LockMode::PESSIMISTIC_WRITE:
425
                    $persister = $unitOfWork->getEntityPersister($className);
426
                    $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

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