Failed Conditions
Push — master ( 2ade86...13f838 )
by Jonathan
18s
created

lib/Doctrine/ORM/Cache/DefaultCache.php (11 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
6
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
7
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
8
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
11
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
12
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
13
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
14
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15
 *
16
 * This software consists of voluntary contributions made by many individuals
17
 * and is licensed under the MIT license. For more information, see
18
 * <http://www.doctrine-project.org>.
19
 */
20
21
namespace Doctrine\ORM\Cache;
22
23
use Doctrine\ORM\Cache;
24
use Doctrine\Common\Util\ClassUtils;
25
use Doctrine\ORM\Mapping\ClassMetadata;
26
use Doctrine\ORM\EntityManagerInterface;
27
use Doctrine\ORM\Cache\Persister\CachedPersister;
28
use Doctrine\ORM\ORMInvalidArgumentException;
29
30
/**
31
 * Provides an API for querying/managing the second level cache regions.
32
 *
33
 * @since   2.5
34
 * @author  Fabio B. Silva <[email protected]>
35
 */
36
class DefaultCache implements Cache
37
{
38
    /**
39
     * @var \Doctrine\ORM\EntityManagerInterface
40
     */
41
    private $em;
42
43
    /**
44
     * @var \Doctrine\ORM\UnitOfWork
45
     */
46
    private $uow;
47
48
     /**
49
     * @var \Doctrine\ORM\Cache\CacheFactory
50
     */
51
    private $cacheFactory;
52
53
    /**
54
     * @var \Doctrine\ORM\Cache\QueryCache[]
55
     */
56
    private $queryCaches = [];
57
58
    /**
59
     * @var \Doctrine\ORM\Cache\QueryCache
60
     */
61
    private $defaultQueryCache;
62
63
    /**
64
     * {@inheritdoc}
65
     */
66 285
    public function __construct(EntityManagerInterface $em)
67
    {
68 285
        $this->em           = $em;
69 285
        $this->uow          = $em->getUnitOfWork();
70 285
        $this->cacheFactory = $em->getConfiguration()
71 285
            ->getSecondLevelCacheConfiguration()
72 285
            ->getCacheFactory();
73 285
    }
74
75
    /**
76
     * {@inheritdoc}
77
     */
78 25
    public function getEntityCacheRegion($className)
79
    {
80 25
        $metadata  = $this->em->getClassMetadata($className);
81 25
        $persister = $this->uow->getEntityPersister($metadata->rootEntityName);
0 ignored issues
show
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...
82
83 25
        if ( ! ($persister instanceof CachedPersister)) {
84 5
            return null;
85
        }
86
87 25
        return $persister->getCacheRegion();
88
    }
89
90
    /**
91
     * {@inheritdoc}
92
     */
93 6 View Code Duplication
    public function getCollectionCacheRegion($className, $association)
94
    {
95 6
        $metadata  = $this->em->getClassMetadata($className);
96 6
        $persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association));
97
98 6
        if ( ! ($persister instanceof CachedPersister)) {
99 1
            return null;
100
        }
101
102 6
        return $persister->getCacheRegion();
103
    }
104
105
    /**
106
     * {@inheritdoc}
107
     */
108 68
    public function containsEntity($className, $identifier)
109
    {
110 68
        $metadata   = $this->em->getClassMetadata($className);
111 68
        $persister  = $this->uow->getEntityPersister($metadata->rootEntityName);
0 ignored issues
show
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...
112
113 68
        if ( ! ($persister instanceof CachedPersister)) {
114 4
            return false;
115
        }
116
117 68
        return $persister->getCacheRegion()->contains($this->buildEntityCacheKey($metadata, $identifier));
0 ignored issues
show
$metadata of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
118
    }
119
120
    /**
121
     * {@inheritdoc}
122
     */
123 4
    public function evictEntity($className, $identifier)
124
    {
125 4
        $metadata  = $this->em->getClassMetadata($className);
126 4
        $persister = $this->uow->getEntityPersister($metadata->rootEntityName);
0 ignored issues
show
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...
127
128 4
        if ( ! ($persister instanceof CachedPersister)) {
129 1
            return;
130
        }
131
132 4
        $persister->getCacheRegion()->evict($this->buildEntityCacheKey($metadata, $identifier));
0 ignored issues
show
$metadata of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
133 4
    }
134
135
    /**
136
     * {@inheritdoc}
137
     */
138 29 View Code Duplication
    public function evictEntityRegion($className)
139
    {
140 29
        $metadata  = $this->em->getClassMetadata($className);
141 29
        $persister = $this->uow->getEntityPersister($metadata->rootEntityName);
0 ignored issues
show
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...
142
143 29
        if ( ! ($persister instanceof CachedPersister)) {
144 2
            return;
145
        }
146
147 29
        $persister->getCacheRegion()->evictAll();
148 29
    }
149
150
    /**
151
     * {@inheritdoc}
152
     */
153 48
    public function evictEntityRegions()
154
    {
155 48
        $metadatas = $this->em->getMetadataFactory()->getAllMetadata();
156
157 48
        foreach ($metadatas as $metadata) {
158 48
            $persister = $this->uow->getEntityPersister($metadata->rootEntityName);
0 ignored issues
show
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...
159
160 48
            if ( ! ($persister instanceof CachedPersister)) {
161 48
                continue;
162
            }
163
164 48
            $persister->getCacheRegion()->evictAll();
165
        }
166 48
    }
167
168
    /**
169
     * {@inheritdoc}
170
     */
171 18 View Code Duplication
    public function containsCollection($className, $association, $ownerIdentifier)
172
    {
173 18
        $metadata  = $this->em->getClassMetadata($className);
174 18
        $persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association));
175
176 18
        if ( ! ($persister instanceof CachedPersister)) {
177 1
            return false;
178
        }
179
180 18
        return $persister->getCacheRegion()->contains($this->buildCollectionCacheKey($metadata, $association, $ownerIdentifier));
0 ignored issues
show
$metadata of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
181
    }
182
183
    /**
184
     * {@inheritdoc}
185
     */
186 2 View Code Duplication
    public function evictCollection($className, $association, $ownerIdentifier)
187
    {
188 2
        $metadata  = $this->em->getClassMetadata($className);
189 2
        $persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association));
190
191 2
        if ( ! ($persister instanceof CachedPersister)) {
192 1
            return;
193
        }
194
195 2
        $persister->getCacheRegion()->evict($this->buildCollectionCacheKey($metadata, $association, $ownerIdentifier));
0 ignored issues
show
$metadata of type object<Doctrine\Common\P...\Mapping\ClassMetadata> is not a sub-type of object<Doctrine\ORM\Mapping\ClassMetadata>. It seems like you assume a concrete implementation of the interface Doctrine\Common\Persistence\Mapping\ClassMetadata to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
196 2
    }
197
198
    /**
199
     * {@inheritdoc}
200
     */
201 9 View Code Duplication
    public function evictCollectionRegion($className, $association)
202
    {
203 9
        $metadata  = $this->em->getClassMetadata($className);
204 9
        $persister = $this->uow->getCollectionPersister($metadata->getAssociationMapping($association));
205
206 9
        if ( ! ($persister instanceof CachedPersister)) {
207 1
            return;
208
        }
209
210 9
        $persister->getCacheRegion()->evictAll();
211 9
    }
212
213
    /**
214
     * {@inheritdoc}
215
     */
216 46
    public function evictCollectionRegions()
217
    {
218 46
        $metadatas = $this->em->getMetadataFactory()->getAllMetadata();
219
220 46
        foreach ($metadatas as $metadata) {
221
222 46
            foreach ($metadata->associationMappings as $association) {
0 ignored issues
show
Accessing associationMappings 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...
223
224 46
                if ( ! $association['type'] & ClassMetadata::TO_MANY) {
225
                    continue;
226
                }
227
228 46
                $persister = $this->uow->getCollectionPersister($association);
229
230 46
                if ( ! ($persister instanceof CachedPersister)) {
231 46
                    continue;
232
                }
233
234 46
                $persister->getCacheRegion()->evictAll();
235
            }
236
        }
237 46
    }
238
239
    /**
240
     * {@inheritdoc}
241
     */
242 1
    public function containsQuery($regionName)
243
    {
244 1
        return isset($this->queryCaches[$regionName]);
245
    }
246
247
    /**
248
     * {@inheritdoc}
249
     */
250 3
    public function evictQueryRegion($regionName = null)
251
    {
252 3
        if ($regionName === null && $this->defaultQueryCache !== null) {
253 1
            $this->defaultQueryCache->clear();
254
255 1
            return;
256
        }
257
258 3
        if (isset($this->queryCaches[$regionName])) {
259 1
            $this->queryCaches[$regionName]->clear();
260
        }
261 3
    }
262
263
    /**
264
     * {@inheritdoc}
265
     */
266 47
    public function evictQueryRegions()
267
    {
268 47
        $this->getQueryCache()->clear();
269
270 47
        foreach ($this->queryCaches as $queryCache) {
271 1
            $queryCache->clear();
272
        }
273 47
    }
274
275
    /**
276
     * {@inheritdoc}
277
     */
278 64
    public function getQueryCache($regionName = null)
279
    {
280 64
        if ($regionName === null) {
281 60
            return $this->defaultQueryCache ?:
282 60
                $this->defaultQueryCache = $this->cacheFactory->buildQueryCache($this->em);
283
        }
284
285 14
        if ( ! isset($this->queryCaches[$regionName])) {
286 14
            $this->queryCaches[$regionName] = $this->cacheFactory->buildQueryCache($this->em, $regionName);
287
        }
288
289 14
        return $this->queryCaches[$regionName];
290
    }
291
292
     /**
293
     * @param \Doctrine\ORM\Mapping\ClassMetadata $metadata   The entity metadata.
294
     * @param mixed                               $identifier The entity identifier.
295
     *
296
     * @return \Doctrine\ORM\Cache\EntityCacheKey
297
     */
298 69 View Code Duplication
    private function buildEntityCacheKey(ClassMetadata $metadata, $identifier)
299
    {
300 69
        if ( ! is_array($identifier)) {
301 67
            $identifier = $this->toIdentifierArray($metadata, $identifier);
302
        }
303
304 69
        return new EntityCacheKey($metadata->rootEntityName, $identifier);
305
    }
306
307
    /**
308
     * @param \Doctrine\ORM\Mapping\ClassMetadata $metadata        The entity metadata.
309
     * @param string                              $association     The field name that represents the association.
310
     * @param mixed                               $ownerIdentifier The identifier of the owning entity.
311
     *
312
     * @return \Doctrine\ORM\Cache\CollectionCacheKey
313
     */
314 19 View Code Duplication
    private function buildCollectionCacheKey(ClassMetadata $metadata, $association, $ownerIdentifier)
315
    {
316 19
        if ( ! is_array($ownerIdentifier)) {
317 19
            $ownerIdentifier = $this->toIdentifierArray($metadata, $ownerIdentifier);
318
        }
319
320 19
        return new CollectionCacheKey($metadata->rootEntityName, $association, $ownerIdentifier);
321
    }
322
323
    /**
324
     * @param \Doctrine\ORM\Mapping\ClassMetadata $metadata   The entity metadata.
325
     * @param mixed                               $identifier The entity identifier.
326
     *
327
     * @return array
328
     */
329 74
    private function toIdentifierArray(ClassMetadata $metadata, $identifier)
330
    {
331 74 View Code Duplication
        if (is_object($identifier) && $this->em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($identifier))) {
0 ignored issues
show
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...
332
            $identifier = $this->uow->getSingleIdentifierValue($identifier);
333
334
            if ($identifier === null) {
335
                throw ORMInvalidArgumentException::invalidIdentifierBindingEntity();
336
            }
337
        }
338
339 74
        return [$metadata->identifier[0] => $identifier];
340
    }
341
342
}
343