Passed
Pull Request — develop (#6794)
by Claudio
64:40
created

EntityManager::getMetadataFactory()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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

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

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

Loading history...
396 410
            if ($class->isIdentifierComposite()) {
397
                throw ORMInvalidArgumentException::invalidCompositeIdentifier();
398
            }
399
400
            $id = [$class->identifier[0] => $id];
401 409
        }
402
403 409 View Code Duplication
        foreach ($id as $i => $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
404 409
            if (is_object($value) && $this->metadataFactory->hasMetadataFor(StaticClassNameConverter::getClass($value))) {
405 1
                $id[$i] = $this->unitOfWork->getSingleIdentifierValue($value);
406
407
                if ($id[$i] === null) {
408 408
                    throw ORMInvalidArgumentException::invalidIdentifierBindingEntity();
409 408
                }
410
            }
411
        }
412 408
413 1
        $sortedId = [];
414
415 View Code Duplication
        foreach ($class->identifier as $identifier) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
416 407
            if ( ! isset($id[$identifier])) {
417
                throw ORMException::missingIdentifierField($className, $identifier);
418
            }
419 407
420 41
            $sortedId[$identifier] = $id[$identifier];
421 1
            unset($id[$identifier]);
422
        }
423
424
        if ($id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
425 40
            throw ORMException::unrecognizedIdentifierFields($className, array_keys($id));
426 1
        }
427
428
        $unitOfWork = $this->getUnitOfWork();
429 40
430 40
        // Check identity map first
431 40
        if (($entity = $unitOfWork->tryGetById($sortedId, $class->getRootClassName())) !== false) {
432
            if ( ! ($entity instanceof $className)) {
433
                return null;
434
            }
435
436
            switch (true) {
437 40
                case LockMode::OPTIMISTIC === $lockMode:
438
                    $this->lock($entity, $lockMode, $lockVersion);
439
                    break;
440 392
441
                case LockMode::NONE === $lockMode:
442
                case LockMode::PESSIMISTIC_READ === $lockMode:
443 392
                case LockMode::PESSIMISTIC_WRITE === $lockMode:
444 1
                    $persister = $unitOfWork->getEntityPersister($className);
445 1
                    $persister->refresh($sortedId, $entity, $lockMode);
446
                    break;
447
            }
448
449
            return $entity; // Hit!
450
        }
451
452
        $persister = $unitOfWork->getEntityPersister($className);
453
454 391
        switch (true) {
455 390
            case LockMode::OPTIMISTIC === $lockMode:
456 2
                if ( ! $class->isVersioned()) {
457 2
                    throw OptimisticLockException::notVersioned($className);
458
                }
459
460
                $entity = $persister->load($sortedId);
461
462
                $unitOfWork->lock($entity, $lockMode, $lockVersion);
0 ignored issues
show
Bug introduced by
It seems like $entity defined by $persister->load($sortedId) on line 460 can also be of type null; however, Doctrine\ORM\UnitOfWork::lock() does only seem to accept object, maybe add an additional type check?

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

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

    return array();
}

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

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

Loading history...
463 389
464
                return $entity;
465
466
            case LockMode::PESSIMISTIC_READ === $lockMode:
467
            case LockMode::PESSIMISTIC_WRITE === $lockMode:
468
                if ( ! $this->getConnection()->isTransactionActive()) {
469
                    throw TransactionRequiredException::transactionRequired();
470 91
                }
471
472 91
                return $persister->load($sortedId, null, null, [], $lockMode);
473
474 91
            default:
475 49
                return $persister->loadById($sortedId);
476
        }
477
    }
478 91
479
    /**
480 91
     * {@inheritDoc}
481 91
     */
482
    public function getReference($entityName, $id)
483
    {
484
        $class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
485 91
        $className = $class->getClassName();
486 91
487 View Code Duplication
        if ( ! is_array($id)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
488
            if ($class->isIdentifierComposite()) {
489 91
                throw ORMInvalidArgumentException::invalidCompositeIdentifier();
490 1
            }
491
492
            $id = [$class->identifier[0] => $id];
493
        }
494 90
495 27
        $scalarId = [];
496
497
        foreach ($id as $i => $value) {
498 86
            $scalarId[$i] = $value;
499 2
500
            if (is_object($value) && $this->metadataFactory->hasMetadataFor(StaticClassNameConverter::getClass($value))) {
501
                $scalarId[$i] = $this->unitOfWork->getSingleIdentifierValue($value);
502 86
503
                if ($scalarId[$i] === null) {
504 86
                    throw ORMInvalidArgumentException::invalidIdentifierBindingEntity();
505
                }
506 86
            }
507
        }
508
509
        $sortedId = [];
510
511 View Code Duplication
        foreach ($class->identifier as $identifier) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
512 4
            if ( ! isset($scalarId[$identifier])) {
513
                throw ORMException::missingIdentifierField($className, $identifier);
514 4
            }
515
516
            $sortedId[$identifier] = $scalarId[$identifier];
517 4
            unset($scalarId[$identifier]);
518 1
        }
519
520
        if ($scalarId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $scalarId of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
521 3
            throw ORMException::unrecognizedIdentifierFields($className, array_keys($scalarId));
522 3
        }
523
524
        // Check identity map first, if its already in there just return it.
525 3 View Code Duplication
        if (($entity = $this->unitOfWork->tryGetById($sortedId, $class->getRootClassName())) !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
526
            return ($entity instanceof $className) ? $entity : null;
527 3
        }
528
529 3
        if ($class->getSubClasses()) {
530 3
            return $this->find($entityName, $sortedId);
531
        }
532 3
533
        $entity = $this->proxyFactory->getProxy($class, $id);
534
535
        $this->unitOfWork->registerManaged($entity, $sortedId, []);
536
537
        if ($entity instanceof EntityManagerAware) {
538
            $entity->injectEntityManager($this, $class);
539
        }
540
541
        return $entity;
542
    }
543 1217
544
    /**
545 1217
     * {@inheritDoc}
546 1217
     */
547
    public function getPartialReference($entityName, $id)
548
    {
549
        $class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
550
        $className = $class->getClassName();
551 19
552 View Code Duplication
        if ( ! is_array($id)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
553 19
            if ($class->isIdentifierComposite()) {
554
                throw ORMInvalidArgumentException::invalidCompositeIdentifier();
555 19
            }
556 19
557
            $id = [$class->identifier[0] => $id];
558
        }
559
560 View Code Duplication
        foreach ($id as $i => $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
561
            if (is_object($value) && $this->metadataFactory->hasMetadataFor(StaticClassNameConverter::getClass($value))) {
562
                $id[$i] = $this->unitOfWork->getSingleIdentifierValue($value);
563
564
                if ($id[$i] === null) {
565
                    throw ORMInvalidArgumentException::invalidIdentifierBindingEntity();
566
                }
567
            }
568
        }
569
570
        $sortedId = [];
571
572 View Code Duplication
        foreach ($class->identifier as $identifier) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
573
            if ( ! isset($id[$identifier])) {
574 1006
                throw ORMException::missingIdentifierField($className, $identifier);
575
            }
576 1006
577 1
            $sortedId[$identifier] = $id[$identifier];
578
            unset($id[$identifier]);
579
        }
580 1005
581
        if ($id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
582 1004
            throw ORMException::unrecognizedIdentifierFields($className, array_keys($id));
583 1003
        }
584
585
        // Check identity map first, if its already in there just return it.
586 View Code Duplication
        if (($entity = $this->unitOfWork->tryGetById($sortedId, $class->getRootClassName())) !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
587
            return ($entity instanceof $className) ? $entity : null;
588
        }
589
590
        $persister = $this->unitOfWork->getEntityPersister($class->getClassName());
591
        $entity    = $this->unitOfWork->newInstance($class);
592
593
        $persister->setIdentifier($entity, $sortedId);
594
595
        $this->unitOfWork->registerManaged($entity, $sortedId, []);
596
        $this->unitOfWork->markReadOnly($entity);
597
598 50
        return $entity;
599
    }
600 50
601 1
    /**
602
     * Clears the EntityManager. All entities that are currently managed
603
     * by this EntityManager become detached.
604 49
     *
605
     * @param null $entityName Unused. @todo Remove from ObjectManager.
606 48
     *
607 48
     * @return void
608
     */
609
    public function clear($entityName = null)
610
    {
611
        $this->unitOfWork->clear();
612
    }
613
614
    /**
615
     * {@inheritDoc}
616
     */
617
    public function close()
618
    {
619
        $this->clear();
620 18
621
        $this->closed = true;
622 18
    }
623 1
624
    /**
625
     * Tells the EntityManager to make an instance managed and persistent.
626 17
     *
627
     * The entity will be entered into the database at or before transaction
628 16
     * commit or as a result of the flush operation.
629 16
     *
630
     * NOTE: The persist operation always considers entities that are not yet known to
631
     * this EntityManager as NEW. Do not pass detached entities to the persist operation.
632
     *
633
     * @param object $entity The instance to make managed and persistent.
634
     *
635
     * @return void
636
     *
637
     * @throws ORMInvalidArgumentException
638
     * @throws ORMException
639
     */
640 View Code Duplication
    public function persist($entity)
641
    {
642
        if ( ! is_object($entity)) {
643
            throw ORMInvalidArgumentException::invalidObject('EntityManager#persist()', $entity);
644 13
        }
645
646 13
        $this->errorIfClosed();
647 1
648
        $this->unitOfWork->persist($entity);
649
    }
650 12
651 12
    /**
652
     * Removes an entity instance.
653
     *
654
     * A removed entity will be removed from the database at or before transaction commit
655
     * or as a result of the flush operation.
656
     *
657
     * @param object $entity The entity instance to remove.
658
     *
659
     * @return void
660
     *
661
     * @throws ORMInvalidArgumentException
662
     * @throws ORMException
663
     */
664 View Code Duplication
    public function remove($entity)
665 42
    {
666
        if ( ! is_object($entity)) {
667 42
            throw ORMInvalidArgumentException::invalidObject('EntityManager#remove()', $entity);
668 1
        }
669
670
        $this->errorIfClosed();
671 41
672
        $this->unitOfWork->remove($entity);
673 40
    }
674
675
    /**
676
     * Refreshes the persistent state of an entity from the database,
677
     * overriding any local changes that have not yet been persisted.
678
     *
679
     * @param object $entity The entity to refresh.
680
     *
681
     * @return void
682
     *
683
     * @throws ORMInvalidArgumentException
684
     * @throws ORMException
685
     */
686 View Code Duplication
    public function refresh($entity)
687
    {
688
        if ( ! is_object($entity)) {
689
            throw ORMInvalidArgumentException::invalidObject('EntityManager#refresh()', $entity);
690 10
        }
691
692 10
        $this->errorIfClosed();
693 3
694
        $this->unitOfWork->refresh($entity);
695
    }
696
697
    /**
698
     * {@inheritDoc}
699
     */
700
    public function lock($entity, $lockMode, $lockVersion = null)
701
    {
702 142
        $this->unitOfWork->lock($entity, $lockMode, $lockVersion);
703
    }
704 142
705
    /**
706
     * Gets the repository for an entity class.
707
     *
708
     * @param string $entityName The name of the entity.
709
     *
710
     * @return \Doctrine\ORM\EntityRepository The repository class.
711
     */
712
    public function getRepository($entityName)
713
    {
714 22
        return $this->repositoryFactory->getRepository($this, $entityName);
715
    }
716 22
717 20
    /**
718 22
     * Determines whether an entity instance is managed in this EntityManager.
719
     *
720
     * @param object $entity
721
     *
722
     * @return boolean TRUE if this EntityManager currently manages the given entity, FALSE otherwise.
723
     */
724 2290
    public function contains($entity)
725
    {
726 2290
        return $this->unitOfWork->isScheduledForInsert($entity)
727
            || ($this->unitOfWork->isInIdentityMap($entity) && !$this->unitOfWork->isScheduledForDelete($entity));
728
    }
729
730
    /**
731
     * {@inheritDoc}
732 2290
     */
733
    public function getEventManager()
734 2290
    {
735
        return $this->eventManager;
736
    }
737
738
    /**
739
     * {@inheritDoc}
740
     */
741
    public function getConfiguration()
742
    {
743
        return $this->config;
744 1025
    }
745
746 1025
    /**
747 5
     * Throws an exception if the EntityManager is closed or currently not active.
748
     *
749 1020
     * @return void
750
     *
751
     * @throws ORMException If the EntityManager is closed.
752
     */
753
    private function errorIfClosed()
754 1
    {
755
        if ($this->closed) {
756 1
            throw ORMException::entityManagerClosed();
757
        }
758
    }
759
760
    /**
761
     * {@inheritDoc}
762 2290
     */
763
    public function isOpen()
764 2290
    {
765
        return (!$this->closed);
766
    }
767
768
    /**
769
     * {@inheritDoc}
770
     */
771
    public function getUnitOfWork()
772
    {
773
        return $this->unitOfWork;
774
    }
775
776
    /**
777
     * {@inheritDoc}
778 879
     */
779
    public function getHydrator($hydrationMode)
780
    {
781 879
        return $this->newHydrator($hydrationMode);
782 611
    }
783
784 535
    /**
785 34
     * {@inheritDoc}
786
     */
787 506
    public function newHydrator($hydrationMode)
788 85
    {
789
        switch ($hydrationMode) {
790 423
            case Query::HYDRATE_OBJECT:
791 12
                return new Internal\Hydration\ObjectHydrator($this);
792
793 415
            case Query::HYDRATE_ARRAY:
794 414
                return new Internal\Hydration\ArrayHydrator($this);
795
796
            case Query::HYDRATE_SCALAR:
797 1
                return new Internal\Hydration\ScalarHydrator($this);
798 1
799
            case Query::HYDRATE_SINGLE_SCALAR:
800
                return new Internal\Hydration\SingleScalarHydrator($this);
801
802
            case Query::HYDRATE_SIMPLEOBJECT:
803
                return new Internal\Hydration\SimpleObjectHydrator($this);
804
805
            default:
806
                if (($class = $this->config->getCustomHydrationMode($hydrationMode)) !== null) {
807
                    return new $class($this);
808 166
                }
809
        }
810 166
811
        throw ORMException::invalidHydrationMode($hydrationMode);
812
    }
813
814
    /**
815
     * {@inheritDoc}
816
     */
817
    public function getProxyFactory()
818
    {
819
        return $this->proxyFactory;
820
    }
821
822
    /**
823
     * {@inheritDoc}
824
     */
825
    public function initializeObject($obj)
826
    {
827
        $this->unitOfWork->initializeObject($obj);
828
    }
829
830
    /**
831
     * Factory method to create EntityManager instances.
832
     *
833 1229
     * @param array|Connection $connection   An array with the connection parameters or an existing Connection instance.
834
     * @param Configuration    $config       The Configuration instance to use.
835 1229
     * @param EventManager     $eventManager The EventManager instance to use.
836
     *
837
     * @return EntityManager The created EntityManager.
838
     *
839 1229
     * @throws \InvalidArgumentException
840
     * @throws ORMException
841 1229
     */
842
    public static function create($connection, Configuration $config, EventManager $eventManager = null)
843
    {
844
        if ( ! $config->getMetadataDriverImpl()) {
845
            throw ORMException::missingMappingDriverImpl();
846
        }
847
848
        $connection = static::createConnection($connection, $config, $eventManager);
849
850
        return new EntityManager($connection, $config, $connection->getEventManager());
851
    }
852
853
    /**
854
     * Factory method to create Connection instances.
855
     *
856 1229
     * @param array|Connection $connection   An array with the connection parameters or an existing Connection instance.
857
     * @param Configuration    $config       The Configuration instance to use.
858 1229
     * @param EventManager     $eventManager The EventManager instance to use.
859
     *
860
     * @return Connection
861
     *
862 1229
     * @throws \InvalidArgumentException
863
     * @throws ORMException
864
     */
865
    protected static function createConnection($connection, Configuration $config, EventManager $eventManager = null)
866 1229
    {
867
        if (is_array($connection)) {
868
            return DriverManager::getConnection($connection, $config, $eventManager ?: new EventManager());
869
        }
870 1229
871
        if ( ! $connection instanceof Connection) {
872
            throw new \InvalidArgumentException(
873
                sprintf(
874
                    'Invalid $connection argument of type %s given%s.',
875
                    is_object($connection) ? get_class($connection) : gettype($connection),
876 605
                    is_object($connection) ? '' : ': "' . $connection . '"'
877
                )
878 605
            );
879 605
        }
880
881
        if ($eventManager !== null && $connection->getEventManager() !== $eventManager) {
882 605
            throw ORMException::mismatchedEventManager();
883
        }
884
885
        return $connection;
886
    }
887
888 36
    /**
889
     * {@inheritDoc}
890 36
     */
891
    public function getFilters()
892
    {
893
        if (null === $this->filterCollection) {
894
            $this->filterCollection = new FilterCollection($this);
895
        }
896 734
897
        return $this->filterCollection;
898 734
    }
899
900
    /**
901
     * {@inheritDoc}
902
     */
903
    public function isFiltersStateClean()
904
    {
905
        return null === $this->filterCollection || $this->filterCollection->isClean();
906
    }
907
908
    /**
909
     * {@inheritDoc}
910
     */
911
    public function hasFilters()
912
    {
913
        return null !== $this->filterCollection;
914
    }
915
}
916