Skip to content

Commit d59c6d2

Browse files
authored
Merge pull request #4667 from MGatner/psr-cache
PSR: Cache
2 parents 968ba63 + 812d524 commit d59c6d2

11 files changed

Lines changed: 1000 additions & 5 deletions

File tree

composer.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,16 @@
1212
"ext-mbstring": "*",
1313
"kint-php/kint": "^3.3",
1414
"laminas/laminas-escaper": "^2.6",
15-
"psr/log": "^1.1"
15+
"psr/cache": "^1.0",
16+
"psr/log": "^1.1",
17+
"psr/simple-cache": "^1.0"
18+
},
19+
"provide": {
20+
"psr/cache-implementation": "^1.0",
21+
"psr/simple-cache-implementation": "^1.0"
1622
},
1723
"require-dev": {
24+
"cache/integration-tests": "^0.17.0",
1825
"codeigniter4/codeigniter4-standard": "^1.0",
1926
"fakerphp/faker": "^1.9",
2027
"mikey179/vfsstream": "^1.6",

phpunit.xml.dist

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@
4343
<testsuite name="Database">
4444
<directory>./tests/system/Database</directory>
4545
</testsuite>
46+
<testsuite name="Psr">
47+
<directory>./tests/psr</directory>
48+
</testsuite>
4649
</testsuites>
4750

4851
<extensions>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
/**
4+
* This file is part of the CodeIgniter 4 framework.
5+
*
6+
* (c) CodeIgniter Foundation <admin@codeigniter.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace CodeIgniter\Psr\Cache;
13+
14+
use InvalidArgumentException;
15+
use Psr\Cache\InvalidArgumentException as CacheException;
16+
use Psr\SimpleCache\InvalidArgumentException as SimpleCacheException;
17+
18+
final class CacheArgumentException extends InvalidArgumentException implements CacheException, SimpleCacheException
19+
{
20+
}

system/Psr/Cache/Item.php

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
<?php
2+
3+
/**
4+
* This file is part of the CodeIgniter 4 framework.
5+
*
6+
* (c) CodeIgniter Foundation <admin@codeigniter.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace CodeIgniter\Psr\Cache;
13+
14+
use CodeIgniter\Cache\Handlers\BaseHandler;
15+
use CodeIgniter\I18n\Time;
16+
use DateInterval;
17+
use DateTime;
18+
use DateTimeInterface;
19+
use InvalidArgumentException;
20+
use Psr\Cache\CacheItemInterface;
21+
22+
final class Item implements CacheItemInterface
23+
{
24+
/**
25+
* Reserved characters that cannot be used in a key or tag.
26+
*
27+
* @see https://github.com/symfony/cache-contracts/blob/c0446463729b89dd4fa62e9aeecc80287323615d/ItemInterface.php#L43
28+
*/
29+
public const RESERVED_CHARACTERS = '{}()/\@:';
30+
31+
/**
32+
* @var string
33+
*/
34+
protected $key;
35+
36+
/**
37+
* @var mixed
38+
*/
39+
protected $value;
40+
41+
/**
42+
* Whether this Item was the result
43+
* of a cache hit.
44+
*
45+
* @var boolean
46+
*/
47+
protected $hit;
48+
49+
/**
50+
* The expiration time
51+
*
52+
* @var Time|null
53+
*/
54+
protected $expiration;
55+
56+
/**
57+
* Validates a cache key according to PSR-6.
58+
*
59+
* @param mixed $key The key to validate
60+
*
61+
* @throws CacheArgumentException When $key is not valid
62+
*/
63+
public static function validateKey($key)
64+
{
65+
// Use the framework's Cache key validation
66+
try
67+
{
68+
BaseHandler::validateKey($key);
69+
}
70+
catch (InvalidArgumentException $e)
71+
{
72+
throw new CacheArgumentException($e->getMessage(), $e->getCode(), $e);
73+
}
74+
}
75+
76+
/**
77+
* Stores the Item's details.
78+
*
79+
* @param string $key
80+
* @param mixed $value
81+
* @param boolean $hit
82+
*/
83+
public function __construct(string $key, $value, bool $hit)
84+
{
85+
$this->key = $key;
86+
$this->value = $value;
87+
$this->hit = $hit;
88+
}
89+
90+
/**
91+
* Returns the key for the current cache item.
92+
*
93+
* The key is loaded by the Implementing Library, but should be available to
94+
* the higher level callers when needed.
95+
*
96+
* @return string
97+
* The key string for this cache item.
98+
*/
99+
public function getKey(): string
100+
{
101+
return $this->key;
102+
}
103+
104+
/**
105+
* Retrieves the value of the item from the cache associated with this object's key.
106+
*
107+
* The value returned must be identical to the value originally stored by set().
108+
*
109+
* If isHit() returns false, this method MUST return null. Note that null
110+
* is a legitimate cached value, so the isHit() method SHOULD be used to
111+
* differentiate between "null value was found" and "no value was found."
112+
*
113+
* @return mixed
114+
* The value corresponding to this cache item's key, or null if not found.
115+
*/
116+
public function get()
117+
{
118+
return $this->value;
119+
}
120+
121+
/**
122+
* Confirms if the cache item lookup resulted in a cache hit.
123+
*
124+
* Note: This method MUST NOT have a race condition between calling isHit()
125+
* and calling get().
126+
*
127+
* @return boolean
128+
* True if the request resulted in a cache hit. False otherwise.
129+
*/
130+
public function isHit(): bool
131+
{
132+
return $this->hit;
133+
}
134+
135+
/**
136+
* Sets the value represented by this cache item.
137+
*
138+
* The $value argument may be any item that can be serialized by PHP,
139+
* although the method of serialization is left up to the Implementing
140+
* Library.
141+
*
142+
* @param mixed $value
143+
* The serializable value to be stored.
144+
*
145+
* @return static
146+
* The invoked object.
147+
*/
148+
public function set($value): self
149+
{
150+
$this->value = $value;
151+
152+
return $this;
153+
}
154+
155+
/**
156+
* Sets the expiration time for this cache item.
157+
*
158+
* @param DateTimeInterface|null $expiration
159+
* The point in time after which the item MUST be considered expired.
160+
* If null is passed explicitly, a default value MAY be used. If none is set,
161+
* the value should be stored permanently or for as long as the
162+
* implementation allows.
163+
*
164+
* @return static
165+
* The called object.
166+
*/
167+
public function expiresAt($expiration): self
168+
{
169+
if ($expiration === null)
170+
{
171+
$this->expiration = null;
172+
}
173+
elseif ($expiration instanceof DateTimeInterface)
174+
{
175+
$this->expiration = Time::createFromInstance($expiration);
176+
}
177+
else
178+
{
179+
throw new CacheArgumentException('Expiration date must be a DateTimeInterface or null');
180+
}
181+
182+
return $this;
183+
}
184+
185+
/**
186+
* Sets the expiration time for this cache item.
187+
*
188+
* @param integer|DateInterval|null $time
189+
* The period of time from the present after which the item MUST be considered
190+
* expired. An integer parameter is understood to be the time in seconds until
191+
* expiration. If null is passed explicitly, a default value MAY be used.
192+
* If none is set, the value should be stored permanently or for as long as the
193+
* implementation allows.
194+
*
195+
* @return static
196+
* The called object.
197+
*/
198+
public function expiresAfter($time): self
199+
{
200+
if ($time === null)
201+
{
202+
$this->expiration = null;
203+
}
204+
elseif ($time instanceof DateInterval)
205+
{
206+
$this->expiration = Time::now()->add($time);
207+
}
208+
elseif (is_int($time))
209+
{
210+
$this->expiration = Time::now()->addSeconds($time);
211+
}
212+
else
213+
{
214+
throw new CacheArgumentException('Expiration date must be an integer, a DateInterval or null');
215+
}
216+
217+
return $this;
218+
}
219+
220+
/**
221+
* Returns the expiration Time.
222+
* This method is not a requirement of PSR-6 but is necessary
223+
* to pass "testExpiration".
224+
*
225+
* @see https://groups.google.com/g/php-fig/c/Qr4OxCf7J5Y
226+
*
227+
* @return Time|null
228+
*/
229+
public function getExpiration(): ?Time
230+
{
231+
return $this->expiration;
232+
}
233+
234+
/**
235+
* Returns whether or not this Item is expired.
236+
* This method is not a requirement of PSR-6 but is necessary
237+
* to pass "testSavedExpired".
238+
*
239+
* @see https://groups.google.com/g/php-fig/c/Qr4OxCf7J5Y
240+
*
241+
* @return boolean True if this Item is expired.
242+
*/
243+
public function isExpired(): bool
244+
{
245+
if (isset($this->expiration))
246+
{
247+
$now = Time::now();
248+
return $this->expiration->isBefore($now) || $this->expiration->sameAs($now);
249+
}
250+
251+
return false;
252+
}
253+
254+
/**
255+
* Sets the hit value.
256+
* This method is not a requirement of PSR-6 but is necessary
257+
* to allow deferred items to count as hits.
258+
*
259+
* @return $this
260+
*/
261+
public function setHit(bool $hit): self
262+
{
263+
$this->hit = $hit;
264+
265+
return $this;
266+
}
267+
}

0 commit comments

Comments
 (0)