LocalCacheAdapter   A
last analyzed

Complexity

Total Complexity 24

Size/Duplication

Total Lines 239
Duplicated Lines 0 %

Test Coverage

Coverage 45.83%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 24
eloc 45
c 1
b 0
f 0
dl 0
loc 239
ccs 22
cts 48
cp 0.4583
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
A removeCache() 0 12 3
A __construct() 0 3 1
A fromCache() 0 4 2
A cacheKey() 0 3 1
A flushCache() 0 5 1
A resolveReference() 0 10 2
A notCached() 0 3 1
A isCached() 0 3 1
A invalidateTags() 0 19 6
A addReference() 0 3 1
A toCache() 0 29 5
1
<?php
2
3
/**
4
 * TechDivision\Import\Cache\Collection\GenericCacheAdapter
5
 *
6
 * PHP version 7
7
 *
8
 * @author    Tim Wagner <[email protected]>
9
 * @copyright 2021 TechDivision GmbH <[email protected]>
10
 * @license   https://opensource.org/licenses/MIT
11
 * @link      https://github.com/techdivision/import-cache-collection
12
 * @link      http://www.techdivision.com
13
 */
14
15
namespace TechDivision\Import\Cache\Collection;
16
17
use TechDivision\Import\Cache\CacheAdapterInterface;
18
use TechDivision\Import\Cache\Utils\CacheKeyUtilInterface;
19
20
/**
21
 * Local cache adapter implementation.
22
 *
23
 * This cache adapter guarantees maximum performance but can eventually not be used
24
 * in a distributed environemnt where you want to use e. g. Redis for caching.
25
 *
26
 * If you are in a distributed environment, have a look at the GenericCacheAdapter
27
 * that can wrap any PSR-6 compatible cache implementations.
28
 *
29
 * @author    Tim Wagner <[email protected]>
30
 * @copyright 2021 TechDivision GmbH <[email protected]>
31
 * @license   https://opensource.org/licenses/MIT
32
 * @link      https://github.com/techdivision/import-cache-collection
33
 * @link      http://www.techdivision.com
34
 */
35
class LocalCacheAdapter implements CacheAdapterInterface
36
{
37
38
    /**
39
     * Trait that provides custom cache adapter functionality.
40
     *
41
     * @var \TechDivision\Import\Cache\Collection\CacheAdapterTrait
42
     */
43
    use CacheAdapterTrait;
44
45
    /**
46
     * The array with the tags.
47
     *
48
     * @var array
49
     */
50
    protected $tags = array();
51
52
    /**
53
     * The cache for the query results.
54
     *
55
     * @var array
56
     */
57
    protected $cache = array();
58
59
    /**
60
     * References that links to another cache entry.
61
     *
62
     * @var array
63
     */
64
    protected $references = array();
65
66
    /**
67
     * The cache key utility instance.
68
     *
69
     * @var \TechDivision\Import\Cache\Utils\CacheKeyUtilInterface
70
     */
71
    protected $cacheKeyUtil;
72
73
    /**
74
     * Initialize the cache handler with the passed cache and configuration instances.
75
     *
76
     * @param \TechDivision\Import\Cache\Utils\CacheKeyUtilInterface $cacheKeyUtil The cache key utility instance
77
     */
78 20
    public function __construct(CacheKeyUtilInterface $cacheKeyUtil)
79
    {
80 20
        $this->cacheKeyUtil = $cacheKeyUtil;
81
    }
82
83
    /**
84
     * Creates a unique cache key from the passed data.
85
     *
86
     * @param mixed   $data      The date to create the cache key from
87
     * @param boolean $usePrefix Flag to signal using the prefix or not
88
     *
89
     * @return string The generated cache key
90
     */
91 20
    public function cacheKey($data, $usePrefix = true)
92
    {
93 20
        return $this->cacheKeyUtil->cacheKey($data, $usePrefix);
94
    }
95
96
    /**
97
     * Query whether or not a cache value for the passed cache key is available.
98
     *
99
     * @param string $key The cache key to query for
100
     *
101
     * @return boolean TRUE if the a value is available, else FALSE
102
     */
103 20
    public function isCached($key)
104
    {
105 20
        return isset($this->cache[$this->resolveReference($this->cacheKey($key))]);
106
    }
107
108
    /**
109
     * Inversion of the isCached() method.
110
     *
111
     * @param string $key The cache key to query for
112
     *
113
     * @return boolean TRUE if the value is not available, else FALSE
114
     */
115
    public function notCached($key)
116
    {
117
        return !$this->isCached($key);
118
    }
119
120
    /**
121
     * Add's a cache reference from one key to another.
122
     *
123
     * @param string $from The key to reference from
124
     * @param string $to   The key to reference to
125
     *
126
     * @return void
127
     */
128 20
    public function addReference($from, $to)
129
    {
130 20
        $this->references[$this->cacheKey($from)] = $this->cacheKey($to);
131
    }
132
133
    /**
134
     * Resolve's the cache key.
135
     *
136
     * @param string $from The cache key to resolve
137
     *
138
     * @return string The resolved reference
139
     */
140 20
    protected function resolveReference($from)
141
    {
142
143
        // query whether or not a reference exists
144 20
        if (isset($this->references[$from])) {
145 20
            return $this->references[$from];
146
        }
147
148
        // return the passed reference
149 20
        return $from;
150
    }
151
152
    /**
153
     * Add the passed item to the cache.
154
     *
155
     * @param string  $key        The cache key to use
156
     * @param mixed   $value      The value that has to be cached
157
     * @param array   $references An array with references to add
158
     * @param array   $tags       An array with tags to add
159
     * @param boolean $override   Flag that allows to override an exising cache entry
160
     * @param integer $time       The TTL in seconds for the passed item
161
     *
162
     * @return void
163
     */
164 20
    public function toCache($key, $value, array $references = array(), array $tags = array(), $override = true, $time = null)
165
    {
166
167
        // query whether or not the key has already been used
168 20
        if (isset($this->cache[$this->resolveReference($uniqueKey = $this->cacheKey($key))]) && $override === false) {
169
            throw new \Exception(
170
                sprintf(
171
                    'Try to override data with key "%s"',
172
                    $uniqueKey
173
                )
174
            );
175
        }
176
177
        // set the attribute in the registry
178 20
        $this->cache[$uniqueKey] = $value;
179
180
        // prepend the tags with the cache key
181 20
        array_walk($tags, function (&$tag) {
182
            $tag = $this->cacheKey($tag);
183
        });
184
185
        // tag the unique key
186 20
        foreach ($tags as $tag) {
187
            $this->tags[$tag][] = $uniqueKey;
188
        }
189
190
        // also register the references if given
191 20
        foreach ($references as $from => $to) {
192 20
            $this->addReference($from, $to);
193
        }
194
    }
195
196
    /**
197
     * Returns a new cache item for the passed key
198
     *
199
     * @param string $key The cache key to return the item for
200
     *
201
     * @return mixed The value for the passed key
202
     */
203
    public function fromCache($key)
204
    {
205
        if (isset($this->cache[$uniqueKey = $this->resolveReference($this->cacheKey($key))])) {
206
            return $this->cache[$uniqueKey];
207
        }
208
    }
209
210
    /**
211
     * Flush the cache and remove the references.
212
     *
213
     * @return void
214
     */
215
    public function flushCache()
216
    {
217
        $this->tags = array();
218
        $this->cache = array();
219
        $this->references = array();
220
    }
221
222
    /**
223
     * Invalidate the cache entries for the passed tags.
224
     *
225
     * @param array $tags The tags to invalidate the cache for
226
     *
227
     * @return void
228
     */
229
    public function invalidateTags(array $tags)
230
    {
231
232
        // prepend the tags with the cache key
233
        array_walk($tags, function (&$tag) {
234
            $tag = $this->cacheKey($tag);
235
        });
236
237
        // remove all the references of items that has one of the passed tags
238
        foreach ($tags as $tag) {
239
            if (isset($this->tags[$tag])) {
240
                foreach ($this->tags[$tag] as $to) {
241
                    // clean-up the references that reference to the key
242
                    if ($from = array_search($to, $this->references)) {
243
                        unset($this->references[$from]);
244
                    }
245
                    // clean-up the cache entry itself
246
                    if (isset($this->cache[$to])) {
247
                        unset($this->cache[$to]);
248
                    }
249
                }
250
            }
251
        }
252
    }
253
254
    /**
255
     * Remove the item with the passed key and all its references from the cache.
256
     *
257
     * @param string $key               The key of the cache item to Remove
258
     * @param bool   $cleanUpReferences TRUE if the references has to be cleaned-up, else FALSE (default)
259
     *
260
     * @return void
261
     */
262 10
    public function removeCache($key, $cleanUpReferences = false)
263
    {
264 10
        unset($this->cache[$this->resolveReference($uniqueKey = $this->cacheKey($key))]);
265
266
        // query whether or not we've to clean-up references
267 10
        if ($cleanUpReferences === true) {
268
            // load the keys of the references we want to remove
269
            $references = array_keys($this->references, $uniqueKey);
270
271
            // remove ALL references to the passed unique key
272
            foreach ($references as $reference) {
273
                unset($this->references[$reference]);
274
            }
275
        }
276
    }
277
}
278