1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* |
4
|
|
|
* This file is part of phpFastCache. |
5
|
|
|
* |
6
|
|
|
* @license MIT License (MIT) |
7
|
|
|
* |
8
|
|
|
* For full copyright and license information, please see the docs/CREDITS.txt file. |
9
|
|
|
* |
10
|
|
|
* @author Khoa Bui (khoaofgod) <[email protected]> http://www.phpfastcache.com |
11
|
|
|
* @author Georges.L (Geolim4) <[email protected]> |
12
|
|
|
* |
13
|
|
|
*/ |
14
|
|
|
|
15
|
|
|
namespace phpFastCache\Core; |
16
|
|
|
|
17
|
|
|
use phpFastCache\Cache\ExtendedCacheItemInterface; |
18
|
|
|
use phpFastCache\CacheManager; |
19
|
|
|
use Psr\Cache\CacheItemInterface; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* Trait StandardPsr6StructureTrait |
23
|
|
|
* @package phpFastCache\Core |
24
|
|
|
*/ |
25
|
|
|
trait StandardPsr6StructureTrait |
26
|
|
|
{ |
27
|
|
|
use ClassNamespaceResolverTrait; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @var array |
31
|
|
|
*/ |
32
|
|
|
protected $deferredList = []; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* @var ExtendedCacheItemInterface[] |
36
|
|
|
*/ |
37
|
|
|
protected $itemInstances = []; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* @param string $key |
41
|
|
|
* @return \phpFastCache\Cache\ExtendedCacheItemInterface |
42
|
|
|
* @throws \InvalidArgumentException |
43
|
|
|
*/ |
44
|
|
|
public function getItem($key) |
45
|
|
|
{ |
46
|
|
|
if (is_string($key)) { |
47
|
|
|
if (!array_key_exists($key, $this->itemInstances)) { |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* @var $item ExtendedCacheItemInterface |
51
|
|
|
*/ |
52
|
|
|
CacheManager::$ReadHits++; |
53
|
|
|
$class = new \ReflectionClass((new \ReflectionObject($this))->getNamespaceName() . '\Item'); |
54
|
|
|
$item = $class->newInstanceArgs([$this, $key]); |
55
|
|
|
$driverArray = $this->driverRead($item); |
56
|
|
|
|
57
|
|
|
if ($driverArray) { |
58
|
|
|
$item->set($this->driverUnwrapData($driverArray)); |
59
|
|
|
$item->expiresAt($this->driverUnwrapTime($driverArray)); |
60
|
|
|
$item->setTags($this->driverUnwrapTags($driverArray)); |
61
|
|
|
if ($item->isExpired()) { |
62
|
|
|
/** |
63
|
|
|
* Using driverDelete() instead of delete() |
64
|
|
|
* to avoid infinite loop caused by |
65
|
|
|
* getItem() call in delete() method |
66
|
|
|
* As we MUST return an item in any |
67
|
|
|
* way, we do not de-register here |
68
|
|
|
*/ |
69
|
|
|
$this->driverDelete($item); |
70
|
|
|
|
71
|
|
|
} else { |
72
|
|
|
$item->setHit(true); |
73
|
|
|
} |
74
|
|
|
} else { |
75
|
|
|
$item->expiresAfter(abs((int) $this->getConfig()[ 'defaultTtl' ])); |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
} |
79
|
|
|
} else { |
80
|
|
|
throw new \InvalidArgumentException(sprintf('$key must be a string, got type "%s" instead.', gettype($key))); |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
return $this->itemInstances[ $key ]; |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* @param \Psr\Cache\CacheItemInterface $item |
88
|
|
|
* @return $this |
89
|
|
|
* @throws \InvalidArgumentException |
90
|
|
|
*/ |
91
|
|
|
public function setItem(CacheItemInterface $item) |
92
|
|
|
{ |
93
|
|
|
if ($this->getClassNamespace() . '\\Item' === get_class($item)) { |
94
|
|
|
$this->itemInstances[ $item->getKey() ] = $item; |
95
|
|
|
|
96
|
|
|
return $this; |
97
|
|
|
} else { |
98
|
|
|
throw new \InvalidArgumentException(sprintf('Invalid Item Class "%s" for this driver.', get_class($item))); |
99
|
|
|
} |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* @param array $keys |
104
|
|
|
* @return CacheItemInterface[] |
105
|
|
|
* @throws \InvalidArgumentException |
106
|
|
|
*/ |
107
|
|
|
public function getItems(array $keys = []) |
108
|
|
|
{ |
109
|
|
|
$collection = []; |
110
|
|
|
foreach ($keys as $key) { |
111
|
|
|
$collection[ $key ] = $this->getItem($key); |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
return $collection; |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* @param string $key |
119
|
|
|
* @return bool |
120
|
|
|
* @throws \InvalidArgumentException |
121
|
|
|
*/ |
122
|
|
|
public function hasItem($key) |
123
|
|
|
{ |
124
|
|
|
CacheManager::$ReadHits++; |
125
|
|
|
|
126
|
|
|
return $this->getItem($key)->isHit(); |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* @return bool |
131
|
|
|
*/ |
132
|
|
|
public function clear() |
133
|
|
|
{ |
134
|
|
|
CacheManager::$WriteHits++; |
135
|
|
|
$this->itemInstances = []; |
136
|
|
|
|
137
|
|
|
return $this->driverClear(); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
/** |
141
|
|
|
* @param string $key |
142
|
|
|
* @return bool |
143
|
|
|
* @throws \InvalidArgumentException |
144
|
|
|
*/ |
145
|
|
|
public function deleteItem($key) |
146
|
|
|
{ |
147
|
|
|
$item = $this->getItem($key); |
148
|
|
|
if ($this->hasItem($key) && $this->driverDelete($item)) { |
149
|
|
|
$item->setHit(false); |
150
|
|
|
CacheManager::$WriteHits++; |
151
|
|
|
/** |
152
|
|
|
* De-register the item instance |
153
|
|
|
* then collect gc cycles |
154
|
|
|
*/ |
155
|
|
|
$this->deregisterItem($key); |
156
|
|
|
|
157
|
|
|
return true; |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
return false; |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* @param array $keys |
165
|
|
|
* @return bool |
166
|
|
|
* @throws \InvalidArgumentException |
167
|
|
|
*/ |
168
|
|
|
public function deleteItems(array $keys) |
169
|
|
|
{ |
170
|
|
|
$return = null; |
171
|
|
|
foreach ($keys as $key) { |
172
|
|
|
$result = $this->deleteItem($key); |
173
|
|
|
if ($result !== false) { |
174
|
|
|
$return = $result; |
175
|
|
|
} |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
return (bool) $return; |
179
|
|
|
} |
180
|
|
|
|
181
|
|
|
/** |
182
|
|
|
* @param \Psr\Cache\CacheItemInterface $item |
183
|
|
|
* @return mixed |
184
|
|
|
* @throws \InvalidArgumentException |
185
|
|
|
* @throws \RuntimeException |
186
|
|
|
*/ |
187
|
|
|
public function save(CacheItemInterface $item) |
188
|
|
|
{ |
189
|
|
|
/** |
190
|
|
|
* @var ExtendedCacheItemInterface $item |
191
|
|
|
*/ |
192
|
|
View Code Duplication |
if (!array_key_exists($item->getKey(), $this->itemInstances)) { |
|
|
|
|
193
|
|
|
$this->itemInstances[ $item->getKey() ] = $item; |
194
|
|
|
} else if(spl_object_hash($item) !== spl_object_hash($this->itemInstances[ $item->getKey() ])){ |
195
|
|
|
throw new \RuntimeException('Spl object hash mismatches ! You probably tried to save a detached item which has been already retrieved from cache.'); |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
|
199
|
|
|
if ($this->driverWrite($item) && $this->driverWriteTags($item)) { |
200
|
|
|
$item->setHit(true); |
201
|
|
|
CacheManager::$WriteHits++; |
202
|
|
|
|
203
|
|
|
return true; |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
return false; |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
/** |
210
|
|
|
* @param \Psr\Cache\CacheItemInterface $item |
211
|
|
|
* @return \Psr\Cache\CacheItemInterface |
212
|
|
|
* @throws \RuntimeException |
213
|
|
|
*/ |
214
|
|
|
public function saveDeferred(CacheItemInterface $item) |
215
|
|
|
{ |
216
|
|
View Code Duplication |
if (!array_key_exists($item->getKey(), $this->itemInstances)) { |
|
|
|
|
217
|
|
|
$this->itemInstances[ $item->getKey() ] = $item; |
218
|
|
|
}else if(spl_object_hash($item) !== spl_object_hash($this->itemInstances[ $item->getKey() ])){ |
219
|
|
|
throw new \RuntimeException('Spl object hash mismatches ! You probably tried to save a detached item which has been already retrieved from cache.'); |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
return $this->deferredList[ $item->getKey() ] = $item; |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
/** |
226
|
|
|
* @return mixed|null |
227
|
|
|
* @throws \InvalidArgumentException |
228
|
|
|
*/ |
229
|
|
|
public function commit() |
230
|
|
|
{ |
231
|
|
|
$return = null; |
232
|
|
|
foreach ($this->deferredList as $key => $item) { |
233
|
|
|
$result = $this->save($item); |
234
|
|
|
if ($return !== false) { |
235
|
|
|
unset($this->deferredList[ $key ]); |
236
|
|
|
$return = $result; |
237
|
|
|
} |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
return (bool) $return; |
241
|
|
|
} |
242
|
|
|
} |
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.