Completed
Pull Request — 11.x (#154)
by Tim
05:15
created

LocalCacheAdapter::toCache()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 0
loc 31
ccs 0
cts 21
cp 0
rs 9.1128
c 0
b 0
f 0
nc 5
cc 5
nop 6
crap 30
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 2019 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
18
 * @link      http://www.techdivision.com
19
 */
20
21
namespace TechDivision\Import\Cache;
22
23
use TechDivision\Import\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 2019 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
38
 * @link      http://www.techdivision.com
39
 * @see       \TechDivision\Import\Cache\GenericCacheAdapter
40
 */
41
class LocalCacheAdapter implements CacheAdapterInterface
42
{
43
44
    /**
45
     * Trait that provides custom cache adapter functionality.
46
     *
47
     * @var TechDivision\Import\Cache\CacheAdapterTrait
48
     */
49
    use CacheAdapterTrait;
50
51
    /**
52
     * The array with the tags.
53
     *
54
     * @var array
55
     */
56
    protected $tags = array();
57
58
    /**
59
     * The cache for the query results.
60
     *
61
     * @var array
62
     */
63
    protected $cache = array();
64
65
    /**
66
     * References that links to another cache entry.
67
     *
68
     * @var array
69
     */
70
    protected $references = array();
71
72
    /**
73
     * The cache key utility instance.
74
     *
75
     * @var \TechDivision\Import\Utils\CacheKeyUtilInterface
76
     */
77
    protected $cacheKeyUtil;
78
79
    /**
80
     * Initialize the cache handler with the passed cache and configuration instances.
81
     *
82
     * @param \TechDivision\Import\Utils\CacheKeyUtilInterface $cacheKeyUtil The cache key utility instance
83
     */
84
    public function __construct(CacheKeyUtilInterface $cacheKeyUtil)
85
    {
86
        $this->cacheKeyUtil = $cacheKeyUtil;
87
    }
88
89
    /**
90
     * Creates a unique cache key from the passed data.
91
     *
92
     * @param mixed $data The date to create the cache key from
93
     *
94
     * @return string The generated cache key
95
     */
96
    public function cacheKey($data)
97
    {
98
        return $this->cacheKeyUtil->cacheKey($data);
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
111
        // query whether or not the item has been cached, and if yes if the cache is valid
112 View Code Duplication
        if (isset($this->cache[$resolvedKey = $this->resolveReference($this->cacheKey($key))])) {
0 ignored issues
show
Duplication introduced by
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...
113
            return $this->cache[$resolvedKey];
114
        }
115
116
        // return FALSE in all other cases
117
        return false;
118
    }
119
120
    /**
121
     * Inversion of the isCached() method.
122
     *
123
     * @param string $key The cache key to query for
124
     *
125
     * @return boolean TRUE if the value is not available, else FALSE
126
     */
127
    public function notCached($key)
128
    {
129
        return !$this->isCached($key);
130
    }
131
132
    /**
133
     * Add's a cache reference from one key to another.
134
     *
135
     * @param string $from The key to reference from
136
     * @param string $to   The key to reference to
137
     *
138
     * @return void
139
     */
140
    public function addReference($from, $to)
141
    {
142
        $this->references[$this->cacheKey($from)] = $this->cacheKey($to);
143
    }
144
145
    /**
146
     * Resolve's the cache key.
147
     *
148
     * @param string $from The cache key to resolve
149
     *
150
     * @return string The resolved reference
151
     */
152
    protected function resolveReference($from)
153
    {
154
155
        // query whether or not a reference exists
156
        if (isset($this->references[$from])) {
157
            return $this->references[$from];
158
        }
159
160
        // return the passed reference
161
        return $from;
162
    }
163
164
    /**
165
     * Add the passed item to the cache.
166
     *
167
     * @param string  $key        The cache key to use
168
     * @param mixed   $value      The value that has to be cached
169
     * @param array   $references An array with references to add
170
     * @param array   $tags       An array with tags to add
171
     * @param boolean $override   Flag that allows to override an exising cache entry
172
     * @param integer $time       The TTL in seconds for the passed item
173
     *
174
     * @return void
175
     */
176
    public function toCache($key, $value, array $references = array(), array $tags = array(), $override = false, $time = null)
177
    {
178
179
        // query whether or not the key has already been used
180
        if (isset($this->cache[$this->resolveReference($uniqueKey = $this->cacheKey($key))]) && $override === false) {
181
            throw new \Exception(
182
                sprintf(
183
                    'Try to override data with key "%s"',
184
                    $uniqueKey
185
                )
186
            );
187
        }
188
189
        // set the attribute in the registry
190
        $this->cache[$uniqueKey] = $value;
191
192
        // prepend the tags with the cache key
193
        array_walk($tags, function (&$tag) {
194
            $tag = $this->cacheKey($tag);
195
        });
196
197
        // tag the unique key
198
        foreach ($tags as $tag) {
199
            $this->tags[$tag][] = $uniqueKey;
200
        }
201
202
        // also register the references if given
203
        foreach ($references as $from => $to) {
204
            $this->addReference($from, $to);
205
        }
206
    }
207
208
    /**
209
     * Returns a new cache item for the passed key
210
     *
211
     * @param string $key The cache key to return the item for
212
     *
213
     * @return mixed The value for the passed key
214
     */
215
    public function fromCache($key)
216
    {
217 View Code Duplication
        if (isset($this->cache[$uniqueKey = $this->resolveReference($this->cacheKey($key))])) {
0 ignored issues
show
Duplication introduced by
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...
218
            return $this->cache[$uniqueKey];
219
        }
220
    }
221
222
    /**
223
     * Flush the cache and remove the references.
224
     *
225
     * @return void
226
     */
227
    public function flushCache()
228
    {
229
        $this->tags = array();
230
        $this->cache = array();
231
        $this->references = array();
232
    }
233
234
    /**
235
     * Invalidate the cache entries for the passed tags.
236
     *
237
     * @param array $tags The tags to invalidate the cache for
238
     *
239
     * @return void
240
     */
241
    public function invalidateTags(array $tags)
242
    {
243
244
        // prepend the tags with the cache key
245
        array_walk($tags, function (&$tag) {
246
            $tag = $this->cacheKey($tag);
247
        });
248
249
        // remove all the references of items that has one of the passed tags
250
        foreach ($tags as $tag) {
251
            if (isset($this->tags[$tag])) {
252
                foreach ($this->tags[$tag] as $to) {
253
                    if ($from = array_search($to, $this->references)) {
254
                        unset($this->references[$from]);
255
                    }
256
                }
257
            }
258
        }
259
    }
260
261
    /**
262
     * Remove the item with the passed key and all its references from the cache.
263
     *
264
     * @param string $key The key of the cache item to Remove
265
     *
266
     * @return void
267
     */
268
    public function removeCache($key)
269
    {
270
271
        // delete the item with the passed key
272
        unset($this->cache[$this->resolveReference($uniqueKey = $this->cacheKey($key))]);
273
274
        // query whether or not the references exists and has to be removed
275
        if (isset($this->references[$uniqueKey])) {
0 ignored issues
show
Bug introduced by
The variable $uniqueKey seems only to be defined at a later point. As such the call to isset() seems to always evaluate to false.

This check marks calls to isset(...) or empty(...) that are found before the variable itself is defined. These will always have the same result.

This is likely the result of code being shifted around. Consider removing these calls.

Loading history...
276
            unset($this->references[$uniqueKey]);
277
        }
278
    }
279
}
280