Passed
Push — master ( 0f35d9...62011e )
by Tim
03:47
created

LocalCacheAdapter::cacheKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 3
ccs 0
cts 3
cp 0
crap 2
rs 10
1
<?php
2
3
/**
4
 * TechDivision\Import\Cache\GenericCacheAdapter
5
 *
6
 * NOTICE OF LICENSE
7
 *
8
 * This source file is subject to the Open Software License (OSL 3.0)
9
 * that is available through the world-wide-web at this URL:
10
 * http://opensource.org/licenses/osl-3.0.php
11
 *
12
 * PHP version 5
13
 *
14
 * @author    Tim Wagner <[email protected]>
15
 * @copyright 2021 TechDivision GmbH <[email protected]>
16
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
 * @link      https://github.com/techdivision/import-cache
18
 * @link      http://www.techdivision.com
19
 */
20
21
namespace TechDivision\Import\Cache;
22
23
use TechDivision\Import\Cache\Utils\CacheKeyUtilInterface;
24
25
/**
26
 * Local cache adapter implementation.
27
 *
28
 * This cache adapter guarantees maximum performance but can eventually not be used
29
 * in a distributed environemnt where you want to use e. g. Redis for caching.
30
 *
31
 * If you are in a distributed environment, have a look at the GenericCacheAdapter
32
 * that can wrap any PSR-6 compatible cache implementations.
33
 *
34
 * @author    Tim Wagner <[email protected]>
35
 * @copyright 2021 TechDivision GmbH <[email protected]>
36
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
37
 * @link      https://github.com/techdivision/import-cache
38
 * @link      http://www.techdivision.com
39
 */
40
class LocalCacheAdapter implements CacheAdapterInterface
41
{
42
43
    /**
44
     * Trait that provides custom cache adapter functionality.
45
     *
46
     * @var TechDivision\Import\Cache\CacheAdapterTrait
47
     */
48
    use CacheAdapterTrait;
49
50
    /**
51
     * The array with the tags.
52
     *
53
     * @var array
54
     */
55
    protected $tags = array();
56
57
    /**
58
     * The cache for the query results.
59
     *
60
     * @var array
61
     */
62
    protected $cache = array();
63
64
    /**
65
     * References that links to another cache entry.
66
     *
67
     * @var array
68
     */
69
    protected $references = array();
70
71
    /**
72
     * The cache key utility instance.
73
     *
74
     * @var \TechDivision\Import\Utils\CacheKeyUtilInterface
75
     */
76
    protected $cacheKeyUtil;
77
78
    /**
79
     * Initialize the cache handler with the passed cache and configuration instances.
80
     *
81
     * @param \TechDivision\Import\Utils\CacheKeyUtilInterface $cacheKeyUtil The cache key utility instance
82
     */
83
    public function __construct(CacheKeyUtilInterface $cacheKeyUtil)
84
    {
85
        $this->cacheKeyUtil = $cacheKeyUtil;
0 ignored issues
show
Documentation Bug introduced by
It seems like $cacheKeyUtil of type TechDivision\Import\Cach...s\CacheKeyUtilInterface is incompatible with the declared type TechDivision\Import\Utils\CacheKeyUtilInterface of property $cacheKeyUtil.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
86
    }
87
88
    /**
89
     * Creates a unique cache key from the passed data.
90
     *
91
     * @param mixed   $data      The date to create the cache key from
92
     * @param boolean $usePrefix Flag to signal using the prefix or not
93
     *
94
     * @return string The generated cache key
95
     */
96
    public function cacheKey($data, $usePrefix = true)
97
    {
98
        return $this->cacheKeyUtil->cacheKey($data, $usePrefix);
99
    }
100
101
    /**
102
     * Query whether or not a cache value for the passed cache key is available.
103
     *
104
     * @param string $key The cache key to query for
105
     *
106
     * @return boolean TRUE if the a value is available, else FALSE
107
     */
108
    public function isCached($key)
109
    {
110
        return isset($this->cache[$this->resolveReference($this->cacheKey($key))]);
111
    }
112
113
    /**
114
     * Inversion of the isCached() method.
115
     *
116
     * @param string $key The cache key to query for
117
     *
118
     * @return boolean TRUE if the value is not available, else FALSE
119
     */
120
    public function notCached($key)
121
    {
122
        return !$this->isCached($key);
123
    }
124
125
    /**
126
     * Add's a cache reference from one key to another.
127
     *
128
     * @param string $from The key to reference from
129
     * @param string $to   The key to reference to
130
     *
131
     * @return void
132
     */
133
    public function addReference($from, $to)
134
    {
135
        $this->references[$this->cacheKey($from)] = $this->cacheKey($to);
136
    }
137
138
    /**
139
     * Resolve's the cache key.
140
     *
141
     * @param string $from The cache key to resolve
142
     *
143
     * @return string The resolved reference
144
     */
145
    protected function resolveReference($from)
146
    {
147
148
        // query whether or not a reference exists
149
        if (isset($this->references[$from])) {
150
            return $this->references[$from];
151
        }
152
153
        // return the passed reference
154
        return $from;
155
    }
156
157
    /**
158
     * Add the passed item to the cache.
159
     *
160
     * @param string  $key        The cache key to use
161
     * @param mixed   $value      The value that has to be cached
162
     * @param array   $references An array with references to add
163
     * @param array   $tags       An array with tags to add
164
     * @param boolean $override   Flag that allows to override an exising cache entry
165
     * @param integer $time       The TTL in seconds for the passed item
166
     *
167
     * @return void
168
     */
169
    public function toCache($key, $value, array $references = array(), array $tags = array(), $override = true, $time = null)
170
    {
171
172
        // query whether or not the key has already been used
173
        if (isset($this->cache[$this->resolveReference($uniqueKey = $this->cacheKey($key))]) && $override === false) {
174
            throw new \Exception(
175
                sprintf(
176
                    'Try to override data with key "%s"',
177
                    $uniqueKey
178
                )
179
            );
180
        }
181
182
        // set the attribute in the registry
183
        $this->cache[$uniqueKey] = $value;
184
185
        // prepend the tags with the cache key
186
        array_walk($tags, function (&$tag) {
187
            $tag = $this->cacheKey($tag);
188
        });
189
190
        // tag the unique key
191
        foreach ($tags as $tag) {
192
            $this->tags[$tag][] = $uniqueKey;
193
        }
194
195
        // also register the references if given
196
        foreach ($references as $from => $to) {
197
            $this->addReference($from, $to);
198
        }
199
    }
200
201
    /**
202
     * Returns a new cache item for the passed key
203
     *
204
     * @param string $key The cache key to return the item for
205
     *
206
     * @return mixed The value for the passed key
207
     */
208
    public function fromCache($key)
209
    {
210
        if (isset($this->cache[$uniqueKey = $this->resolveReference($this->cacheKey($key))])) {
211
            return $this->cache[$uniqueKey];
212
        }
213
    }
214
215
    /**
216
     * Flush the cache and remove the references.
217
     *
218
     * @return void
219
     */
220
    public function flushCache()
221
    {
222
        $this->tags = array();
223
        $this->cache = array();
224
        $this->references = array();
225
    }
226
227
    /**
228
     * Invalidate the cache entries for the passed tags.
229
     *
230
     * @param array $tags The tags to invalidate the cache for
231
     *
232
     * @return void
233
     */
234
    public function invalidateTags(array $tags)
235
    {
236
237
        // prepend the tags with the cache key
238
        array_walk($tags, function (&$tag) {
239
            $tag = $this->cacheKey($tag);
240
        });
241
242
        // remove all the references of items that has one of the passed tags
243
        foreach ($tags as $tag) {
244
            if (isset($this->tags[$tag])) {
245
                foreach ($this->tags[$tag] as $to) {
246
                    // clean-up the references that reference to the key
247
                    if ($from = array_search($to, $this->references)) {
248
                        unset($this->references[$from]);
249
                    }
250
                    // clean-up the cache entry itself
251
                    if (isset($this->cache[$to])) {
252
                        unset($this->cache[$to]);
253
                    }
254
                }
255
            }
256
        }
257
    }
258
259
    /**
260
     * Remove the item with the passed key and all its references from the cache.
261
     *
262
     * @param string $key               The key of the cache item to Remove
263
     * @param bool   $cleanUpReferences TRUE if the references has to be cleaned-up, else FALSE (default)
264
     *
265
     * @return void
266
     */
267
    public function removeCache($key, $cleanUpReferences = false)
268
    {
269
        unset($this->cache[$this->resolveReference($uniqueKey = $this->cacheKey($key))]);
270
271
        // query whether or not we've to clean-up references
272
        if ($cleanUpReferences === true) {
273
            // load the keys of the references we want to remove
274
            $references = array_keys($this->references, $uniqueKey);
275
276
            // remove ALL references to the passed unique key
277
            foreach ($references as $reference) {
278
                unset($this->references[$reference]);
279
            }
280
        }
281
    }
282
}
283