Completed
Push — siteaccessaware-layer-only ( edaec2...37e924 )
by André
22:17
created

AbstractHandler::getMultipleCacheItems()   B

Complexity

Conditions 9
Paths 41

Size

Total Lines 57
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 37
nc 41
nop 5
dl 0
loc 57
rs 7.0745
c 0
b 0
f 0

How to fix   Long Method   

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
 * File containing the ContentHandler implementation.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 */
9
namespace eZ\Publish\Core\Persistence\Cache;
10
11
use eZ\Publish\SPI\Persistence\Handler as PersistenceHandler;
12
use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface;
13
14
/**
15
 * Class AbstractHandler.
16
 *
17
 * Abstract handler for use in other Persistence Cache Handlers.
18
 */
19
abstract class AbstractHandler
20
{
21
    /**
22
     * @var \Symfony\Component\Cache\Adapter\TagAwareAdapterInterface
23
     */
24
    protected $cache;
25
26
    /**
27
     * @var \eZ\Publish\SPI\Persistence\Handler
28
     */
29
    protected $persistenceHandler;
30
31
    /**
32
     * @var \eZ\Publish\Core\Persistence\Cache\PersistenceLogger
33
     */
34
    protected $logger;
35
36
    /**
37
     * Setups current handler with everything needed.
38
     *
39
     * @param \Symfony\Component\Cache\Adapter\TagAwareAdapterInterface $cache
40
     * @param \eZ\Publish\SPI\Persistence\Handler $persistenceHandler
41
     * @param \eZ\Publish\Core\Persistence\Cache\PersistenceLogger $logger
42
     */
43
    public function __construct(
44
        TagAwareAdapterInterface $cache,
45
        PersistenceHandler $persistenceHandler,
46
        PersistenceLogger $logger
47
    ) {
48
        $this->cache = $cache;
49
        $this->persistenceHandler = $persistenceHandler;
50
        $this->logger = $logger;
51
    }
52
53
    /**
54
     * Helper for getting multiple cache items in one call and do the id extraction for you.
55
     *
56
     * Cache items must be stored with a key in the following format "${keyPrefix}${id}", like "ez-content-info-${id}",
57
     * in order for this method to be able to prefix key on id's and also extract key prefix afterwards.
58
     *
59
     * It also optionally supports a key suffix, for use on a variable argument that affects all lookups,
60
     * like translations, i.e. "ez-content-${id}-${translationKey}" where $keySuffix = "-${translationKey}".
61
     *
62
     * @param array $ids
63
     * @param string $keyPrefix E.g "ez-content-"
64
     * @param callable $missingLoader Function for loading missing objects, gets array with missing id's as argument,
65
     *                                expects return value to be array with id as key. Missing items should be missing.
66
     * @param callable $loadedTagger Function for tagging loaded object, gets object as argument, return array of tags.
67
     * @param array $keySuffixes Optional, key is id as provided in $ids, and value is a key suffix e.g. "-eng-Gb"
68
     *
69
     * @return array
70
     */
71
    final protected function getMultipleCacheItems(
72
        array $ids,
73
        string $keyPrefix,
74
        callable $missingLoader,
75
        callable $loadedTagger,
76
        array $keySuffixes = []
77
    ): array {
78
        if (empty($ids)) {
79
            return [];
80
        }
81
82
        // Generate unique cache keys
83
        $cacheKeys = [];
84
        foreach (array_unique($ids) as $id) {
85
            $cacheKeys[] = $keyPrefix . $id . ($keySuffixes[$id] ?? '');
86
        }
87
88
        // Load cache items by cache keys (will contain hits and misses)
89
        $list = [];
90
        $cacheMisses = [];
91
        $keyPrefixLength = strlen($keyPrefix);
92
        foreach ($this->cache->getItems($cacheKeys) as $key => $cacheItem) {
93
            $id = substr($key, $keyPrefixLength);
94
            if (!empty($keySuffixes)) {
95
                $id = explode('-', $id, 2)[0];
96
            }
97
98
            if ($cacheItem->isHit()) {
99
                $list[$id] = $cacheItem->get();
100
            } else {
101
                $cacheMisses[] = $id;
102
                $list[$id] = $cacheItem;
103
            }
104
        }
105
106
        // No misses, return completely cached list
107
        if (empty($cacheMisses)) {
108
            return $list;
109
        }
110
111
        // Load missing items, save to cache & apply to list if found
112
        $loadedList = $missingLoader($cacheMisses);
113
        foreach ($cacheMisses as $id) {
114
            if (isset($loadedList[$id])) {
115
                $this->cache->save(
116
                    $list[$id]
117
                        ->set($loadedList[$id])
118
                        ->tag($loadedTagger($loadedList[$id]))
119
                );
120
                $list[$id] = $loadedList[$id];
121
            } else {
122
                unset($list[$id]);
123
            }
124
        }
125
126
        return $list;
127
    }
128
}
129