Passed
Pull Request — master (#6869)
by Michael
09:57
created

EntityManager::flush()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

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

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

162
        $this->proxyFactory      = /** @scrutinizer ignore-deprecated */ new ProxyFactory(
Loading history...
163 2453
            $this,
164 2453
            $config->getProxyDir(),
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\ORM\Configuration::getProxyDir() has been deprecated. ( Ignorable by Annotation )

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

164
            /** @scrutinizer ignore-deprecated */ $config->getProxyDir(),
Loading history...
165 2453
            $config->getProxyNamespace(),
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\ORM\Configuration::getProxyNamespace() has been deprecated. ( Ignorable by Annotation )

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

165
            /** @scrutinizer ignore-deprecated */ $config->getProxyNamespace(),
Loading history...
166 2453
            $config->getAutoGenerateProxyClasses()
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\ORM\Configurati...oGenerateProxyClasses() has been deprecated. ( 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->getAutoGenerateProxyClasses()
Loading history...
167
        );
168
169 2453
        if ($config->isSecondLevelCacheEnabled()) {
170 285
            $cacheConfig    = $config->getSecondLevelCacheConfiguration();
171 285
            $cacheFactory   = $cacheConfig->getCacheFactory();
172 285
            $this->cache    = $cacheFactory->createCache($this);
173
        }
174 2453
    }
175
176
    /**
177
     * {@inheritDoc}
178
     */
179 1922
    public function getConnection()
180
    {
181 1922
        return $this->conn;
182
    }
183
184
    /**
185
     * Gets the metadata factory used to gather the metadata of classes.
186
     *
187
     * @return \Doctrine\ORM\Mapping\ClassMetadataFactory
188
     */
189 2453
    public function getMetadataFactory()
190
    {
191 2453
        return $this->metadataFactory;
192
    }
193
194
    /**
195
     * {@inheritDoc}
196
     */
197 17
    public function getExpressionBuilder()
198
    {
199 17
        if ($this->expressionBuilder === null) {
200 17
            $this->expressionBuilder = new Query\Expr;
201
        }
202
203 17
        return $this->expressionBuilder;
204
    }
205
206
    /**
207
     * {@inheritDoc}
208
     */
209 1
    public function beginTransaction()
210
    {
211 1
        $this->conn->beginTransaction();
212 1
    }
213
214
    /**
215
     * {@inheritDoc}
216
     */
217 217
    public function getCache()
218
    {
219 217
        return $this->cache;
220
    }
221
222
    /**
223
     * {@inheritDoc}
224
     */
225 5
    public function transactional($func)
226
    {
227 5
        if (!is_callable($func)) {
228 1
            throw new \InvalidArgumentException('Expected argument of type "callable", got "' . gettype($func) . '"');
229
        }
230
231 4
        $this->conn->beginTransaction();
232
233
        try {
234 4
            $return = call_user_func($func, $this);
235
236 3
            $this->flush();
237 3
            $this->conn->commit();
238
239 3
            return $return ?: true;
240 1
        } catch (Throwable $e) {
241 1
            $this->close();
242 1
            $this->conn->rollBack();
243
244 1
            throw $e;
245
        }
246
    }
247
248
    /**
249
     * {@inheritDoc}
250
     */
251 1
    public function commit()
252
    {
253 1
        $this->conn->commit();
254 1
    }
255
256
    /**
257
     * {@inheritDoc}
258
     */
259
    public function rollback()
260
    {
261
        $this->conn->rollBack();
262
    }
263
264
    /**
265
     * Returns the ORM metadata descriptor for a class.
266
     *
267
     * The class name must be the fully-qualified class name without a leading backslash
268
     * (as it is returned by get_class($obj)) or an aliased class name.
269
     *
270
     * Examples:
271
     * MyProject\Domain\User
272
     * sales:PriceRequest
273
     *
274
     * Internal note: Performance-sensitive method.
275
     *
276
     * @param string $className
277
     *
278
     * @return \Doctrine\ORM\Mapping\ClassMetadata
279
     */
280 1980
    public function getClassMetadata($className)
281
    {
282 1980
        return $this->metadataFactory->getMetadataFor($className);
283
    }
284
285
    /**
286
     * {@inheritDoc}
287
     */
288 968
    public function createQuery($dql = '')
289
    {
290 968
        $query = new Query($this);
291
292 968
        if ( ! empty($dql)) {
293 963
            $query->setDQL($dql);
294
        }
295
296 968
        return $query;
297
    }
298
299
    /**
300
     * {@inheritDoc}
301
     */
302 1
    public function createNamedQuery($name)
303
    {
304 1
        return $this->createQuery($this->config->getNamedQuery($name));
305
    }
306
307
    /**
308
     * {@inheritDoc}
309
     */
310 21
    public function createNativeQuery($sql, ResultSetMapping $rsm)
311
    {
312 21
        $query = new NativeQuery($this);
313
314 21
        $query->setSQL($sql);
315 21
        $query->setResultSetMapping($rsm);
316
317 21
        return $query;
318
    }
319
320
    /**
321
     * {@inheritDoc}
322
     */
323 1
    public function createNamedNativeQuery($name)
324
    {
325 1
        list($sql, $rsm) = $this->config->getNamedNativeQuery($name);
326
327 1
        return $this->createNativeQuery($sql, $rsm);
328
    }
329
330
    /**
331
     * {@inheritDoc}
332
     */
333 127
    public function createQueryBuilder()
334
    {
335 127
        return new QueryBuilder($this);
336
    }
337
338
    /**
339
     * Flushes all changes to objects that have been queued up to now to the database.
340
     * This effectively synchronizes the in-memory state of managed objects with the
341
     * database.
342
     *
343
     * If an entity is explicitly passed to this method only this entity and
344
     * the cascade-persist semantics + scheduled inserts/removals are synchronized.
345
     *
346
     * @param null|object|array $entity
347
     *
348
     * @return void
349
     *
350
     * @throws \Doctrine\ORM\OptimisticLockException If a version check on an entity that
351
     *         makes use of optimistic locking fails.
352
     * @throws ORMException
353
     */
354 1062
    public function flush($entity = null)
355
    {
356 1062
        if (func_num_args() !== 0) {
357 12
            @trigger_error(
358 12
                'Calling ' . __METHOD__ . '() with any arguments to flush specific entities is deprecated and will not be supported in Doctrine 3.0.',
359 12
                E_USER_DEPRECATED
360
            );
361
        }
362
363 1062
        $this->errorIfClosed();
364
365 1061
        $this->unitOfWork->commit($entity);
366 1050
    }
367
368
    /**
369
     * Finds an Entity by its identifier.
370
     *
371
     * @param string       $entityName  The class name of the entity to find.
372
     * @param mixed        $id          The identity of the entity to find.
373
     * @param integer|null $lockMode    One of the \Doctrine\DBAL\LockMode::* constants
374
     *                                  or NULL if no specific lock mode should be used
375
     *                                  during the search.
376
     * @param integer|null $lockVersion The version of the entity to find when using
377
     *                                  optimistic locking.
378
     *
379
     * @return object|null The entity instance or NULL if the entity can not be found.
380
     *
381
     * @throws OptimisticLockException
382
     * @throws ORMInvalidArgumentException
383
     * @throws TransactionRequiredException
384
     * @throws ORMException
385
     */
386 434
    public function find($entityName, $id, $lockMode = null, $lockVersion = null)
387
    {
388 434
        $class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
389
390 434
        if ( ! is_array($id)) {
391 388
            if ($class->isIdentifierComposite) {
0 ignored issues
show
Bug introduced by
Accessing isIdentifierComposite on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
392
                throw ORMInvalidArgumentException::invalidCompositeIdentifier();
393
            }
394
395 388
            $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...
396
        }
397
398 434
        foreach ($id as $i => $value) {
399 434 View Code Duplication
            if (is_object($value) && $this->metadataFactory->hasMetadataFor(ClassUtils::getClass($value))) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
400 7
                $id[$i] = $this->unitOfWork->getSingleIdentifierValue($value);
401
402 7
                if ($id[$i] === null) {
403 434
                    throw ORMInvalidArgumentException::invalidIdentifierBindingEntity();
404
                }
405
            }
406
        }
407
408 433
        $sortedId = [];
409
410 433 View Code Duplication
        foreach ($class->identifier as $identifier) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
411 433
            if ( ! isset($id[$identifier])) {
412 1
                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...
413
            }
414
415 432
            $sortedId[$identifier] = $id[$identifier];
416 432
            unset($id[$identifier]);
417
        }
418
419 432
        if ($id) {
420 1
            throw ORMException::unrecognizedIdentifierFields($class->name, array_keys($id));
421
        }
422
423 431
        $unitOfWork = $this->getUnitOfWork();
424
425
        // Check identity map first
426 431
        if (($entity = $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...
427 46
            if ( ! ($entity instanceof $class->name)) {
428 1
                return null;
429
            }
430
431
            switch (true) {
432 45
                case LockMode::OPTIMISTIC === $lockMode:
433 1
                    $this->lock($entity, $lockMode, $lockVersion);
434
                    break;
435
436 45
                case LockMode::NONE === $lockMode:
437 45
                case LockMode::PESSIMISTIC_READ === $lockMode:
438 45
                case LockMode::PESSIMISTIC_WRITE === $lockMode:
439
                    $persister = $unitOfWork->getEntityPersister($class->name);
440
                    $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

440
                    $persister->refresh($sortedId, /** @scrutinizer ignore-type */ $entity, $lockMode);
Loading history...
441
                    break;
442
            }
443
444 45
            return $entity; // Hit!
0 ignored issues
show
Bug Best Practice introduced by
The expression return $entity also could return the type true which is incompatible with the documented return type object|null.
Loading history...
445
        }
446
447 412
        $persister = $unitOfWork->getEntityPersister($class->name);
448
449
        switch (true) {
450 412
            case LockMode::OPTIMISTIC === $lockMode:
451 1
                if ( ! $class->isVersioned) {
0 ignored issues
show
Bug introduced by
Accessing isVersioned on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
452 1
                    throw OptimisticLockException::notVersioned($class->name);
453
                }
454
455
                $entity = $persister->load($sortedId);
456
457
                $unitOfWork->lock($entity, $lockMode, $lockVersion);
458
459
                return $entity;
460
461 411
            case LockMode::PESSIMISTIC_READ === $lockMode:
462 410
            case LockMode::PESSIMISTIC_WRITE === $lockMode:
463 2
                if ( ! $this->getConnection()->isTransactionActive()) {
464 2
                    throw TransactionRequiredException::transactionRequired();
465
                }
466
467
                return $persister->load($sortedId, null, null, [], $lockMode);
468
469
            default:
470 409
                return $persister->loadById($sortedId);
471
        }
472
    }
473
474
    /**
475
     * {@inheritDoc}
476
     */
477 94
    public function getReference($entityName, $id)
478
    {
479 94
        $class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
480
481 94
        if ( ! is_array($id)) {
482 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...
483
        }
484
485 94
        $sortedId = [];
486
487 94 View Code Duplication
        foreach ($class->identifier as $identifier) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
488 94
            if ( ! isset($id[$identifier])) {
489
                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...
490
            }
491
492 94
            $sortedId[$identifier] = $id[$identifier];
493 94
            unset($id[$identifier]);
494
        }
495
496 94
        if ($id) {
497 1
            throw ORMException::unrecognizedIdentifierFields($class->name, array_keys($id));
498
        }
499
500
        // Check identity map first, if its already in there just return it.
501 93 View Code Duplication
        if (($entity = $this->unitOfWork->tryGetById($sortedId, $class->rootEntityName)) !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
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...
502 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 object|null.
Loading history...
503
        }
504
505 88
        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...
506 2
            return $this->find($entityName, $sortedId);
507
        }
508
509 88
        $entity = $this->proxyFactory->getProxy($class->name, $sortedId);
510
511 88
        $this->unitOfWork->registerManaged($entity, $sortedId, []);
512
513 88
        return $entity;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $entity returns the type Doctrine\Common\Proxy\Proxy which is incompatible with the return type mandated by Doctrine\ORM\EntityManag...terface::getReference() of object|null.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
514
    }
515
516
    /**
517
     * {@inheritDoc}
518
     */
519 4
    public function getPartialReference($entityName, $identifier)
520
    {
521 4
        $class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
522
523
        // Check identity map first, if its already in there just return it.
524 4 View Code Duplication
        if (($entity = $this->unitOfWork->tryGetById($identifier, $class->rootEntityName)) !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
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...
525 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 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...
526
        }
527
528 3
        if ( ! is_array($identifier)) {
529 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...
530
        }
531
532 3
        $entity = $class->newInstance();
0 ignored issues
show
Bug introduced by
The method newInstance() does not exist on Doctrine\Common\Persistence\Mapping\ClassMetadata. It seems like you code against a sub-type of Doctrine\Common\Persistence\Mapping\ClassMetadata such as Doctrine\ORM\Mapping\ClassMetadataInfo. ( Ignorable by Annotation )

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

532
        /** @scrutinizer ignore-call */ 
533
        $entity = $class->newInstance();
Loading history...
533
534 3
        $class->setIdentifierValues($entity, $identifier);
0 ignored issues
show
Bug introduced by
The method setIdentifierValues() does not exist on Doctrine\Common\Persistence\Mapping\ClassMetadata. It seems like you code against a sub-type of Doctrine\Common\Persistence\Mapping\ClassMetadata such as Doctrine\ORM\Mapping\ClassMetadataInfo. ( Ignorable by Annotation )

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

534
        $class->/** @scrutinizer ignore-call */ 
535
                setIdentifierValues($entity, $identifier);
Loading history...
535
536 3
        $this->unitOfWork->registerManaged($entity, $identifier, []);
537 3
        $this->unitOfWork->markReadOnly($entity);
538
539 3
        return $entity;
540
    }
541
542
    /**
543
     * Clears the EntityManager. All entities that are currently managed
544
     * by this EntityManager become detached.
545
     *
546
     * @param string|null $entityName if given, only entities of this type will get detached
547
     *
548
     * @return void
549
     *
550
     * @throws ORMInvalidArgumentException                           if a non-null non-string value is given
551
     * @throws \Doctrine\Common\Persistence\Mapping\MappingException if a $entityName is given, but that entity is not
552
     *                                                               found in the mappings
553
     */
554 1288
    public function clear($entityName = null)
555
    {
556 1288
        if (null !== $entityName && ! is_string($entityName)) {
557 1
            throw ORMInvalidArgumentException::invalidEntityName($entityName);
558
        }
559
560 1287
        $this->unitOfWork->clear(
561 1287
            null === $entityName
562 1285
                ? null
563 1287
                : $this->metadataFactory->getMetadataFor($entityName)->getName()
564
        );
565 1286
    }
566
567
    /**
568
     * {@inheritDoc}
569
     */
570 20
    public function close()
571
    {
572 20
        $this->clear();
573
574 20
        $this->closed = true;
575 20
    }
576
577
    /**
578
     * Tells the EntityManager to make an instance managed and persistent.
579
     *
580
     * The entity will be entered into the database at or before transaction
581
     * commit or as a result of the flush operation.
582
     *
583
     * NOTE: The persist operation always considers entities that are not yet known to
584
     * this EntityManager as NEW. Do not pass detached entities to the persist operation.
585
     *
586
     * @param object $entity The instance to make managed and persistent.
587
     *
588
     * @return void
589
     *
590
     * @throws ORMInvalidArgumentException
591
     * @throws ORMException
592
     */
593 1061 View Code Duplication
    public function persist($entity)
594
    {
595 1061
        if ( ! is_object($entity)) {
596 1
            throw ORMInvalidArgumentException::invalidObject('EntityManager#persist()', $entity);
597
        }
598
599 1060
        $this->errorIfClosed();
600
601 1059
        $this->unitOfWork->persist($entity);
602 1058
    }
603
604
    /**
605
     * Removes an entity instance.
606
     *
607
     * A removed entity will be removed from the database at or before transaction commit
608
     * or as a result of the flush operation.
609
     *
610
     * @param object $entity The entity instance to remove.
611
     *
612
     * @return void
613
     *
614
     * @throws ORMInvalidArgumentException
615
     * @throws ORMException
616
     */
617 52 View Code Duplication
    public function remove($entity)
618
    {
619 52
        if ( ! is_object($entity)) {
620 1
            throw ORMInvalidArgumentException::invalidObject('EntityManager#remove()', $entity);
621
        }
622
623 51
        $this->errorIfClosed();
624
625 50
        $this->unitOfWork->remove($entity);
626 50
    }
627
628
    /**
629
     * Refreshes the persistent state of an entity from the database,
630
     * overriding any local changes that have not yet been persisted.
631
     *
632
     * @param object $entity The entity to refresh.
633
     *
634
     * @return void
635
     *
636
     * @throws ORMInvalidArgumentException
637
     * @throws ORMException
638
     */
639 19 View Code Duplication
    public function refresh($entity)
640
    {
641 19
        if ( ! is_object($entity)) {
642 1
            throw ORMInvalidArgumentException::invalidObject('EntityManager#refresh()', $entity);
643
        }
644
645 18
        $this->errorIfClosed();
646
647 17
        $this->unitOfWork->refresh($entity);
648 17
    }
649
650
    /**
651
     * Detaches an entity from the EntityManager, causing a managed entity to
652
     * become detached.  Unflushed changes made to the entity if any
653
     * (including removal of the entity), will not be synchronized to the database.
654
     * Entities which previously referenced the detached entity will continue to
655
     * reference it.
656
     *
657
     * @param object $entity The entity to detach.
658
     *
659
     * @return void
660
     *
661
     * @throws ORMInvalidArgumentException
662
     *
663
     * @deprecated This method is deprecated and will be removed in Doctrine 3.0.
664
     */
665 7 View Code Duplication
    public function detach($entity)
666
    {
667 7
        @trigger_error('Method ' . __METHOD__ . '() is deprecated and will be removed in Doctrine 3.0.', E_USER_DEPRECATED);
668
669 7
        if ( ! is_object($entity)) {
670 1
            throw ORMInvalidArgumentException::invalidObject('EntityManager#detach()', $entity);
671
        }
672
673 6
        $this->unitOfWork->detach($entity);
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\ORM\UnitOfWork::detach() has been deprecated. ( Ignorable by Annotation )

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

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

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

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