Passed
Pull Request — master (#6794)
by Claudio
15:20
created

EntityManager::copy()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
ccs 0
cts 2
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 2
crap 2
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 2415
    protected function __construct(Connection $conn, Configuration $config, EventManager $eventManager)
149
    {
150 2415
        $this->conn              = $conn;
151 2415
        $this->config            = $config;
152 2415
        $this->eventManager      = $eventManager;
153
154 2415
        $metadataFactoryClassName = $config->getClassMetadataFactoryName();
155
156 2415
        $this->metadataFactory = new $metadataFactoryClassName;
157 2415
        $this->metadataFactory->setEntityManager($this);
158 2415
        $this->metadataFactory->setCacheDriver($this->config->getMetadataCacheImpl());
159
160 2415
        $this->repositoryFactory = $config->getRepositoryFactory();
161 2415
        $this->unitOfWork        = new UnitOfWork($this);
162 2415
        $this->proxyFactory      = new ProxyFactory(
163 2415
            $this,
164 2415
            $config->getProxyDir(),
165 2415
            $config->getProxyNamespace(),
166 2415
            $config->getAutoGenerateProxyClasses()
167
        );
168
169 2415
        if ($config->isSecondLevelCacheEnabled()) {
170 285
            $cacheConfig    = $config->getSecondLevelCacheConfiguration();
171 285
            $cacheFactory   = $cacheConfig->getCacheFactory();
172 285
            $this->cache    = $cacheFactory->createCache($this);
173
        }
174 2415
    }
175
176
    /**
177
     * {@inheritDoc}
178
     */
179 1896
    public function getConnection()
180
    {
181 1896
        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 2415
    public function getMetadataFactory()
190
    {
191 2415
        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 1956
    public function getClassMetadata($className)
281
    {
282 1956
        return $this->metadataFactory->getMetadataFor($className);
283
    }
284
285
    /**
286
     * {@inheritDoc}
287
     */
288 949
    public function createQuery($dql = '')
289
    {
290 949
        $query = new Query($this);
291
292 949
        if ( ! empty($dql)) {
293 944
            $query->setDQL($dql);
294
        }
295
296 949
        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 121
    public function createQueryBuilder()
334
    {
335 121
        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 1045
    public function flush($entity = null)
355
    {
356 1045
        $this->errorIfClosed();
357
358 1044
        $this->unitOfWork->commit($entity);
359 1035
    }
360
361
    /**
362
     * Finds an Entity by its identifier.
363
     *
364
     * @param string       $entityName  The class name of the entity to find.
365
     * @param mixed        $id          The identity of the entity to find.
366
     * @param integer|null $lockMode    One of the \Doctrine\DBAL\LockMode::* constants
367
     *                                  or NULL if no specific lock mode should be used
368
     *                                  during the search.
369
     * @param integer|null $lockVersion The version of the entity to find when using
370
     *                                  optimistic locking.
371
     *
372
     * @return object|null The entity instance or NULL if the entity can not be found.
373
     *
374
     * @throws OptimisticLockException
375
     * @throws ORMInvalidArgumentException
376
     * @throws TransactionRequiredException
377
     * @throws ORMException
378
     */
379 429
    public function find($entityName, $id, $lockMode = null, $lockVersion = null)
380
    {
381 429
        $class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
382
383 429
        if ( ! is_array($id)) {
384 383
            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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
385
                throw ORMInvalidArgumentException::invalidCompositeIdentifier();
386
            }
387
388 383
            $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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
389
        }
390
391 429
        foreach ($id as $i => $value) {
392 429 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...
393 7
                $id[$i] = $this->unitOfWork->getSingleIdentifierValue($value);
394
395 7
                if ($id[$i] === null) {
396 429
                    throw ORMInvalidArgumentException::invalidIdentifierBindingEntity();
397
                }
398
            }
399
        }
400
401 428
        $sortedId = [];
402
403 428 View Code Duplication
        foreach ($class->identifier as $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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
404 428
            if ( ! isset($id[$identifier])) {
405 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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
406
            }
407
408 427
            $sortedId[$identifier] = $id[$identifier];
409 427
            unset($id[$identifier]);
410
        }
411
412 427
        if ($id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
413 1
            throw ORMException::unrecognizedIdentifierFields($class->name, array_keys($id));
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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
414
        }
415
416 426
        $unitOfWork = $this->getUnitOfWork();
417
418
        // Check identity map first
419 426
        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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
420 46
            if ( ! ($entity instanceof $class->name)) {
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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
421 1
                return null;
422
            }
423
424
            switch (true) {
425 45
                case LockMode::OPTIMISTIC === $lockMode:
426 1
                    $this->lock($entity, $lockMode, $lockVersion);
427
                    break;
428
429 45
                case LockMode::NONE === $lockMode:
430 45
                case LockMode::PESSIMISTIC_READ === $lockMode:
431 45
                case LockMode::PESSIMISTIC_WRITE === $lockMode:
432
                    $persister = $unitOfWork->getEntityPersister($class->name);
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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
433
                    $persister->refresh($sortedId, $entity, $lockMode);
434
                    break;
435
            }
436
437 45
            return $entity; // Hit!
438
        }
439
440 407
        $persister = $unitOfWork->getEntityPersister($class->name);
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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
441
442
        switch (true) {
443 407
            case LockMode::OPTIMISTIC === $lockMode:
444 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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
445 1
                    throw OptimisticLockException::notVersioned($class->name);
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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
446
                }
447
448
                $entity = $persister->load($sortedId);
449
450
                $unitOfWork->lock($entity, $lockMode, $lockVersion);
0 ignored issues
show
Bug introduced by
It seems like $entity defined by $persister->load($sortedId) on line 448 can also be of type null; however, Doctrine\ORM\UnitOfWork::lock() does only seem to accept object, maybe add an additional type check?

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

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

    return array();
}

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

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

Loading history...
451
452
                return $entity;
453
454 406
            case LockMode::PESSIMISTIC_READ === $lockMode:
455 405
            case LockMode::PESSIMISTIC_WRITE === $lockMode:
456 2
                if ( ! $this->getConnection()->isTransactionActive()) {
457 2
                    throw TransactionRequiredException::transactionRequired();
458
                }
459
460
                return $persister->load($sortedId, null, null, [], $lockMode);
461
462
            default:
463 404
                return $persister->loadById($sortedId);
464
        }
465
    }
466
467
    /**
468
     * {@inheritDoc}
469
     */
470 94
    public function getReference($entityName, $id)
471
    {
472 94
        $class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
473
474 94
        if ( ! is_array($id)) {
475 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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
476
        }
477
478 94
        $sortedId = [];
479
480 94 View Code Duplication
        foreach ($class->identifier as $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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
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...
481 94
            if ( ! isset($id[$identifier])) {
482
                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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
483
            }
484
485 94
            $sortedId[$identifier] = $id[$identifier];
486 94
            unset($id[$identifier]);
487
        }
488
489 94
        if ($id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
490 1
            throw ORMException::unrecognizedIdentifierFields($class->name, array_keys($id));
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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
491
        }
492
493
        // Check identity map first, if its already in there just return it.
494 93 View Code Duplication
        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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
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...
495 28
            return ($entity instanceof $class->name) ? $entity : null;
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
496
        }
497
498 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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
499 2
            return $this->find($entityName, $sortedId);
500
        }
501
502 88
        $entity = $this->proxyFactory->getProxy($class->name, $sortedId);
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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
503
504 88
        $this->unitOfWork->registerManaged($entity, $sortedId, []);
505
506 88
        return $entity;
507
    }
508
509
    /**
510
     * {@inheritDoc}
511
     */
512 4
    public function getPartialReference($entityName, $identifier)
513
    {
514 4
        $class = $this->metadataFactory->getMetadataFor(ltrim($entityName, '\\'));
515
516
        // Check identity map first, if its already in there just return it.
517 4 View Code Duplication
        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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
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...
518 1
            return ($entity instanceof $class->name) ? $entity : null;
0 ignored issues
show
Bug introduced by
Accessing name on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
519
        }
520
521 3
        if ( ! is_array($identifier)) {
522 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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
523
        }
524
525 3
        $entity = $class->newInstance();
526
527 3
        $class->setIdentifierValues($entity, $identifier);
528
529 3
        $this->unitOfWork->registerManaged($entity, $identifier, []);
530 3
        $this->unitOfWork->markReadOnly($entity);
531
532 3
        return $entity;
533
    }
534
535
    /**
536
     * Clears the EntityManager. All entities that are currently managed
537
     * by this EntityManager become detached.
538
     *
539
     * @param string|null $entityName if given, only entities of this type will get detached
540
     *
541
     * @return void
542
     *
543
     * @throws ORMInvalidArgumentException                           if a non-null non-string value is given
544
     * @throws \Doctrine\Common\Persistence\Mapping\MappingException if a $entityName is given, but that entity is not
545
     *                                                               found in the mappings
546
     */
547 1266
    public function clear($entityName = null)
548
    {
549 1266
        if (null !== $entityName && ! is_string($entityName)) {
550 1
            throw ORMInvalidArgumentException::invalidEntityName($entityName);
551
        }
552
553 1265
        $this->unitOfWork->clear(
554 1265
            null === $entityName
555 1263
                ? null
556 1265
                : $this->metadataFactory->getMetadataFor($entityName)->getName()
557
        );
558 1264
    }
559
560
    /**
561
     * {@inheritDoc}
562
     */
563 20
    public function close()
564
    {
565 20
        $this->clear();
566
567 20
        $this->closed = true;
568 20
    }
569
570
    /**
571
     * Tells the EntityManager to make an instance managed and persistent.
572
     *
573
     * The entity will be entered into the database at or before transaction
574
     * commit or as a result of the flush operation.
575
     *
576
     * NOTE: The persist operation always considers entities that are not yet known to
577
     * this EntityManager as NEW. Do not pass detached entities to the persist operation.
578
     *
579
     * @param object $entity The instance to make managed and persistent.
580
     *
581
     * @return void
582
     *
583
     * @throws ORMInvalidArgumentException
584
     * @throws ORMException
585
     */
586 1041 View Code Duplication
    public function persist($entity)
587
    {
588 1041
        if ( ! is_object($entity)) {
589 1
            throw ORMInvalidArgumentException::invalidObject('EntityManager#persist()', $entity);
590
        }
591
592 1040
        $this->errorIfClosed();
593
594 1039
        $this->unitOfWork->persist($entity);
595 1038
    }
596
597
    /**
598
     * Removes an entity instance.
599
     *
600
     * A removed entity will be removed from the database at or before transaction commit
601
     * or as a result of the flush operation.
602
     *
603
     * @param object $entity The entity instance to remove.
604
     *
605
     * @return void
606
     *
607
     * @throws ORMInvalidArgumentException
608
     * @throws ORMException
609
     */
610 52 View Code Duplication
    public function remove($entity)
611
    {
612 52
        if ( ! is_object($entity)) {
613 1
            throw ORMInvalidArgumentException::invalidObject('EntityManager#remove()', $entity);
614
        }
615
616 51
        $this->errorIfClosed();
617
618 50
        $this->unitOfWork->remove($entity);
619 50
    }
620
621
    /**
622
     * Refreshes the persistent state of an entity from the database,
623
     * overriding any local changes that have not yet been persisted.
624
     *
625
     * @param object $entity The entity to refresh.
626
     *
627
     * @return void
628
     *
629
     * @throws ORMInvalidArgumentException
630
     * @throws ORMException
631
     */
632 19 View Code Duplication
    public function refresh($entity)
633
    {
634 19
        if ( ! is_object($entity)) {
635 1
            throw ORMInvalidArgumentException::invalidObject('EntityManager#refresh()', $entity);
636
        }
637
638 18
        $this->errorIfClosed();
639
640 17
        $this->unitOfWork->refresh($entity);
641 17
    }
642
643
    /**
644
     * Detaches an entity from the EntityManager, causing a managed entity to
645
     * become detached.  Unflushed changes made to the entity if any
646
     * (including removal of the entity), will not be synchronized to the database.
647
     * Entities which previously referenced the detached entity will continue to
648
     * reference it.
649
     *
650
     * @param object $entity The entity to detach.
651
     *
652
     * @return void
653
     *
654
     * @throws ORMInvalidArgumentException
655
     */
656 13
    public function detach($entity)
657
    {
658 13
        if ( ! is_object($entity)) {
659 1
            throw ORMInvalidArgumentException::invalidObject('EntityManager#detach()', $entity);
660
        }
661
662 12
        $this->unitOfWork->detach($entity);
663 12
    }
664
665
    /**
666
     * Merges the state of a detached entity into the persistence context
667
     * of this EntityManager and returns the managed copy of the entity.
668
     * The entity passed to merge will not become associated/managed with this EntityManager.
669
     *
670
     * @param object $entity The detached entity to merge into the persistence context.
671
     *
672
     * @return object The managed copy of the entity.
673
     *
674
     * @throws ORMInvalidArgumentException
675
     * @throws ORMException
676
     */
677 42 View Code Duplication
    public function merge($entity)
678
    {
679 42
        if ( ! is_object($entity)) {
680 1
            throw ORMInvalidArgumentException::invalidObject('EntityManager#merge()', $entity);
681
        }
682
683 41
        $this->errorIfClosed();
684
685 40
        return $this->unitOfWork->merge($entity);
686
    }
687
688
    /**
689
     * {@inheritDoc}
690
     */
691 9
    public function lock($entity, $lockMode, $lockVersion = null)
692
    {
693 9
        $this->unitOfWork->lock($entity, $lockMode, $lockVersion);
694 2
    }
695
696
    /**
697
     * Gets the repository for an entity class.
698
     *
699
     * @param string $entityName The name of the entity.
700
     *
701
     * @return \Doctrine\ORM\EntityRepository The repository class.
702
     */
703 158
    public function getRepository($entityName)
704
    {
705 158
        return $this->repositoryFactory->getRepository($this, $entityName);
706
    }
707
708
    /**
709
     * Determines whether an entity instance is managed in this EntityManager.
710
     *
711
     * @param object $entity
712
     *
713
     * @return boolean TRUE if this EntityManager currently manages the given entity, FALSE otherwise.
714
     */
715 24
    public function contains($entity)
716
    {
717 24
        return $this->unitOfWork->isScheduledForInsert($entity)
718 22
            || $this->unitOfWork->isInIdentityMap($entity)
719 24
            && ! $this->unitOfWork->isScheduledForDelete($entity);
720
    }
721
722
    /**
723
     * {@inheritDoc}
724
     */
725 2415
    public function getEventManager()
726
    {
727 2415
        return $this->eventManager;
728
    }
729
730
    /**
731
     * {@inheritDoc}
732
     */
733 2415
    public function getConfiguration()
734
    {
735 2415
        return $this->config;
736
    }
737
738
    /**
739
     * Throws an exception if the EntityManager is closed or currently not active.
740
     *
741
     * @return void
742
     *
743
     * @throws ORMException If the EntityManager is closed.
744
     */
745 1060
    private function errorIfClosed()
746
    {
747 1060
        if ($this->closed) {
748 5
            throw ORMException::entityManagerClosed();
749
        }
750 1055
    }
751
752
    /**
753
     * {@inheritDoc}
754
     */
755 2
    public function isOpen()
756
    {
757 2
        return (!$this->closed);
758
    }
759
760
    /**
761
     * {@inheritDoc}
762
     */
763 2415
    public function getUnitOfWork()
764
    {
765 2415
        return $this->unitOfWork;
766
    }
767
768
    /**
769
     * {@inheritDoc}
770
     */
771
    public function getHydrator($hydrationMode)
772
    {
773
        return $this->newHydrator($hydrationMode);
774
    }
775
776
    /**
777
     * {@inheritDoc}
778
     */
779 926
    public function newHydrator($hydrationMode)
780
    {
781
        switch ($hydrationMode) {
782 926
            case Query::HYDRATE_OBJECT:
783 643
                return new Internal\Hydration\ObjectHydrator($this);
784
785 563
            case Query::HYDRATE_ARRAY:
786 36
                return new Internal\Hydration\ArrayHydrator($this);
787
788 532
            case Query::HYDRATE_SCALAR:
789 85
                return new Internal\Hydration\ScalarHydrator($this);
790
791 449
            case Query::HYDRATE_SINGLE_SCALAR:
792 13
                return new Internal\Hydration\SingleScalarHydrator($this);
793
794 440
            case Query::HYDRATE_SIMPLEOBJECT:
795 439
                return new Internal\Hydration\SimpleObjectHydrator($this);
796
797
            default:
798 1
                if (($class = $this->config->getCustomHydrationMode($hydrationMode)) !== null) {
799 1
                    return new $class($this);
800
                }
801
        }
802
803
        throw ORMException::invalidHydrationMode($hydrationMode);
804
    }
805
806
    /**
807
     * {@inheritDoc}
808
     */
809 176
    public function getProxyFactory()
810
    {
811 176
        return $this->proxyFactory;
812
    }
813
814
    /**
815
     * {@inheritDoc}
816
     */
817
    public function initializeObject($obj)
818
    {
819
        $this->unitOfWork->initializeObject($obj);
820
    }
821
822
    /**
823
     * Factory method to create EntityManager instances.
824
     *
825
     * @param array|Connection $connection   An array with the connection parameters or an existing Connection instance.
826
     * @param Configuration    $config       The Configuration instance to use.
827
     * @param EventManager     $eventManager The EventManager instance to use.
828
     *
829
     * @return EntityManager The created EntityManager.
830
     *
831
     * @throws \InvalidArgumentException
832
     * @throws ORMException
833
     */
834 1268
    public static function create($connection, Configuration $config, EventManager $eventManager = null)
835
    {
836 1268
        if ( ! $config->getMetadataDriverImpl()) {
837
            throw ORMException::missingMappingDriverImpl();
838
        }
839
840 1268
        $connection = static::createConnection($connection, $config, $eventManager);
841
842 1267
        return new EntityManager($connection, $config, $connection->getEventManager());
843
    }
844
845
    /**
846
     * Factory method to create Connection 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 Connection
853
     *
854
     * @throws \InvalidArgumentException
855
     * @throws ORMException
856
     */
857 1268
    protected static function createConnection($connection, Configuration $config, EventManager $eventManager = null)
858
    {
859 1268
        if (is_array($connection)) {
860
            return DriverManager::getConnection($connection, $config, $eventManager ?: new EventManager());
861
        }
862
863 1268
        if ( ! $connection instanceof Connection) {
864 1
            throw new \InvalidArgumentException(
865 1
                sprintf(
866 1
                    'Invalid $connection argument of type %s given%s.',
867 1
                    is_object($connection) ? get_class($connection) : gettype($connection),
868 1
                    is_object($connection) ? '' : ': "' . $connection . '"'
869
                )
870
            );
871
        }
872
873 1267
        if ($eventManager !== null && $connection->getEventManager() !== $eventManager) {
874
            throw ORMException::mismatchedEventManager();
875
        }
876
877 1267
        return $connection;
878
    }
879
880
    /**
881
     * {@inheritDoc}
882
     */
883 633
    public function getFilters()
884
    {
885 633
        if (null === $this->filterCollection) {
886 633
            $this->filterCollection = new FilterCollection($this);
887
        }
888
889 633
        return $this->filterCollection;
890
    }
891
892
    /**
893
     * {@inheritDoc}
894
     */
895 40
    public function isFiltersStateClean()
896
    {
897 40
        return null === $this->filterCollection || $this->filterCollection->isClean();
898
    }
899
900
    /**
901
     * {@inheritDoc}
902
     */
903 760
    public function hasFilters()
904
    {
905 760
        return null !== $this->filterCollection;
906
    }
907
}
908