Completed
Push — 2.7 ( d95974...ce9381 )
by Luís
39s queued 22s
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
ccs 10
cts 12
cp 0.8333
crap 8.2964
rs 8.4444
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 const E_USER_DEPRECATED;
33
use function trigger_error;
34
35
/**
36
 * The EntityManager is the central access point to ORM functionality.
37
 *
38
 * It is a facade to all different ORM subsystems such as UnitOfWork,
39
 * Query Language and Repository API. Instantiation is done through
40
 * the static create() method. The quickest way to obtain a fully
41
 * configured EntityManager is:
42
 *
43
 *     use Doctrine\ORM\Tools\Setup;
44
 *     use Doctrine\ORM\EntityManager;
45
 *
46
 *     $paths = array('/path/to/entity/mapping/files');
47
 *
48
 *     $config = Setup::createAnnotationMetadataConfiguration($paths);
49
 *     $dbParams = array('driver' => 'pdo_sqlite', 'memory' => true);
50
 *     $entityManager = EntityManager::create($dbParams, $config);
51
 *
52
 * For more information see
53
 * {@link http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/configuration.html}
54
 *
55
 * You should never attempt to inherit from the EntityManager: Inheritance
56
 * is not a valid extension point for the EntityManager. Instead you
57
 * should take a look at the {@see \Doctrine\ORM\Decorator\EntityManagerDecorator}
58
 * and wrap your entity manager in a decorator.
59
 *
60
 * @since   2.0
61
 * @author  Benjamin Eberlei <[email protected]>
62
 * @author  Guilherme Blanco <[email protected]>
63
 * @author  Jonathan Wage <[email protected]>
64
 * @author  Roman Borschel <[email protected]>
65
 */
66
/* final */class EntityManager implements EntityManagerInterface
67
{
68
    /**
69
     * The used Configuration.
70
     *
71
     * @var \Doctrine\ORM\Configuration
72
     */
73
    private $config;
74
75
    /**
76
     * The database connection used by the EntityManager.
77
     *
78
     * @var \Doctrine\DBAL\Connection
79
     */
80
    private $conn;
81
82
    /**
83
     * The metadata factory, used to retrieve the ORM metadata of entity classes.
84
     *
85
     * @var \Doctrine\ORM\Mapping\ClassMetadataFactory
86
     */
87
    private $metadataFactory;
88
89
    /**
90
     * The UnitOfWork used to coordinate object-level transactions.
91
     *
92
     * @var \Doctrine\ORM\UnitOfWork
93
     */
94
    private $unitOfWork;
95
96
    /**
97
     * The event manager that is the central point of the event system.
98
     *
99
     * @var \Doctrine\Common\EventManager
100
     */
101
    private $eventManager;
102
103
    /**
104
     * The proxy factory used to create dynamic proxies.
105
     *
106
     * @var \Doctrine\ORM\Proxy\ProxyFactory
107
     */
108
    private $proxyFactory;
109
110
    /**
111
     * The repository factory used to create dynamic repositories.
112
     *
113
     * @var \Doctrine\ORM\Repository\RepositoryFactory
114
     */
115
    private $repositoryFactory;
116
117
    /**
118
     * The expression builder instance used to generate query expressions.
119
     *
120
     * @var \Doctrine\ORM\Query\Expr
121
     */
122
    private $expressionBuilder;
123
124
    /**
125
     * Whether the EntityManager is closed or not.
126
     *
127
     * @var bool
128
     */
129
    private $closed = false;
130
131
    /**
132
     * Collection of query filters.
133
     *
134
     * @var \Doctrine\ORM\Query\FilterCollection
135
     */
136
    private $filterCollection;
137
138
    /**
139
     * @var \Doctrine\ORM\Cache The second level cache regions API.
140
     */
141
    private $cache;
142
143
    /**
144
     * Creates a new EntityManager that operates on the given database connection
145
     * and uses the given Configuration and EventManager implementations.
146
     *
147
     * @param \Doctrine\DBAL\Connection     $conn
148
     * @param \Doctrine\ORM\Configuration   $config
149
     * @param \Doctrine\Common\EventManager $eventManager
150
     */
151 2511
    protected function __construct(Connection $conn, Configuration $config, EventManager $eventManager)
152
    {
153 2511
        $this->conn              = $conn;
154 2511
        $this->config            = $config;
155 2511
        $this->eventManager      = $eventManager;
156
157 2511
        $metadataFactoryClassName = $config->getClassMetadataFactoryName();
158
159 2511
        $this->metadataFactory = new $metadataFactoryClassName;
160 2511
        $this->metadataFactory->setEntityManager($this);
161 2511
        $this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl());
162
163 2511
        $this->repositoryFactory = $config->getRepositoryFactory();
164 2511
        $this->unitOfWork        = new UnitOfWork($this);
165 2511
        $this->proxyFactory      = new ProxyFactory(
0 ignored issues
show
Deprecated Code introduced by
The class Doctrine\ORM\Proxy\ProxyFactory has been deprecated: 2.7 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

165
        $this->proxyFactory      = /** @scrutinizer ignore-deprecated */ new ProxyFactory(
Loading history...
166 2511
            $this,
167 2511
            $config->getProxyDir(),
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\ORM\Configuration::getProxyDir() has been deprecated: 2.7 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->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...
168 2511
            $config->getProxyNamespace(),
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\ORM\Configuration::getProxyNamespace() has been deprecated: 2.7 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->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...
169 2511
            $config->getAutoGenerateProxyClasses()
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\ORM\Configurati...oGenerateProxyClasses() has been deprecated: 2.7 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

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

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

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

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