Failed Conditions
Pull Request — 2.6 (#7506)
by
unknown
09:52
created

EntityManager   F

Complexity

Total Complexity 113

Size/Duplication

Total Lines 884
Duplicated Lines 0 %

Test Coverage

Coverage 92.67%

Importance

Changes 0
Metric Value
wmc 113
eloc 232
dl 0
loc 884
ccs 253
cts 273
cp 0.9267
rs 2
c 0
b 0
f 0

45 Methods

Rating   Name   Duplication   Size   Complexity  
A getClassMetadata() 0 3 1
A getCache() 0 3 1
A beginTransaction() 0 3 1
A commit() 0 3 1
A rollback() 0 3 1
A getConnection() 0 3 1
A getExpressionBuilder() 0 7 2
A getMetadataFactory() 0 3 1
B getReference() 0 37 8
A initializeObject() 0 3 1
A contains() 0 5 3
A getPartialReference() 0 21 4
A createNamedNativeQuery() 0 5 1
A getConfiguration() 0 3 1
A errorIfClosed() 0 4 2
A transactional() 0 20 4
A checkLockRequirements() 0 12 6
A createNamedQuery() 0 3 1
A getProxyFactory() 0 3 1
A detach() 0 9 2
A lock() 0 3 1
A createNativeQuery() 0 8 1
A remove() 0 9 2
A refresh() 0 9 2
A createQueryBuilder() 0 3 1
A getUnitOfWork() 0 3 1
A copy() 0 5 1
B createConnection() 0 21 8
A getRepository() 0 3 1
A createQuery() 0 9 2
A isOpen() 0 3 1
A getEventManager() 0 3 1
A __construct() 0 25 2
A persist() 0 9 2
A getHydrator() 0 3 1
A create() 0 9 2
A hasFilters() 0 3 1
A close() 0 5 1
A merge() 0 11 2
F find() 0 81 20
A flush() 0 12 2
A isFiltersStateClean() 0 3 2
A clear() 0 10 4
A getFilters() 0 7 2
B newHydrator() 0 25 7

How to fix   Complexity   

Complex Class

Complex classes like EntityManager often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EntityManager, and based on these observations, apply Extract Interface, too.

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 2508
    protected function __construct(Connection $conn, Configuration $config, EventManager $eventManager)
151
    {
152 2508
        $this->conn              = $conn;
153 2508
        $this->config            = $config;
154 2508
        $this->eventManager      = $eventManager;
155
156 2508
        $metadataFactoryClassName = $config->getClassMetadataFactoryName();
157
158 2508
        $this->metadataFactory = new $metadataFactoryClassName;
159 2508
        $this->metadataFactory->setEntityManager($this);
160 2508
        $this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl());
161
162 2508
        $this->repositoryFactory = $config->getRepositoryFactory();
163 2508
        $this->unitOfWork        = new UnitOfWork($this);
164 2508
        $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

164
        $this->proxyFactory      = /** @scrutinizer ignore-deprecated */ new ProxyFactory(
Loading history...
165 2508
            $this,
166 2508
            $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

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 2508
            $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

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 2508
            $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

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

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

671
        /** @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...
672 9
    }
673
674
    /**
675
     * Merges the state of a detached entity into the persistence context
676
     * of this EntityManager and returns the managed copy of the entity.
677
     * The entity passed to merge will not become associated/managed with this EntityManager.
678
     *
679
     * @param object $entity The detached entity to merge into the persistence context.
680
     *
681
     * @return object The managed copy of the entity.
682
     *
683
     * @throws ORMInvalidArgumentException
684
     * @throws ORMException
685
     *
686
     * @deprecated 2.7 This method is being removed from the ORM and won't have any replacement
687
     */
688 43
    public function merge($entity)
689
    {
690 43
        @trigger_error('Method ' . __METHOD__ . '() is deprecated and will be removed in Doctrine 3.0.', E_USER_DEPRECATED);
691
692 43
        if ( ! is_object($entity)) {
693 1
            throw ORMInvalidArgumentException::invalidObject('EntityManager#merge()', $entity);
694
        }
695
696 42
        $this->errorIfClosed();
697
698 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

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