Failed Conditions
Pull Request — master (#7143)
by Mike
14:34
created

EntityManager::createConnection()   B

Complexity

Conditions 8
Paths 4

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 8.2964

Importance

Changes 0
Metric Value
cc 8
eloc 11
nc 4
nop 3
dl 0
loc 21
rs 7.1428
c 0
b 0
f 0
ccs 10
cts 12
cp 0.8333
crap 8.2964
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\DriverManager;
12
use Doctrine\DBAL\LockMode;
13
use Doctrine\ORM\Mapping\ClassMetadataFactory;
14
use Doctrine\ORM\Proxy\Factory\ProxyFactory;
15
use Doctrine\ORM\Proxy\Factory\StaticProxyFactory;
16
use Doctrine\ORM\Query\Expr;
17
use Doctrine\ORM\Query\FilterCollection;
18
use Doctrine\ORM\Query\ResultSetMapping;
19
use Doctrine\ORM\Repository\RepositoryFactory;
20
use Doctrine\ORM\Utility\IdentifierFlattener;
21
use Doctrine\ORM\Utility\StaticClassNameConverter;
22
use function array_keys;
23
use function get_class;
24
use function gettype;
25
use function is_array;
26
use function is_object;
27
use function ltrim;
28
use function sprintf;
29
30
/**
31
 * The EntityManager is the central access point to ORM functionality.
32
 *
33
 * It is a facade to all different ORM subsystems such as UnitOfWork,
34
 * Query Language and Repository API. Instantiation is done through
35
 * the static create() method. The quickest way to obtain a fully
36
 * configured EntityManager is:
37
 *
38
 *     use Doctrine\ORM\Tools\Setup;
39
 *     use Doctrine\ORM\EntityManager;
40
 *
41
 *     $paths = array('/path/to/entity/mapping/files');
42
 *
43
 *     $config = Setup::createAnnotationMetadataConfiguration($paths);
44
 *     $dbParams = array('driver' => 'pdo_sqlite', 'memory' => true);
45
 *     $entityManager = EntityManager::create($dbParams, $config);
46
 *
47
 * For more information see
48
 * {@link http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/configuration.html}
49
 *
50
 * You should never attempt to inherit from the EntityManager: Inheritance
51
 * is not a valid extension point for the EntityManager. Instead you
52
 * should take a look at the {@see \Doctrine\ORM\Decorator\EntityManagerDecorator}
53
 * and wrap your entity manager in a decorator.
54
 */
55
final class EntityManager implements EntityManagerInterface
56
{
57
    /**
58
     * The used Configuration.
59
     *
60
     * @var Configuration
61
     */
62
    private $config;
63
64
    /**
65
     * The database connection used by the EntityManager.
66
     *
67
     * @var Connection
68
     */
69
    private $conn;
70
71
    /**
72
     * The metadata factory, used to retrieve the ORM metadata of entity classes.
73
     *
74
     * @var ClassMetadataFactory
75
     */
76
    private $metadataFactory;
77
78
    /**
79
     * The UnitOfWork used to coordinate object-level transactions.
80
     *
81
     * @var UnitOfWork
82
     */
83
    private $unitOfWork;
84
85
    /**
86
     * The event manager that is the central point of the event system.
87
     *
88
     * @var EventManager
89
     */
90
    private $eventManager;
91
92
    /**
93
     * The proxy factory used to create dynamic proxies.
94
     *
95
     * @var ProxyFactory
96
     */
97
    private $proxyFactory;
98
99
    /**
100
     * The repository factory used to create dynamic repositories.
101
     *
102
     * @var RepositoryFactory
103
     */
104
    private $repositoryFactory;
105
106
    /**
107
     * The expression builder instance used to generate query expressions.
108
     *
109
     * @var Expr
110
     */
111
    private $expressionBuilder;
112
113
    /**
114
     * The IdentifierFlattener used for manipulating identifiers
115
     *
116
     * @var IdentifierFlattener
117
     */
118
    private $identifierFlattener;
119
120
    /**
121
     * Whether the EntityManager is closed or not.
122
     *
123
     * @var bool
124
     */
125
    private $closed = false;
126
127
    /**
128
     * Collection of query filters.
129
     *
130
     * @var FilterCollection
131
     */
132
    private $filterCollection;
133
134
    /** @var Cache The second level cache regions API. */
135
    private $cache;
136
137
    /**
138
     * Creates a new EntityManager that operates on the given database connection
139
     * and uses the given Configuration and EventManager implementations.
140
     *
141
     */
142 2247
    protected function __construct(Connection $conn, Configuration $config, EventManager $eventManager, ClassMetadataFactory $classMetadataFactory)
143
    {
144 2247
        $this->conn            = $conn;
145 2247
        $this->config          = $config;
146 2247
        $this->eventManager    = $eventManager;
147 2247
        $this->metadataFactory = $classMetadataFactory;
148
149 2247
        $this->metadataFactory->setEntityManager($this);
150 2247
        $this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl());
151
152 2247
        $this->repositoryFactory   = $config->getRepositoryFactory();
153 2247
        $this->unitOfWork          = new UnitOfWork($this);
154 2247
        $this->proxyFactory        = new StaticProxyFactory($this, $this->config->buildGhostObjectFactory());
155 2247
        $this->identifierFlattener = new IdentifierFlattener($this->unitOfWork, $this->metadataFactory);
156
157 2247
        if ($config->isSecondLevelCacheEnabled()) {
158 280
            $cacheConfig  = $config->getSecondLevelCacheConfiguration();
159 280
            $cacheFactory = $cacheConfig->getCacheFactory();
160 280
            $this->cache  = $cacheFactory->createCache($this);
161
        }
162 2247
    }
163
164
165
166
    /**
167
     * {@inheritDoc}
168
     */
169 1781
    public function getConnection()
170
    {
171 1781
        return $this->conn;
172
    }
173
174
    /**
175
     * Gets the metadata factory used to gather the metadata of classes.
176
     *
177
     * @return ClassMetadataFactory
178
     */
179 812
    public function getMetadataFactory()
180
    {
181 812
        return $this->metadataFactory;
182
    }
183
184
    /**
185
     * {@inheritDoc}
186
     */
187 17
    public function getExpressionBuilder()
188
    {
189 17
        if ($this->expressionBuilder === null) {
190 17
            $this->expressionBuilder = new Query\Expr();
191
        }
192
193 17
        return $this->expressionBuilder;
194
    }
195
196 1094
    public function getIdentifierFlattener() : IdentifierFlattener
197
    {
198 1094
        return $this->identifierFlattener;
199
    }
200
201
    /**
202
     * {@inheritDoc}
203
     */
204 1
    public function beginTransaction()
205
    {
206 1
        $this->conn->beginTransaction();
207 1
    }
208
209
    /**
210
     * {@inheritDoc}
211
     */
212 212
    public function getCache()
213
    {
214 212
        return $this->cache;
215
    }
216
217
    /**
218
     * {@inheritDoc}
219
     */
220 6
    public function transactional(callable $func)
221
    {
222 6
        $this->conn->beginTransaction();
223
224
        try {
225 6
            $return = $func($this);
226
227 5
            $this->flush();
228 5
            $this->conn->commit();
229
230 5
            return $return;
231 1
        } catch (\Throwable $e) {
232 1
            $this->close();
233 1
            $this->conn->rollBack();
234
235 1
            throw $e;
236
        }
237
    }
238
239
    /**
240
     * {@inheritDoc}
241
     */
242 1
    public function commit()
243
    {
244 1
        $this->conn->commit();
245 1
    }
246
247
    /**
248
     * {@inheritDoc}
249
     */
250
    public function rollback()
251
    {
252
        $this->conn->rollBack();
253
    }
254
255
    /**
256
     * Returns the ORM metadata descriptor for a class.
257
     *
258
     * The class name must be the fully-qualified class name without a leading backslash
259
     * (as it is returned by get_class($obj)) or an aliased class name.
260
     *
261
     * Examples:
262
     * MyProject\Domain\User
263
     * sales:PriceRequest
264
     *
265
     * {@internal Performance-sensitive method. }}
266
     *
267
     * @param string $className
268
     *
269
     * @throws \ReflectionException
270
     * @throws \InvalidArgumentException
271
     * @throws MappingException
272
     */
273 1894
    public function getClassMetadata($className) : Mapping\ClassMetadata
274
    {
275 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...
276
    }
277
278
    /**
279
     * {@inheritDoc}
280
     */
281 954
    public function createQuery($dql = '')
282
    {
283 954
        $query = new Query($this);
284
285 954
        if (! empty($dql)) {
286 949
            $query->setDQL($dql);
287
        }
288
289 954
        return $query;
290
    }
291
292
    /**
293
     * {@inheritDoc}
294
     */
295 13
    public function createNativeQuery($sql, ResultSetMapping $rsm)
296
    {
297 13
        $query = new NativeQuery($this);
298
299 13
        $query->setSQL($sql);
300 13
        $query->setResultSetMapping($rsm);
301
302 13
        return $query;
303
    }
304
305
    /**
306
     * {@inheritDoc}
307
     */
308 128
    public function createQueryBuilder()
309
    {
310 128
        return new QueryBuilder($this);
311
    }
312
313
    /**
314
     * {@inheritDoc}
315
     *
316
     * @deprecated
317
     */
318
    public function merge($object)
319
    {
320
        throw new \BadMethodCallException('@TODO method disabled - will be removed in 3.0 with a release of doctrine/common');
321
    }
322
323
    /**
324
     * {@inheritDoc}
325
     *
326
     * @deprecated
327
     */
328
    public function detach($object)
329
    {
330
        throw new \BadMethodCallException('@TODO method disabled - will be removed in 3.0 with a release of doctrine/common');
331
    }
332
333
    /**
334
     * Flushes all changes to objects that have been queued up to now to the database.
335
     * This effectively synchronizes the in-memory state of managed objects with the
336
     * database.
337
     *
338
     * If an entity is explicitly passed to this method only this entity and
339
     * the cascade-persist semantics + scheduled inserts/removals are synchronized.
340
     *
341
     * @throws OptimisticLockException If a version check on an entity that
342
     *         makes use of optimistic locking fails.
343
     * @throws ORMException
344
     */
345 1005
    public function flush()
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($entityName, $id, $lockMode = null, $lockVersion = null)
371
    {
372 403
        $class     = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
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);
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 also could return the type true which is incompatible with the documented return type object|null.
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($entityName, $id)
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 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...
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;
524
    }
525
526
    /**
527
     * {@inheritDoc}
528
     */
529 4
    public function getPartialReference($entityName, $id)
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 also could return the type true which is incompatible with the return type mandated by Doctrine\ORM\EntityManag...::getPartialReference() of object.
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 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...
589
     *
590
     */
591 1197
    public function clear($entityName = null)
592
    {
593 1197
        $this->unitOfWork->clear();
594
595 1197
        $this->unitOfWork = new UnitOfWork($this);
596
597 1197
        if ($this->eventManager->hasListeners(Events::onClear)) {
598 9
            $this->eventManager->dispatchEvent(Events::onClear, new Event\OnClearEventArgs($this));
599
        }
600 1197
    }
601
602
    /**
603
     * {@inheritDoc}
604
     */
605 18
    public function close()
606
    {
607 18
        $this->clear();
608
609 18
        $this->closed = true;
610 18
    }
611
612
    /**
613
     * Tells the EntityManager to make an instance managed and persistent.
614
     *
615
     * The entity will be entered into the database at or before transaction
616
     * commit or as a result of the flush operation.
617
     *
618
     * NOTE: The persist operation always considers entities that are not yet known to
619
     * this EntityManager as NEW. Do not pass detached entities to the persist operation.
620
     *
621
     * @param object $entity The instance to make managed and persistent.
622
     *
623
     * @throws ORMInvalidArgumentException
624
     * @throws ORMException
625
     */
626 999
    public function persist($entity)
627
    {
628 999
        if (! is_object($entity)) {
629 1
            throw ORMInvalidArgumentException::invalidObject('EntityManager#persist()', $entity);
630
        }
631
632 998
        $this->errorIfClosed();
633
634 997
        $this->unitOfWork->persist($entity);
635 996
    }
636
637
    /**
638
     * Removes an entity instance.
639
     *
640
     * A removed entity will be removed from the database at or before transaction commit
641
     * or as a result of the flush operation.
642
     *
643
     * @param object $entity The entity instance to remove.
644
     *
645
     * @throws ORMInvalidArgumentException
646
     * @throws ORMException
647
     */
648 49
    public function remove($entity)
649
    {
650 49
        if (! is_object($entity)) {
651 1
            throw ORMInvalidArgumentException::invalidObject('EntityManager#remove()', $entity);
652
        }
653
654 48
        $this->errorIfClosed();
655
656 47
        $this->unitOfWork->remove($entity);
657 47
    }
658
659
    /**
660
     * Refreshes the persistent state of an entity from the database,
661
     * overriding any local changes that have not yet been persisted.
662
     *
663
     * @param object $entity The entity to refresh.
664
     *
665
     * @throws ORMInvalidArgumentException
666
     * @throws ORMException
667
     */
668 17
    public function refresh($entity)
669
    {
670 17
        if (! is_object($entity)) {
671 1
            throw ORMInvalidArgumentException::invalidObject('EntityManager#refresh()', $entity);
672
        }
673
674 16
        $this->errorIfClosed();
675
676 15
        $this->unitOfWork->refresh($entity);
677 15
    }
678
679
    /**
680
     * {@inheritDoc}
681
     */
682 9
    public function lock($entity, $lockMode, $lockVersion = null)
683
    {
684 9
        $this->unitOfWork->lock($entity, $lockMode, $lockVersion);
685 2
    }
686
687
    /**
688
     * Gets the repository for an entity class.
689
     *
690
     * @param string $entityName The name of the entity.
691
     *
692
     * @return ObjectRepository|EntityRepository The repository class.
693
     */
694 137
    public function getRepository($entityName)
695
    {
696 137
        return $this->repositoryFactory->getRepository($this, $entityName);
697
    }
698
699
    /**
700
     * Determines whether an entity instance is managed in this EntityManager.
701
     *
702
     * @param object $entity
703
     *
704
     * @return bool TRUE if this EntityManager currently manages the given entity, FALSE otherwise.
705
     */
706 15
    public function contains($entity)
707
    {
708 15
        return $this->unitOfWork->isScheduledForInsert($entity)
709 15
            || ($this->unitOfWork->isInIdentityMap($entity) && ! $this->unitOfWork->isScheduledForDelete($entity));
710
    }
711
712
    /**
713
     * {@inheritDoc}
714
     */
715 2247
    public function getEventManager()
716
    {
717 2247
        return $this->eventManager;
718
    }
719
720
    /**
721
     * {@inheritDoc}
722
     */
723 2247
    public function getConfiguration()
724
    {
725 2247
        return $this->config;
726
    }
727
728
    /**
729
     * Throws an exception if the EntityManager is closed or currently not active.
730
     *
731
     * @throws ORMException If the EntityManager is closed.
732
     */
733 1010
    private function errorIfClosed()
734
    {
735 1010
        if ($this->closed) {
736 4
            throw ORMException::entityManagerClosed();
737
        }
738 1006
    }
739
740
    /**
741
     * {@inheritDoc}
742
     */
743 2
    public function isOpen()
744
    {
745 2
        return ! $this->closed;
746
    }
747
748
    /**
749
     * {@inheritDoc}
750
     */
751 1350
    public function getUnitOfWork()
752
    {
753 1350
        return $this->unitOfWork;
754
    }
755
756
    /**
757
     * {@inheritDoc}
758
     */
759
    public function getHydrator($hydrationMode)
760
    {
761
        return $this->newHydrator($hydrationMode);
762
    }
763
764
    /**
765
     * {@inheritDoc}
766
     */
767 883
    public function newHydrator($hydrationMode)
768
    {
769 883
        switch ($hydrationMode) {
770
            case Query::HYDRATE_OBJECT:
771 614
                return new Internal\Hydration\ObjectHydrator($this);
772
773
            case Query::HYDRATE_ARRAY:
774 45
                return new Internal\Hydration\ArrayHydrator($this);
775
776
            case Query::HYDRATE_SCALAR:
777 85
                return new Internal\Hydration\ScalarHydrator($this);
778
779
            case Query::HYDRATE_SINGLE_SCALAR:
780 13
                return new Internal\Hydration\SingleScalarHydrator($this);
781
782
            case Query::HYDRATE_SIMPLEOBJECT:
783 407
                return new Internal\Hydration\SimpleObjectHydrator($this);
784
785
            default:
786 1
                $class = $this->config->getCustomHydrationMode($hydrationMode);
787 1
                if ($class !== null) {
788 1
                    return new $class($this);
789
                }
790
        }
791
792
        throw ORMException::invalidHydrationMode($hydrationMode);
793
    }
794
795
    /**
796
     * {@inheritDoc}
797
     */
798 166
    public function getProxyFactory()
799
    {
800 166
        return $this->proxyFactory;
801
    }
802
803
    /**
804
     * {@inheritDoc}
805
     */
806
    public function initializeObject($obj)
807
    {
808
        $this->unitOfWork->initializeObject($obj);
809
    }
810
811
    /**
812
     * Factory method to create EntityManager instances.
813
     *
814
     * @param Connection|mixed[] $connection   An array with the connection parameters or an existing Connection instance.
815
     * @param Configuration      $config       The Configuration instance to use.
816
     * @param EventManager       $eventManager The EventManager instance to use.
817
     *
818
     * @return EntityManager The created EntityManager.
819
     *
820
     * @throws \InvalidArgumentException
821
     * @throws ORMException
822
     */
823 2247
    public static function create($connection, Configuration $config, ?EventManager $eventManager = null)
824
    {
825 2247
        if (! $config->getMetadataDriverImpl()) {
826
            throw ORMException::missingMappingDriverImpl();
827
        }
828
829 2247
        $connection = static::createConnection($connection, $config, $eventManager);
830
831 2247
        $metadataFactoryClassName = $config->getClassMetadataFactoryName();
832 2247
        $metadataFactory          = new $metadataFactoryClassName();
833
834 2247
        return new EntityManager($connection, $config, $connection->getEventManager(), $metadataFactory);
835
    }
836
837
    public static function createWithClassMetadataFactory(Connection $conn, Configuration $config, EventManager $eventManager, ClassMetadataFactory $classMetadataFactory)
838
    {
839
        return new self($conn, $config, $eventManager, $classMetadataFactory);
840
    }
841
842
    /**
843
     * Factory method to create Connection instances.
844
     *
845
     * @param Connection|mixed[] $connection   An array with the connection parameters or an existing Connection instance.
846
     * @param Configuration      $config       The Configuration instance to use.
847
     * @param EventManager       $eventManager The EventManager instance to use.
848
     *
849
     * @return Connection
850
     *
851
     * @throws \InvalidArgumentException
852
     * @throws ORMException
853
     */
854 2247
    protected static function createConnection($connection, Configuration $config, ?EventManager $eventManager = null)
855
    {
856 2247
        if (is_array($connection)) {
857
            return DriverManager::getConnection($connection, $config, $eventManager ?: new EventManager());
858
        }
859
860 2247
        if (! $connection instanceof Connection) {
0 ignored issues
show
introduced by
$connection is always a sub-type of Doctrine\DBAL\Connection.
Loading history...
861 1
            throw new \InvalidArgumentException(
862 1
                sprintf(
863 1
                    'Invalid $connection argument of type %s given%s.',
864 1
                    is_object($connection) ? get_class($connection) : gettype($connection),
865 1
                    is_object($connection) ? '' : ': "' . $connection . '"'
866
                )
867
            );
868
        }
869
870 2247
        if ($eventManager !== null && $connection->getEventManager() !== $eventManager) {
871
            throw ORMException::mismatchedEventManager();
872
        }
873
874 2247
        return $connection;
875
    }
876
877
    /**
878
     * {@inheritDoc}
879
     */
880 588
    public function getFilters()
881
    {
882 588
        if ($this->filterCollection === null) {
883 588
            $this->filterCollection = new FilterCollection($this);
884
        }
885
886 588
        return $this->filterCollection;
887
    }
888
889
    /**
890
     * {@inheritDoc}
891
     */
892 40
    public function isFiltersStateClean()
893
    {
894 40
        return $this->filterCollection === null || $this->filterCollection->isClean();
895
    }
896
897
    /**
898
     * {@inheritDoc}
899
     */
900 765
    public function hasFilters()
901
    {
902 765
        return $this->filterCollection !== null;
903
    }
904
}
905