Failed Conditions
Pull Request — 2.7 (#7556)
by Luís
28:50 queued 22:17
created

EntityManager::getHydrator()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ORM;
21
22
use Doctrine\Common\EventManager;
23
use Doctrine\DBAL\Connection;
24
use Doctrine\DBAL\DriverManager;
25
use Doctrine\DBAL\LockMode;
26
use Doctrine\ORM\Mapping\ClassMetadata;
27
use Doctrine\ORM\Query\ResultSetMapping;
28
use Doctrine\ORM\Proxy\ProxyFactory;
29
use Doctrine\ORM\Query\FilterCollection;
30
use Doctrine\Common\Util\ClassUtils;
31
use Throwable;
32
use function trigger_error;
33
34
/**
35
 * The EntityManager is the central access point to ORM functionality.
36
 *
37
 * It is a facade to all different ORM subsystems such as UnitOfWork,
38
 * Query Language and Repository API. Instantiation is done through
39
 * the static create() method. The quickest way to obtain a fully
40
 * configured EntityManager is:
41
 *
42
 *     use Doctrine\ORM\Tools\Setup;
43
 *     use Doctrine\ORM\EntityManager;
44
 *
45
 *     $paths = array('/path/to/entity/mapping/files');
46
 *
47
 *     $config = Setup::createAnnotationMetadataConfiguration($paths);
48
 *     $dbParams = array('driver' => 'pdo_sqlite', 'memory' => true);
49
 *     $entityManager = EntityManager::create($dbParams, $config);
50
 *
51
 * For more information see
52
 * {@link http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/configuration.html}
53
 *
54
 * You should never attempt to inherit from the EntityManager: Inheritance
55
 * is not a valid extension point for the EntityManager. Instead you
56
 * should take a look at the {@see \Doctrine\ORM\Decorator\EntityManagerDecorator}
57
 * and wrap your entity manager in a decorator.
58
 *
59
 * @since   2.0
60
 * @author  Benjamin Eberlei <[email protected]>
61
 * @author  Guilherme Blanco <[email protected]>
62
 * @author  Jonathan Wage <[email protected]>
63
 * @author  Roman Borschel <[email protected]>
64
 */
65
/* final */class EntityManager implements EntityManagerInterface
66
{
67
    /**
68
     * The used Configuration.
69
     *
70
     * @var \Doctrine\ORM\Configuration
71
     */
72
    private $config;
73
74
    /**
75
     * The database connection used by the EntityManager.
76
     *
77
     * @var \Doctrine\DBAL\Connection
78
     */
79
    private $conn;
80
81
    /**
82
     * The metadata factory, used to retrieve the ORM metadata of entity classes.
83
     *
84
     * @var \Doctrine\ORM\Mapping\ClassMetadataFactory
85
     */
86
    private $metadataFactory;
87
88
    /**
89
     * The UnitOfWork used to coordinate object-level transactions.
90
     *
91
     * @var \Doctrine\ORM\UnitOfWork
92
     */
93
    private $unitOfWork;
94
95
    /**
96
     * The event manager that is the central point of the event system.
97
     *
98
     * @var \Doctrine\Common\EventManager
99
     */
100
    private $eventManager;
101
102
    /**
103
     * The proxy factory used to create dynamic proxies.
104
     *
105
     * @var \Doctrine\ORM\Proxy\ProxyFactory
106
     */
107
    private $proxyFactory;
108
109
    /**
110
     * The repository factory used to create dynamic repositories.
111
     *
112
     * @var \Doctrine\ORM\Repository\RepositoryFactory
113
     */
114
    private $repositoryFactory;
115
116
    /**
117
     * The expression builder instance used to generate query expressions.
118
     *
119
     * @var \Doctrine\ORM\Query\Expr
120
     */
121
    private $expressionBuilder;
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 \Doctrine\ORM\Query\FilterCollection
134
     */
135
    private $filterCollection;
136
137
    /**
138
     * @var \Doctrine\ORM\Cache The second level cache regions API.
139
     */
140
    private $cache;
141
142
    /**
143
     * Creates a new EntityManager that operates on the given database connection
144
     * and uses the given Configuration and EventManager implementations.
145
     *
146
     * @param \Doctrine\DBAL\Connection     $conn
147
     * @param \Doctrine\ORM\Configuration   $config
148
     * @param \Doctrine\Common\EventManager $eventManager
149
     */
150 2499
    protected function __construct(Connection $conn, Configuration $config, EventManager $eventManager)
151
    {
152 2499
        $this->conn              = $conn;
153 2499
        $this->config            = $config;
154 2499
        $this->eventManager      = $eventManager;
155
156 2499
        $metadataFactoryClassName = $config->getClassMetadataFactoryName();
157
158 2499
        $this->metadataFactory = new $metadataFactoryClassName;
159 2499
        $this->metadataFactory->setEntityManager($this);
160 2499
        $this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl());
161
162 2499
        $this->repositoryFactory = $config->getRepositoryFactory();
163 2499
        $this->unitOfWork        = new UnitOfWork($this);
164 2499
        $this->proxyFactory      = new ProxyFactory(
0 ignored issues
show
Deprecated Code introduced by
The class Doctrine\ORM\Proxy\ProxyFactory has been deprecated: 3.0 This class is being removed from the ORM and won't have any replacement ( Ignorable by Annotation )

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

164
        $this->proxyFactory      = /** @scrutinizer ignore-deprecated */ new ProxyFactory(
Loading history...
165 2499
            $this,
166 2499
            $config->getProxyDir(),
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\ORM\Configuration::getProxyDir() has been deprecated: 3.0 We're switch to `ocramius/proxy-manager` and this method isn't applicable any longer ( Ignorable by Annotation )

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

166
            /** @scrutinizer ignore-deprecated */ $config->getProxyDir(),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
167 2499
            $config->getProxyNamespace(),
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\ORM\Configuration::getProxyNamespace() has been deprecated: 3.0 We're switch to `ocramius/proxy-manager` and this method isn't applicable any longer ( Ignorable by Annotation )

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

167
            /** @scrutinizer ignore-deprecated */ $config->getProxyNamespace(),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
168 2499
            $config->getAutoGenerateProxyClasses()
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\ORM\Configurati...oGenerateProxyClasses() has been deprecated: 3.0 We're switch to `ocramius/proxy-manager` and this method isn't applicable any longer ( Ignorable by Annotation )

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

168
            /** @scrutinizer ignore-deprecated */ $config->getAutoGenerateProxyClasses()

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
169
        );
170
171 2499
        if ($config->isSecondLevelCacheEnabled()) {
172 288
            $cacheConfig    = $config->getSecondLevelCacheConfiguration();
173 288
            $cacheFactory   = $cacheConfig->getCacheFactory();
174 288
            $this->cache    = $cacheFactory->createCache($this);
175
        }
176 2499
    }
177
178
    /**
179
     * {@inheritDoc}
180
     */
181 1965
    public function getConnection()
182
    {
183 1965
        return $this->conn;
184
    }
185
186
    /**
187
     * Gets the metadata factory used to gather the metadata of classes.
188
     *
189
     * @return \Doctrine\ORM\Mapping\ClassMetadataFactory
190
     */
191 2499
    public function getMetadataFactory()
192
    {
193 2499
        return $this->metadataFactory;
194
    }
195
196
    /**
197
     * {@inheritDoc}
198
     */
199 17
    public function getExpressionBuilder()
200
    {
201 17
        if ($this->expressionBuilder === null) {
202 17
            $this->expressionBuilder = new Query\Expr;
203
        }
204
205 17
        return $this->expressionBuilder;
206
    }
207
208
    /**
209
     * {@inheritDoc}
210
     */
211 1
    public function beginTransaction()
212
    {
213 1
        $this->conn->beginTransaction();
214 1
    }
215
216
    /**
217
     * {@inheritDoc}
218
     */
219 220
    public function getCache()
220
    {
221 220
        return $this->cache;
222
    }
223
224
    /**
225
     * {@inheritDoc}
226
     */
227 5
    public function transactional($func)
228
    {
229 5
        if (!is_callable($func)) {
230 1
            throw new \InvalidArgumentException('Expected argument of type "callable", got "' . gettype($func) . '"');
231
        }
232
233 4
        $this->conn->beginTransaction();
234
235
        try {
236 4
            $return = call_user_func($func, $this);
237
238 3
            $this->flush();
239 1
        } catch (Throwable $e) {
240 1
            $this->close();
241 1
            $this->conn->rollBack();
242
243 1
            throw $e;
244
        }
245
246
        try {
247 3
            $this->conn->commit();
248
249 3
            return $return ?: true;
250
        } catch (Throwable $e) {
251
            $this->close();
252
253
            throw $e;
254
        }
255
    }
256
257
    /**
258
     * {@inheritDoc}
259
     */
260 1
    public function commit()
261
    {
262 1
        $this->conn->commit();
263 1
    }
264
265
    /**
266
     * {@inheritDoc}
267
     */
268
    public function rollback()
269
    {
270
        $this->conn->rollBack();
271
    }
272
273
    /**
274
     * Returns the ORM metadata descriptor for a class.
275
     *
276
     * The class name must be the fully-qualified class name without a leading backslash
277
     * (as it is returned by get_class($obj)) or an aliased class name.
278
     *
279
     * Examples:
280
     * MyProject\Domain\User
281
     * sales:PriceRequest
282
     *
283
     * Internal note: Performance-sensitive method.
284
     *
285
     * @param string $className
286
     *
287
     * @return \Doctrine\ORM\Mapping\ClassMetadata
288
     */
289 2023
    public function getClassMetadata($className)
290
    {
291 2023
        return $this->metadataFactory->getMetadataFor($className);
292
    }
293
294
    /**
295
     * {@inheritDoc}
296
     */
297 983
    public function createQuery($dql = '')
298
    {
299 983
        $query = new Query($this);
300
301 983
        if ( ! empty($dql)) {
302 978
            $query->setDQL($dql);
303
        }
304
305 983
        return $query;
306
    }
307
308
    /**
309
     * {@inheritDoc}
310
     */
311 1
    public function createNamedQuery($name)
312
    {
313 1
        return $this->createQuery($this->config->getNamedQuery($name));
314
    }
315
316
    /**
317
     * {@inheritDoc}
318
     */
319 21
    public function createNativeQuery($sql, ResultSetMapping $rsm)
320
    {
321 21
        $query = new NativeQuery($this);
322
323 21
        $query->setSQL($sql);
324 21
        $query->setResultSetMapping($rsm);
325
326 21
        return $query;
327
    }
328
329
    /**
330
     * {@inheritDoc}
331
     */
332 1
    public function createNamedNativeQuery($name)
333
    {
334 1
        list($sql, $rsm) = $this->config->getNamedNativeQuery($name);
335
336 1
        return $this->createNativeQuery($sql, $rsm);
337
    }
338
339
    /**
340
     * {@inheritDoc}
341
     */
342 131
    public function createQueryBuilder()
343
    {
344 131
        return new QueryBuilder($this);
345
    }
346
347
    /**
348
     * Flushes all changes to objects that have been queued up to now to the database.
349
     * This effectively synchronizes the in-memory state of managed objects with the
350
     * database.
351
     *
352
     * If an entity is explicitly passed to this method only this entity and
353
     * the cascade-persist semantics + scheduled inserts/removals are synchronized.
354
     *
355
     * @param null|object|array $entity
356
     *
357
     * @return void
358
     *
359
     * @throws \Doctrine\ORM\OptimisticLockException If a version check on an entity that
360
     *         makes use of optimistic locking fails.
361
     * @throws ORMException
362
     */
363 1090
    public function flush($entity = null)
364
    {
365 1090
        if ($entity !== null) {
366 12
            @trigger_error(
367 12
                'Calling ' . __METHOD__ . '() with any arguments to flush specific entities is deprecated and will not be supported in Doctrine 3.0.',
368 12
                E_USER_DEPRECATED
369
            );
370
        }
371
372 1090
        $this->errorIfClosed();
373
374 1089
        $this->unitOfWork->commit($entity);
375 1078
    }
376
377
    /**
378
     * Finds an Entity by its identifier.
379
     *
380
     * @param string       $entityName  The class name of the entity to find.
381
     * @param mixed        $id          The identity of the entity to find.
382
     * @param integer|null $lockMode    One of the \Doctrine\DBAL\LockMode::* constants
383
     *                                  or NULL if no specific lock mode should be used
384
     *                                  during the search.
385
     * @param integer|null $lockVersion The version of the entity to find when using
386
     *                                  optimistic locking.
387
     *
388
     * @return object|null The entity instance or NULL if the entity can not be found.
389
     *
390
     * @throws OptimisticLockException
391
     * @throws ORMInvalidArgumentException
392
     * @throws TransactionRequiredException
393
     * @throws ORMException
394
     */
395 453
    public function find($entityName, $id, $lockMode = null, $lockVersion = null)
396
    {
397 453
        $class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
398
399 453
        if ($lockMode !== null) {
400 6
            $this->checkLockRequirements($lockMode, $class);
401
        }
402
403 450
        if ( ! is_array($id)) {
404 402
            if ($class->isIdentifierComposite) {
405
                throw ORMInvalidArgumentException::invalidCompositeIdentifier();
406
            }
407
408 402
            $id = [$class->identifier[0] => $id];
409
        }
410
411 450
        foreach ($id as $i => $value) {
412 450
            if (is_object($value) && $this->metadataFactory->hasMetadataFor(ClassUtils::getClass($value))) {
413 10
                $id[$i] = $this->unitOfWork->getSingleIdentifierValue($value);
414
415 10
                if ($id[$i] === null) {
416 450
                    throw ORMInvalidArgumentException::invalidIdentifierBindingEntity();
417
                }
418
            }
419
        }
420
421 449
        $sortedId = [];
422
423 449
        foreach ($class->identifier as $identifier) {
424 449
            if ( ! isset($id[$identifier])) {
425 1
                throw ORMException::missingIdentifierField($class->name, $identifier);
426
            }
427
428 448
            $sortedId[$identifier] = $id[$identifier];
429 448
            unset($id[$identifier]);
430
        }
431
432 448
        if ($id) {
433 1
            throw ORMException::unrecognizedIdentifierFields($class->name, array_keys($id));
434
        }
435
436 447
        $unitOfWork = $this->getUnitOfWork();
437
438
        // Check identity map first
439 447
        if (($entity = $unitOfWork->tryGetById($sortedId, $class->rootEntityName)) !== false) {
440 50
            if ( ! ($entity instanceof $class->name)) {
441 1
                return null;
442
            }
443
444
            switch (true) {
445 49
                case LockMode::OPTIMISTIC === $lockMode:
446
                    $this->lock($entity, $lockMode, $lockVersion);
447
                    break;
448
449 49
                case LockMode::NONE === $lockMode:
450 49
                case LockMode::PESSIMISTIC_READ === $lockMode:
451 49
                case LockMode::PESSIMISTIC_WRITE === $lockMode:
452
                    $persister = $unitOfWork->getEntityPersister($class->name);
453
                    $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

453
                    $persister->refresh($sortedId, /** @scrutinizer ignore-type */ $entity, $lockMode);
Loading history...
454
                    break;
455
            }
456
457 49
            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 null|object.
Loading history...
458
        }
459
460 425
        $persister = $unitOfWork->getEntityPersister($class->name);
461
462
        switch (true) {
463 425
            case LockMode::OPTIMISTIC === $lockMode:
464 1
                $entity = $persister->load($sortedId);
465
466 1
                $unitOfWork->lock($entity, $lockMode, $lockVersion);
467
468 1
                return $entity;
469
470 424
            case LockMode::PESSIMISTIC_READ === $lockMode:
471 424
            case LockMode::PESSIMISTIC_WRITE === $lockMode:
472
                return $persister->load($sortedId, null, null, [], $lockMode);
473
474
            default:
475 424
                return $persister->loadById($sortedId);
476
        }
477
    }
478
479
    /**
480
     * {@inheritDoc}
481
     */
482 95
    public function getReference($entityName, $id)
483
    {
484 95
        $class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
485
486 95
        if ( ! is_array($id)) {
487 50
            $id = [$class->identifier[0] => $id];
0 ignored issues
show
Bug introduced by
Accessing identifier on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
488
        }
489
490 95
        $sortedId = [];
491
492 95
        foreach ($class->identifier as $identifier) {
493 95
            if ( ! isset($id[$identifier])) {
494
                throw ORMException::missingIdentifierField($class->name, $identifier);
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
495
            }
496
497 95
            $sortedId[$identifier] = $id[$identifier];
498 95
            unset($id[$identifier]);
499
        }
500
501 95
        if ($id) {
502 1
            throw ORMException::unrecognizedIdentifierFields($class->name, array_keys($id));
503
        }
504
505
        // Check identity map first, if its already in there just return it.
506 94
        if (($entity = $this->unitOfWork->tryGetById($sortedId, $class->rootEntityName)) !== false) {
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
507 28
            return ($entity instanceof $class->name) ? $entity : null;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $entity instanceo...->name ? $entity : null also could return the type true which is incompatible with the return type mandated by Doctrine\ORM\EntityManag...terface::getReference() of null|object.
Loading history...
508
        }
509
510 89
        if ($class->subClasses) {
0 ignored issues
show
Bug introduced by
Accessing subClasses on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
511 2
            return $this->find($entityName, $sortedId);
512
        }
513
514 89
        $entity = $this->proxyFactory->getProxy($class->name, $sortedId);
515
516 89
        $this->unitOfWork->registerManaged($entity, $sortedId, []);
517
518 89
        return $entity;
519
    }
520
521
    /**
522
     * {@inheritDoc}
523
     */
524 4
    public function getPartialReference($entityName, $identifier)
525
    {
526 4
        $class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
527
528
        // Check identity map first, if its already in there just return it.
529 4
        if (($entity = $this->unitOfWork->tryGetById($identifier, $class->rootEntityName)) !== false) {
0 ignored issues
show
Bug introduced by
Accessing rootEntityName on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
530 1
            return ($entity instanceof $class->name) ? $entity : null;
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
Bug Best Practice introduced by
The expression return $entity instanceo...->name ? $entity : null also could return the type true which is incompatible with the return type mandated by Doctrine\ORM\EntityManag...::getPartialReference() of null|object.
Loading history...
531
        }
532
533 3
        if ( ! is_array($identifier)) {
534 3
            $identifier = [$class->identifier[0] => $identifier];
0 ignored issues
show
Bug introduced by
Accessing identifier on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
535
        }
536
537 3
        $entity = $class->newInstance();
538
539 3
        $class->setIdentifierValues($entity, $identifier);
540
541 3
        $this->unitOfWork->registerManaged($entity, $identifier, []);
542 3
        $this->unitOfWork->markReadOnly($entity);
543
544 3
        return $entity;
545
    }
546
547
    /**
548
     * Clears the EntityManager. All entities that are currently managed
549
     * by this EntityManager become detached.
550
     *
551
     * @param string|null $entityName if given, only entities of this type will get detached
552
     *
553
     * @return void
554
     *
555
     * @throws ORMInvalidArgumentException                           if a non-null non-string value is given
556
     * @throws \Doctrine\Common\Persistence\Mapping\MappingException if a $entityName is given, but that entity is not
557
     *                                                               found in the mappings
558
     */
559 1319
    public function clear($entityName = null)
560
    {
561 1319
        if (null !== $entityName && ! is_string($entityName)) {
0 ignored issues
show
introduced by
The condition is_string($entityName) is always true.
Loading history...
562 1
            throw ORMInvalidArgumentException::invalidEntityName($entityName);
563
        }
564
565 1318
        $this->unitOfWork->clear(
566 1318
            null === $entityName
567 1316
                ? null
568 1318
                : $this->metadataFactory->getMetadataFor($entityName)->getName()
569
        );
570 1317
    }
571
572
    /**
573
     * {@inheritDoc}
574
     */
575 20
    public function close()
576
    {
577 20
        $this->clear();
578
579 20
        $this->closed = true;
580 20
    }
581
582
    /**
583
     * Tells the EntityManager to make an instance managed and persistent.
584
     *
585
     * The entity will be entered into the database at or before transaction
586
     * commit or as a result of the flush operation.
587
     *
588
     * NOTE: The persist operation always considers entities that are not yet known to
589
     * this EntityManager as NEW. Do not pass detached entities to the persist operation.
590
     *
591
     * @param object $entity The instance to make managed and persistent.
592
     *
593
     * @return void
594
     *
595
     * @throws ORMInvalidArgumentException
596
     * @throws ORMException
597
     */
598 1089
    public function persist($entity)
599
    {
600 1089
        if ( ! is_object($entity)) {
601 1
            throw ORMInvalidArgumentException::invalidObject('EntityManager#persist()', $entity);
602
        }
603
604 1088
        $this->errorIfClosed();
605
606 1087
        $this->unitOfWork->persist($entity);
607 1086
    }
608
609
    /**
610
     * Removes an entity instance.
611
     *
612
     * A removed entity will be removed from the database at or before transaction commit
613
     * or as a result of the flush operation.
614
     *
615
     * @param object $entity The entity instance to remove.
616
     *
617
     * @return void
618
     *
619
     * @throws ORMInvalidArgumentException
620
     * @throws ORMException
621
     */
622 53
    public function remove($entity)
623
    {
624 53
        if ( ! is_object($entity)) {
625 1
            throw ORMInvalidArgumentException::invalidObject('EntityManager#remove()', $entity);
626
        }
627
628 52
        $this->errorIfClosed();
629
630 51
        $this->unitOfWork->remove($entity);
631 51
    }
632
633
    /**
634
     * Refreshes the persistent state of an entity from the database,
635
     * overriding any local changes that have not yet been persisted.
636
     *
637
     * @param object $entity The entity to refresh.
638
     *
639
     * @return void
640
     *
641
     * @throws ORMInvalidArgumentException
642
     * @throws ORMException
643
     */
644 19
    public function refresh($entity)
645
    {
646 19
        if ( ! is_object($entity)) {
647 1
            throw ORMInvalidArgumentException::invalidObject('EntityManager#refresh()', $entity);
648
        }
649
650 18
        $this->errorIfClosed();
651
652 17
        $this->unitOfWork->refresh($entity);
653 17
    }
654
655
    /**
656
     * Detaches an entity from the EntityManager, causing a managed entity to
657
     * become detached.  Unflushed changes made to the entity if any
658
     * (including removal of the entity), will not be synchronized to the database.
659
     * Entities which previously referenced the detached entity will continue to
660
     * reference it.
661
     *
662
     * @param object $entity The entity to detach.
663
     *
664
     * @return void
665
     *
666
     * @throws ORMInvalidArgumentException
667
     *
668
     * @deprecated 3.0 This method is being removed from the ORM and won't have any replacement
669
     */
670 10
    public function detach($entity)
671
    {
672 10
        @trigger_error('Method ' . __METHOD__ . '() is deprecated and will be removed in Doctrine 3.0.', E_USER_DEPRECATED);
673
674 10
        if ( ! is_object($entity)) {
675 1
            throw ORMInvalidArgumentException::invalidObject('EntityManager#detach()', $entity);
676
        }
677
678 9
        $this->unitOfWork->detach($entity);
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\ORM\UnitOfWork::detach() has been deprecated: 3.0 This method is being removed from the ORM and won't have any replacement ( Ignorable by Annotation )

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

678
        /** @scrutinizer ignore-deprecated */ $this->unitOfWork->detach($entity);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
679 9
    }
680
681
    /**
682
     * Merges the state of a detached entity into the persistence context
683
     * of this EntityManager and returns the managed copy of the entity.
684
     * The entity passed to merge will not become associated/managed with this EntityManager.
685
     *
686
     * @param object $entity The detached entity to merge into the persistence context.
687
     *
688
     * @return object The managed copy of the entity.
689
     *
690
     * @throws ORMInvalidArgumentException
691
     * @throws ORMException
692
     *
693
     * @deprecated 3.0 This method is being removed from the ORM and won't have any replacement
694
     */
695 43
    public function merge($entity)
696
    {
697 43
        @trigger_error('Method ' . __METHOD__ . '() is deprecated and will be removed in Doctrine 3.0.', E_USER_DEPRECATED);
698
699 43
        if ( ! is_object($entity)) {
700 1
            throw ORMInvalidArgumentException::invalidObject('EntityManager#merge()', $entity);
701
        }
702
703 42
        $this->errorIfClosed();
704
705 41
        return $this->unitOfWork->merge($entity);
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\ORM\UnitOfWork::merge() has been deprecated: 3.0 This method is being removed from the ORM and won't have any replacement ( Ignorable by Annotation )

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

705
        return /** @scrutinizer ignore-deprecated */ $this->unitOfWork->merge($entity);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
706
    }
707
708
    /**
709
     * {@inheritDoc}
710
     */
711 1
    public function copy($entity, $deep = false)
712
    {
713 1
        @trigger_error('Method ' . __METHOD__ . '() is deprecated and will be removed in Doctrine 3.0.', E_USER_DEPRECATED);
714
715 1
        throw new \BadMethodCallException("Not implemented.");
716
    }
717
718
    /**
719
     * {@inheritDoc}
720
     */
721 8
    public function lock($entity, $lockMode, $lockVersion = null)
722
    {
723 8
        $this->unitOfWork->lock($entity, $lockMode, $lockVersion);
724 2
    }
725
726
    /**
727
     * Gets the repository for an entity class.
728
     *
729
     * @param string $entityName The name of the entity.
730
     *
731
     * @return \Doctrine\Common\Persistence\ObjectRepository|\Doctrine\ORM\EntityRepository The repository class.
732
     */
733 161
    public function getRepository($entityName)
734
    {
735 161
        return $this->repositoryFactory->getRepository($this, $entityName);
736
    }
737
738
    /**
739
     * Determines whether an entity instance is managed in this EntityManager.
740
     *
741
     * @param object $entity
742
     *
743
     * @return boolean TRUE if this EntityManager currently manages the given entity, FALSE otherwise.
744
     */
745 24
    public function contains($entity)
746
    {
747 24
        return $this->unitOfWork->isScheduledForInsert($entity)
748 22
            || $this->unitOfWork->isInIdentityMap($entity)
749 24
            && ! $this->unitOfWork->isScheduledForDelete($entity);
750
    }
751
752
    /**
753
     * {@inheritDoc}
754
     */
755 2499
    public function getEventManager()
756
    {
757 2499
        return $this->eventManager;
758
    }
759
760
    /**
761
     * {@inheritDoc}
762
     */
763 2499
    public function getConfiguration()
764
    {
765 2499
        return $this->config;
766
    }
767
768
    /**
769
     * Throws an exception if the EntityManager is closed or currently not active.
770
     *
771
     * @return void
772
     *
773
     * @throws ORMException If the EntityManager is closed.
774
     */
775 1108
    private function errorIfClosed()
776
    {
777 1108
        if ($this->closed) {
778 5
            throw ORMException::entityManagerClosed();
779
        }
780 1103
    }
781
782
    /**
783
     * {@inheritDoc}
784
     */
785 2
    public function isOpen()
786
    {
787 2
        return (!$this->closed);
788
    }
789
790
    /**
791
     * {@inheritDoc}
792
     */
793 2499
    public function getUnitOfWork()
794
    {
795 2499
        return $this->unitOfWork;
796
    }
797
798
    /**
799
     * {@inheritDoc}
800
     */
801
    public function getHydrator($hydrationMode)
802
    {
803
        return $this->newHydrator($hydrationMode);
804
    }
805
806
    /**
807
     * {@inheritDoc}
808
     */
809 965
    public function newHydrator($hydrationMode)
810
    {
811
        switch ($hydrationMode) {
812 965
            case Query::HYDRATE_OBJECT:
813 658
                return new Internal\Hydration\ObjectHydrator($this);
814
815 595
            case Query::HYDRATE_ARRAY:
816 48
                return new Internal\Hydration\ArrayHydrator($this);
817
818 552
            case Query::HYDRATE_SCALAR:
819 86
                return new Internal\Hydration\ScalarHydrator($this);
820
821 468
            case Query::HYDRATE_SINGLE_SCALAR:
822 13
                return new Internal\Hydration\SingleScalarHydrator($this);
823
824 459
            case Query::HYDRATE_SIMPLEOBJECT:
825 458
                return new Internal\Hydration\SimpleObjectHydrator($this);
826
827
            default:
828 1
                if (($class = $this->config->getCustomHydrationMode($hydrationMode)) !== null) {
829 1
                    return new $class($this);
830
                }
831
        }
832
833
        throw ORMException::invalidHydrationMode($hydrationMode);
834
    }
835
836
    /**
837
     * {@inheritDoc}
838
     */
839 177
    public function getProxyFactory()
840
    {
841 177
        return $this->proxyFactory;
842
    }
843
844
    /**
845
     * {@inheritDoc}
846
     */
847
    public function initializeObject($obj)
848
    {
849
        $this->unitOfWork->initializeObject($obj);
850
    }
851
852
    /**
853
     * Factory method to create EntityManager instances.
854
     *
855
     * @param array|Connection $connection   An array with the connection parameters or an existing Connection instance.
856
     * @param Configuration    $config       The Configuration instance to use.
857
     * @param EventManager     $eventManager The EventManager instance to use.
858
     *
859
     * @return EntityManager The created EntityManager.
860
     *
861
     * @throws \InvalidArgumentException
862
     * @throws ORMException
863
     */
864 1321
    public static function create($connection, Configuration $config, EventManager $eventManager = null)
865
    {
866 1321
        if ( ! $config->getMetadataDriverImpl()) {
867
            throw ORMException::missingMappingDriverImpl();
868
        }
869
870 1321
        $connection = static::createConnection($connection, $config, $eventManager);
871
872 1320
        return new EntityManager($connection, $config, $connection->getEventManager());
873
    }
874
875
    /**
876
     * Factory method to create Connection instances.
877
     *
878
     * @param array|Connection $connection   An array with the connection parameters or an existing Connection instance.
879
     * @param Configuration    $config       The Configuration instance to use.
880
     * @param EventManager     $eventManager The EventManager instance to use.
881
     *
882
     * @return Connection
883
     *
884
     * @throws \InvalidArgumentException
885
     * @throws ORMException
886
     */
887 1321
    protected static function createConnection($connection, Configuration $config, EventManager $eventManager = null)
888
    {
889 1321
        if (is_array($connection)) {
890
            return DriverManager::getConnection($connection, $config, $eventManager ?: new EventManager());
891
        }
892
893 1321
        if ( ! $connection instanceof Connection) {
0 ignored issues
show
introduced by
$connection is always a sub-type of Doctrine\DBAL\Connection.
Loading history...
894 1
            throw new \InvalidArgumentException(
895 1
                sprintf(
896 1
                    'Invalid $connection argument of type %s given%s.',
897 1
                    is_object($connection) ? get_class($connection) : gettype($connection),
898 1
                    is_object($connection) ? '' : ': "' . $connection . '"'
899
                )
900
            );
901
        }
902
903 1320
        if ($eventManager !== null && $connection->getEventManager() !== $eventManager) {
904
            throw ORMException::mismatchedEventManager();
905
        }
906
907 1320
        return $connection;
908
    }
909
910
    /**
911
     * {@inheritDoc}
912
     */
913 652
    public function getFilters()
914
    {
915 652
        if (null === $this->filterCollection) {
916 652
            $this->filterCollection = new FilterCollection($this);
917
        }
918
919 652
        return $this->filterCollection;
920
    }
921
922
    /**
923
     * {@inheritDoc}
924
     */
925 51
    public function isFiltersStateClean()
926
    {
927 51
        return null === $this->filterCollection || $this->filterCollection->isClean();
928
    }
929
930
    /**
931
     * {@inheritDoc}
932
     */
933 787
    public function hasFilters()
934
    {
935 787
        return null !== $this->filterCollection;
936
    }
937
938
    /**
939
     * @param int $lockMode
940
     * @param ClassMetadata $class
941
     * @throws OptimisticLockException
942
     * @throws TransactionRequiredException
943
     */
944 6
    private function checkLockRequirements(int $lockMode, ClassMetadata $class): void
945
    {
946
        switch ($lockMode) {
947 6
            case LockMode::OPTIMISTIC:
948 3
                if (!$class->isVersioned) {
949 2
                    throw OptimisticLockException::notVersioned($class->name);
950
                }
951 1
                break;
952 3
            case LockMode::PESSIMISTIC_READ:
953 2
            case LockMode::PESSIMISTIC_WRITE:
954 3
                if (!$this->getConnection()->isTransactionActive()) {
955 3
                    throw TransactionRequiredException::transactionRequired();
956
                }
957
        }
958 1
    }
959
}
960