Completed
Push — master ( acfc89...61404e )
by Marco
24:31 queued 15:11
created

DefaultQueryCache::get()   F

Complexity

Conditions 26
Paths 412

Size

Total Lines 150
Code Lines 74

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 75
CRAP Score 26.0015

Importance

Changes 0
Metric Value
dl 0
loc 150
ccs 75
cts 76
cp 0.9868
rs 3.4723
c 0
b 0
f 0
cc 26
eloc 74
nc 412
nop 3
crap 26.0015

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Common\Collections\ArrayCollection;
24
use Doctrine\ORM\Cache\Persister\CachedPersister;
25
use Doctrine\ORM\EntityManagerInterface;
26
use Doctrine\ORM\Query\ResultSetMapping;
27
use Doctrine\ORM\Mapping\ClassMetadata;
28
use Doctrine\ORM\PersistentCollection;
29
use Doctrine\Common\Proxy\Proxy;
30
use Doctrine\ORM\Cache;
31
use Doctrine\ORM\Query;
32
33
/**
34
 * Default query cache implementation.
35
 *
36
 * @since   2.5
37
 * @author  Fabio B. Silva <[email protected]>
38
 */
39
class DefaultQueryCache implements QueryCache
40
{
41
     /**
42
     * @var \Doctrine\ORM\EntityManagerInterface
43
     */
44
    private $em;
45
46
    /**
47
     * @var \Doctrine\ORM\UnitOfWork
48
     */
49
    private $uow;
50
51
    /**
52
     * @var \Doctrine\ORM\Cache\Region
53
     */
54
    private $region;
55
56
    /**
57
     * @var \Doctrine\ORM\Cache\QueryCacheValidator
58
     */
59
    private $validator;
60
61
    /**
62
     * @var \Doctrine\ORM\Cache\Logging\CacheLogger
63
     */
64
    protected $cacheLogger;
65
66
    /**
67
     * @var array
68
     */
69
    private static $hints = [Query::HINT_CACHE_ENABLED => true];
70
71
    /**
72
     * @param \Doctrine\ORM\EntityManagerInterface $em     The entity manager.
73
     * @param \Doctrine\ORM\Cache\Region           $region The query region.
74
     */
75 86
    public function __construct(EntityManagerInterface $em, Region $region)
76
    {
77 86
        $cacheConfig = $em->getConfiguration()->getSecondLevelCacheConfiguration();
78
79 86
        $this->em           = $em;
80 86
        $this->region       = $region;
81 86
        $this->uow          = $em->getUnitOfWork();
82 86
        $this->cacheLogger  = $cacheConfig->getCacheLogger();
83 86
        $this->validator    = $cacheConfig->getQueryValidator();
84 86
    }
85
86
    /**
87
     * {@inheritdoc}
88
     */
89 52
    public function get(QueryCacheKey $key, ResultSetMapping $rsm, array $hints = [])
90
    {
91 52
        if ( ! ($key->cacheMode & Cache::MODE_GET)) {
92 3
            return null;
93
        }
94
95 51
        $cacheEntry = $this->region->get($key);
96
97 51
        if ( ! $cacheEntry instanceof QueryCacheEntry) {
98 47
            return null;
99
        }
100
101 38
        if ( ! $this->validator->isValid($key, $cacheEntry)) {
102 8
            $this->region->evict($key);
103
104 8
            return null;
105
        }
106
107 33
        $result      = [];
108 33
        $entityName  = reset($rsm->aliasMap);
109 33
        $hasRelation = ( ! empty($rsm->relationMap));
110 33
        $persister   = $this->uow->getEntityPersister($entityName);
111 33
        $region      = $persister->getCacheRegion();
112 33
        $regionName  = $region->getName();
113
114 33
        $cm = $this->em->getClassMetadata($entityName);
115
116 33
        $generateKeys = function (array $entry) use ($cm): EntityCacheKey {
117 33
            return new EntityCacheKey($cm->rootEntityName, $entry['identifier']);
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...
118 33
        };
119
120 33
        $cacheKeys = new CollectionCacheEntry(array_map($generateKeys, $cacheEntry->result));
121 33
        $entries   = $region->getMultiple($cacheKeys);
122
123
        // @TODO - move to cache hydration component
124 33
        foreach ($cacheEntry->result as $index => $entry) {
125 33
            $entityEntry = is_array($entries) && array_key_exists($index, $entries) ? $entries[$index] : null;
126
127 33
            if ($entityEntry === null) {
128 2
                if ($this->cacheLogger !== null) {
129 1
                    $this->cacheLogger->entityCacheMiss($regionName, $cacheKeys->identifiers[$index]);
0 ignored issues
show
Compatibility introduced by
$cacheKeys->identifiers[$index] of type object<Doctrine\ORM\Cache\CacheKey> is not a sub-type of object<Doctrine\ORM\Cache\EntityCacheKey>. It seems like you assume a child class of the class Doctrine\ORM\Cache\CacheKey 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...
130
                }
131
132 2
                return null;
133
            }
134
135 31
            if ($this->cacheLogger !== null) {
136 29
                $this->cacheLogger->entityCacheHit($regionName, $cacheKeys->identifiers[$index]);
0 ignored issues
show
Compatibility introduced by
$cacheKeys->identifiers[$index] of type object<Doctrine\ORM\Cache\CacheKey> is not a sub-type of object<Doctrine\ORM\Cache\EntityCacheKey>. It seems like you assume a child class of the class Doctrine\ORM\Cache\CacheKey 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...
137
            }
138
139 31
            if ( ! $hasRelation) {
140 22
                $result[$index]  = $this->uow->createEntity($entityEntry->class, $entityEntry->resolveAssociationEntries($this->em), self::$hints);
141
142 22
                continue;
143
            }
144
145 9
            $data = $entityEntry->data;
146
147 9
            foreach ($entry['associations'] as $name => $assoc) {
148 9
                $assocPersister  = $this->uow->getEntityPersister($assoc['targetEntity']);
149 9
                $assocRegion     = $assocPersister->getCacheRegion();
150 9
                $assocMetadata   = $this->em->getClassMetadata($assoc['targetEntity']);
151
152 9
                if ($assoc['type'] & ClassMetadata::TO_ONE) {
153
154 5
                    if (($assocEntry = $assocRegion->get($assocKey = new EntityCacheKey($assocMetadata->rootEntityName, $assoc['identifier']))) === null) {
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...
155
156 1
                        if ($this->cacheLogger !== null) {
157 1
                            $this->cacheLogger->entityCacheMiss($assocRegion->getName(), $assocKey);
158
                        }
159
160 1
                        $this->uow->hydrationComplete();
161
162 1
                        return null;
163
                    }
164
165 4
                    $data[$name] = $this->uow->createEntity($assocEntry->class, $assocEntry->resolveAssociationEntries($this->em), self::$hints);
166
167 4
                    if ($this->cacheLogger !== null) {
168 4
                        $this->cacheLogger->entityCacheHit($assocRegion->getName(), $assocKey);
169
                    }
170
171 4
                    continue;
172
                }
173
174 4
                if ( ! isset($assoc['list']) || empty($assoc['list'])) {
175
                    continue;
176
                }
177
178 4
                $generateKeys = function ($id) use ($assocMetadata): EntityCacheKey {
179 4
                    return new EntityCacheKey($assocMetadata->rootEntityName, $id);
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...
180 4
                };
181
182 4
                $collection   = new PersistentCollection($this->em, $assocMetadata, new ArrayCollection());
0 ignored issues
show
Compatibility introduced by
$assocMetadata 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...
183 4
                $assocKeys    = new CollectionCacheEntry(array_map($generateKeys, $assoc['list']));
184 4
                $assocEntries = $assocRegion->getMultiple($assocKeys);
185
186 4
                foreach ($assoc['list'] as $assocIndex => $assocId) {
187 4
                    $assocEntry = is_array($assocEntries) && array_key_exists($assocIndex, $assocEntries) ? $assocEntries[$assocIndex] : null;
188
189 4
                    if ($assocEntry === null) {
190 1
                        if ($this->cacheLogger !== null) {
191 1
                            $this->cacheLogger->entityCacheMiss($assocRegion->getName(), $assocKeys->identifiers[$assocIndex]);
0 ignored issues
show
Compatibility introduced by
$assocKeys->identifiers[$assocIndex] of type object<Doctrine\ORM\Cache\CacheKey> is not a sub-type of object<Doctrine\ORM\Cache\EntityCacheKey>. It seems like you assume a child class of the class Doctrine\ORM\Cache\CacheKey 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...
192
                        }
193
194 1
                        $this->uow->hydrationComplete();
195
196 1
                        return null;
197
                    }
198
199 3
                    $element = $this->uow->createEntity($assocEntry->class, $assocEntry->resolveAssociationEntries($this->em), self::$hints);
200
201 3
                    $collection->hydrateSet($assocIndex, $element);
202
203 3
                    if ($this->cacheLogger !== null) {
204 3
                        $this->cacheLogger->entityCacheHit($assocRegion->getName(), $assocKeys->identifiers[$assocIndex]);
0 ignored issues
show
Compatibility introduced by
$assocKeys->identifiers[$assocIndex] of type object<Doctrine\ORM\Cache\CacheKey> is not a sub-type of object<Doctrine\ORM\Cache\EntityCacheKey>. It seems like you assume a child class of the class Doctrine\ORM\Cache\CacheKey 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...
205
                    }
206
                }
207
208 3
                $data[$name] = $collection;
209
210 3
                $collection->setInitialized(true);
211
            }
212
213 7
            foreach ($data as $fieldName => $unCachedAssociationData) {
214
                // In some scenarios, such as EAGER+ASSOCIATION+ID+CACHE, the
215
                // cache key information in `$cacheEntry` will not contain details
216
                // for fields that are associations.
217
                //
218
                // This means that `$data` keys for some associations that may
219
                // actually not be cached will not be converted to actual association
220
                // data, yet they contain L2 cache AssociationCacheEntry objects.
221
                //
222
                // We need to unwrap those associations into proxy references,
223
                // since we don't have actual data for them except for identifiers.
224 7
                if ($unCachedAssociationData instanceof AssociationCacheEntry) {
225 4
                    $data[$fieldName] = $this->em->getReference(
226 4
                        $unCachedAssociationData->class,
227 7
                        $unCachedAssociationData->identifier
228
                    );
229
                }
230
            }
231
232 7
            $result[$index] = $this->uow->createEntity($entityEntry->class, $data, self::$hints);
233
        }
234
235 29
        $this->uow->hydrationComplete();
236
237 29
        return $result;
238
    }
239
240
    /**
241
     * {@inheritdoc}
242
     */
243 58
    public function put(QueryCacheKey $key, ResultSetMapping $rsm, $result, array $hints = [])
244
    {
245 58
        if ($rsm->scalarMappings) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $rsm->scalarMappings 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...
246 1
            throw new CacheException("Second level cache does not support scalar results.");
247
        }
248
249 57
        if (count($rsm->entityMappings) > 1) {
250 1
            throw new CacheException("Second level cache does not support multiple root entities.");
251
        }
252
253 56
        if ( ! $rsm->isSelect) {
254 2
            throw new CacheException("Second-level cache query supports only select statements.");
255
        }
256
257 54
        if (isset($hints[Query::HINT_FORCE_PARTIAL_LOAD]) && $hints[Query::HINT_FORCE_PARTIAL_LOAD]) {
258 1
            throw new CacheException("Second level cache does not support partial entities.");
259
        }
260
261 53
        if ( ! ($key->cacheMode & Cache::MODE_PUT)) {
262 3
            return false;
263
        }
264
265 52
        $data        = [];
266 52
        $entityName  = reset($rsm->aliasMap);
267 52
        $rootAlias   = key($rsm->aliasMap);
268 52
        $persister   = $this->uow->getEntityPersister($entityName);
269
270 52
        if ( ! ($persister instanceof CachedPersister)) {
271 1
            throw CacheException::nonCacheableEntity($entityName);
272
        }
273
274 51
        $region = $persister->getCacheRegion();
275
276 51
        foreach ($result as $index => $entity) {
277 51
            $identifier                     = $this->uow->getEntityIdentifier($entity);
278 51
            $entityKey                      = new EntityCacheKey($entityName, $identifier);
279
280 51
            if (($key->cacheMode & Cache::MODE_REFRESH) || ! $region->contains($entityKey)) {
281
                // Cancel put result if entity put fail
282 36
                if ( ! $persister->storeEntityCache($entity, $entityKey)) {
283 1
                    return false;
284
                }
285
            }
286
287 50
            $data[$index]['identifier']   = $identifier;
288 50
            $data[$index]['associations'] = [];
289
290
            // @TODO - move to cache hydration components
291 50
            foreach ($rsm->relationMap as $alias => $name) {
292 15
                $parentAlias  = $rsm->parentAliasMap[$alias];
293 15
                $parentClass  = $rsm->aliasMap[$parentAlias];
294 15
                $metadata     = $this->em->getClassMetadata($parentClass);
295 15
                $assoc        = $metadata->associationMappings[$name];
0 ignored issues
show
Bug introduced by
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...
296 15
                $assocValue   = $this->getAssociationValue($rsm, $alias, $entity);
297
298 15
                if ($assocValue === null) {
299 1
                    continue;
300
                }
301
302
                // root entity association
303 14
                if ($rootAlias === $parentAlias) {
304
                    // Cancel put result if association put fail
305 14
                    if ( ($assocInfo = $this->storeAssociationCache($key, $assoc, $assocValue)) === null) {
306 2
                        return false;
307
                    }
308
309 12
                    $data[$index]['associations'][$name] = $assocInfo;
310
311 12
                    continue;
312
                }
313
314
                // store single nested association
315 2
                if ( ! is_array($assocValue)) {
316
                    // Cancel put result if association put fail
317 1
                    if ($this->storeAssociationCache($key, $assoc, $assocValue) === null) {
318
                        return false;
319
                    }
320
321 1
                    continue;
322
                }
323
324
                // store array of nested association
325 1
                foreach ($assocValue as $aVal) {
326
                    // Cancel put result if association put fail
327 1
                    if ($this->storeAssociationCache($key, $assoc, $aVal) === null) {
328 48
                        return false;
329
                    }
330
                }
331
            }
332
        }
333
334 48
        return $this->region->put($key, new QueryCacheEntry($data));
335
    }
336
337
    /**
338
     * @param \Doctrine\ORM\Cache\QueryCacheKey $key
339
     * @param array                             $assoc
340
     * @param mixed                             $assocValue
341
     *
342
     * @return array|null
343
     */
344 14
    private function storeAssociationCache(QueryCacheKey $key, array $assoc, $assocValue)
345
    {
346 14
        $assocPersister = $this->uow->getEntityPersister($assoc['targetEntity']);
347 14
        $assocMetadata  = $assocPersister->getClassMetadata();
348 14
        $assocRegion    = $assocPersister->getCacheRegion();
349
350
        // Handle *-to-one associations
351 14
        if ($assoc['type'] & ClassMetadata::TO_ONE) {
352 8
            $assocIdentifier = $this->uow->getEntityIdentifier($assocValue);
353 8
            $entityKey       = new EntityCacheKey($assocMetadata->rootEntityName, $assocIdentifier);
354
355 8
            if ( ! $assocValue instanceof Proxy && ($key->cacheMode & Cache::MODE_REFRESH) || ! $assocRegion->contains($entityKey)) {
356
                // Entity put fail
357 7
                if ( ! $assocPersister->storeEntityCache($assocValue, $entityKey)) {
358 1
                    return null;
359
                }
360
            }
361
362
            return [
363 7
                'targetEntity'  => $assocMetadata->rootEntityName,
364 7
                'identifier'    => $assocIdentifier,
365 7
                'type'          => $assoc['type']
366
            ];
367
        }
368
369
        // Handle *-to-many associations
370 6
        $list = [];
371
372 6
        foreach ($assocValue as $assocItemIndex => $assocItem) {
373 6
            $assocIdentifier = $this->uow->getEntityIdentifier($assocItem);
374 6
            $entityKey       = new EntityCacheKey($assocMetadata->rootEntityName, $assocIdentifier);
375
376 6
            if (($key->cacheMode & Cache::MODE_REFRESH) || ! $assocRegion->contains($entityKey)) {
377
                // Entity put fail
378 6
                if ( ! $assocPersister->storeEntityCache($assocItem, $entityKey)) {
379 1
                    return null;
380
                }
381
            }
382
383 5
            $list[$assocItemIndex] = $assocIdentifier;
384
        }
385
386
        return [
387 5
            'targetEntity'  => $assocMetadata->rootEntityName,
388 5
            'type'          => $assoc['type'],
389 5
            'list'          => $list,
390
        ];
391
    }
392
393
    /**
394
     * @param \Doctrine\ORM\Query\ResultSetMapping $rsm
395
     * @param string                               $assocAlias
396
     * @param object                               $entity
397
     *
398
     * @return array|object
399
     */
400 16
    private function getAssociationValue(ResultSetMapping $rsm, $assocAlias, $entity)
401
    {
402 16
        $path  = [];
403 16
        $alias = $assocAlias;
404
405 16
        while (isset($rsm->parentAliasMap[$alias])) {
406 16
            $parent = $rsm->parentAliasMap[$alias];
407 16
            $field  = $rsm->relationMap[$alias];
408 16
            $class  = $rsm->aliasMap[$parent];
409
410 16
            array_unshift($path, [
411 16
                'field'  => $field,
412 16
                'class'  => $class
413
            ]
414
            );
415
416 16
            $alias = $parent;
417
        }
418
419 16
        return $this->getAssociationPathValue($entity, $path);
420
    }
421
422
    /**
423
     * @param mixed $value
424
     * @param array $path
425
     *
426
     * @return array|object|null
427
     */
428 16
    private function getAssociationPathValue($value, array $path)
429
    {
430 16
        $mapping  = array_shift($path);
431 16
        $metadata = $this->em->getClassMetadata($mapping['class']);
432 16
        $assoc    = $metadata->associationMappings[$mapping['field']];
0 ignored issues
show
Bug introduced by
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...
433 16
        $value    = $metadata->getFieldValue($value, $mapping['field']);
434
435 16
        if ($value === null) {
436 1
            return null;
437
        }
438
439 15
        if (empty($path)) {
440 15
            return $value;
441
        }
442
443
        // Handle *-to-one associations
444 3
        if ($assoc['type'] & ClassMetadata::TO_ONE) {
445 1
            return $this->getAssociationPathValue($value, $path);
446
        }
447
448 2
        $values = [];
449
450 2
        foreach ($value as $item) {
451 2
            $values[] = $this->getAssociationPathValue($item, $path);
452
        }
453
454 2
        return $values;
455
    }
456
457
    /**
458
     * {@inheritdoc}
459
     */
460 48
    public function clear()
461
    {
462 48
        return $this->region->evictAll();
463
    }
464
465
    /**
466
     * {@inheritdoc}
467
     */
468 28
    public function getRegion()
469
    {
470 28
        return $this->region;
471
    }
472
}
473