Skip to content

Commit

Permalink
Merge pull request #237 from WebFiori/cache
Browse files Browse the repository at this point in the history
feat: Cache
  • Loading branch information
usernane authored Nov 19, 2024
2 parents 85174ea + 2f14e35 commit 381fb63
Show file tree
Hide file tree
Showing 7 changed files with 702 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/php83.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
push:
branches: [ master, dev ]
pull_request:
branches: [ master ]
branches: [ master, dev ]

jobs:

Expand Down
8 changes: 7 additions & 1 deletion phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
<file>./webfiori/framework/router/RouterUri.php</file>
<file>./webfiori/framework/router/Router.php</file>

<file>./webfiori/framework/cache/AbstractCacheStore.php</file>
<file>./webfiori/framework/cache/FileCacheStore.php</file>
<file>./webfiori/framework/cache/Cache.php</file>

<file>./webfiori/framework/session/Session.php</file>
<file>./webfiori/framework/session/SessionsManager.php</file>
<file>./webfiori/framework/session/DefaultSessionStorage.php</file>
Expand Down Expand Up @@ -109,6 +113,8 @@
<testsuite name="Session Tests">
<directory>./tests/webfiori/framework/test/session</directory>
</testsuite>

<testsuite name="Cache Tests">
<directory>./tests/webfiori/framework/test/cache</directory>
</testsuite>
</testsuites>
</phpunit>
87 changes: 87 additions & 0 deletions tests/webfiori/framework/test/cache/CacheTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php
namespace webfiori\framework\test\cache;

use PHPUnit\Framework\TestCase;
use webfiori\framework\cache\Cache;
/**
*/
class CacheTest extends TestCase {
/**
* @test
*/
public function test00() {
$key = 'first';
$data = Cache::get($key, function () {
return 'This is a test.';
});
$this->assertEquals('This is a test.', $data);
$this->assertEquals('This is a test.', Cache::get($key));
$this->assertNull(Cache::get('not_cached'));
}
/**
* @test
*/
public function test01() {
$key = 'test_2';
$this->assertFalse(Cache::has($key));
$data = Cache::get($key, function () {
return 'This is a test.';
}, 5);
$this->assertEquals('This is a test.', $data);
$this->assertTrue(Cache::has($key));
sleep(6);
$this->assertFalse(Cache::has($key));
$this->assertNull(Cache::get($key));
}
/**
* @test
*/
public function test03() {
$key = 'ok_test';
$this->assertFalse(Cache::has($key));
$data = Cache::get($key, function () {
return 'This is a test.';
}, 600);
$this->assertEquals('This is a test.', $data);
$this->assertTrue(Cache::has($key));
Cache::delete($key);
$this->assertFalse(Cache::has($key));
$this->assertNull(Cache::get($key));
}
/**
* @test
*/
public function test04() {
$key = 'test_3';
$this->assertFalse(Cache::has($key));
$data = Cache::get($key, function () {
return 'This is a test.';
}, 600);
$this->assertEquals('This is a test.', $data);
$item = Cache::getItem($key);
$this->assertNotNull($item);
$this->assertEquals(600, $item->getTTL());
Cache::setTTL($key, 1000);
$item = Cache::getItem($key);
$this->assertEquals(1000, $item->getTTL());
Cache::delete($key);
$this->assertNull(Cache::getItem($key));
}
public function test05() {
$keys = [];
for ($x = 0 ; $x < 10 ; $x++) {
$key = 'item_'.$x;
Cache::get($key, function () {
return 'This is a test.';
}, 600);
$keys[] = $key;
}
foreach ($keys as $key) {
$this->assertTrue(Cache::has($key));
}
Cache::flush();
foreach ($keys as $key) {
$this->assertFalse(Cache::has($key));
}
}
}
172 changes: 172 additions & 0 deletions webfiori/framework/cache/Cache.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
<?php
/**
* This file is licensed under MIT License.
*
* Copyright (c) 2024 Ibrahim BinAlshikh and Contributors
*
* For more information on the license, please visit:
* https://github.com/WebFiori/.github/blob/main/LICENSE
*
*/
namespace webfiori\framework\cache;

/**
* A class which is used to manage cache related operations
*/
class Cache {
/**
*
* @var Storage
*/
private $driver;
private static $inst;
/**
* Removes an item from the cache given its unique identifier.
*
* @param string $key
*/
public static function delete(string $key) {
self::getDriver()->delete($key);
}
/**
* Removes all items from the cache.
*/
public static function flush() {
self::getDriver()->flush();
}
/**
* Returns or creates a cache item given its key.
*
*
* @param string $key The unique identifier of the item.
*
* @param callable $generator A callback which is used as a fallback to
* create new cache entry or re-create an existing one if it was expired.
* This callback must return the data that will be cached.
*
* @param int $ttl Time to live of the item in seconds.
*
* @param array $params Any additional parameters to be passed to the callback
* which is used to generate cache data.
* @return null
*/
public static function get(string $key, callable $generator = null, int $ttl = 60, array $params = []) {
$data = self::getDriver()->read($key);

if ($data !== null && $data !== false) {
return $data;
}

if (!is_callable($generator)) {
return null;
}
$newData = call_user_func_array($generator, $params);
$item = new Item($key, $newData, $ttl, defined('CACHE_SECRET') ? CACHE_SECRET : '');
self::getDriver()->cache($item);

return $newData;
}
/**
* Returns storage engine which is used to store, read, update and delete items
* from the cache.
*
* @return Storage
*/
public static function getDriver() : Storage {
return self::getInst()->driver;
}
/**
* Reads an item from the cache and return its information.
*
* @param string $key The unique identifier of the item.
*
* @return Item|null If such item exist and not yet expired, an object
* of type 'Item' is returned which has all cached item information. Other
* than that, null is returned.
*/
public static function getItem(string $key) {
return self::getDriver()->readItem($key);
}
/**
* Checks if the cache has in item given its unique identifier.
*
* @param string $key
*
* @return bool If the item exist and is not yet expired, true is returned.
* Other than that, false is returned.
*/
public static function has(string $key) : bool {
return self::getDriver()->has($key);
}
/**
* Creates new item in the cache.
*
* Note that the item will only be added if it does not exist or already
* expired or the override option is set to true in case it was already
* created and not expired.
*
* @param string $key The unique identifier of the item.
*
* @param mixed $data The data that will be cached.
*
* @param int $ttl The time at which the data will be kept in the cache (in seconds).
*
* @param bool $override If cache item already exist which has given key and not yet
* expired and this one is set to true, the existing item will be overridden by
* provided data and ttl.
*
* @return bool If successfully added, the method will return true. False
* otherwise.
*/
public static function set(string $key, $data, int $ttl = 60, bool $override = false) : bool {
if (!self::has($key) || $override === true) {
$item = new Item($key, $data, $ttl, defined('CACHE_SECRET') ? CACHE_SECRET : '');
self::getDriver()->cache($item);
}

return false;
}
/**
* Sets storage engine which is used to store, read, update and delete items
* from the cache.
*
* @param Storage $driver
*/
public static function setDriver(Storage $driver) {
self::getInst()->driver = $driver;
}
/**
* Updates TTL of specific cache item.
*
* @param string $key The unique identifier of the item.
*
* @param int $ttl The new value for TTL.
*
* @return bool If item is updated, true is returned. Other than that, false
* is returned.
*/
public static function setTTL(string $key, int $ttl) {
$item = self::getItem($key);

if ($item === null) {
return false;
}
$item->setTTL($ttl);
self::getDriver()->cache($item);

return true;
}
/**
* Creates and returns a single instance of the class.
*
* @return Cache
*/
private static function getInst() : Cache {
if (self::$inst === null) {
self::$inst = new Cache();
self::setDriver(new FileStorage());
}

return self::$inst;
}
}
Loading

0 comments on commit 381fb63

Please sign in to comment.