Skip to content

Commit cf06f4f

Browse files
authored
Merge pull request #240 from WebFiori/routes-cache
feat: Routes Caching
2 parents 381fb63 + 53288a9 commit cf06f4f

File tree

7 files changed

+90
-30
lines changed

7 files changed

+90
-30
lines changed

tests/webfiori/framework/test/cli/HelpCommandTest.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
namespace webfiori\framework\test\cli;
33

44
use webfiori\framework\cli\CLITestCase;
5-
use webfiori\framework\cli\commands\CreateCommand;
6-
use webfiori\framework\scheduler\webServices\TasksServicesManager;
7-
use webfiori\http\WebServicesManager;
85
/**
96
* @author Ibrahim
107
*/

webfiori/framework/App.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use webfiori\file\exceptions\FileException;
1919
use webfiori\file\File;
2020
use webfiori\framework\autoload\ClassLoader;
21+
use webfiori\framework\cache\Cache;
2122
use webfiori\framework\config\ConfigurationDriver;
2223
use webfiori\framework\config\Controller;
2324
use webfiori\framework\exceptions\InitializationException;
@@ -179,11 +180,21 @@ private function __construct() {
179180
foreach ($uriObj->getMiddleware() as $mw) {
180181
$mw->after(Request::get(), Response::get());
181182
}
183+
App::cacheResponse($uriObj->getUri(true, true), $uriObj->getCacheDuration());
182184
}
183185
});
184186
//class is now initialized
185187
self::$ClassStatus = self::STATUS_INITIALIZED;
186188
}
189+
public static function cacheResponse(string $key, int $duration) {
190+
Cache::get($key, function () {
191+
return [
192+
'headers' => Response::getHeaders(),
193+
'http-code' => Response::getCode(),
194+
'body' => Response::getBody()
195+
];
196+
}, $duration);
197+
}
187198
/**
188199
* Register CLI commands or background tasks.
189200
*

webfiori/framework/cache/FileStorage.php

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,21 @@ public function __construct() {
3333
* @param Item $item An item that will be added to the cache.
3434
*/
3535
public function cache(Item $item) {
36-
$filePath = $this->getPath().DS.md5($item->getKey()).'.cache';
37-
$encryptedData = $item->getDataEncrypted();
36+
if ($item->getTTL() > 0) {
37+
$filePath = $this->getPath().DS.md5($item->getKey()).'.cache';
38+
$encryptedData = $item->getDataEncrypted();
3839

39-
if (!is_dir($this->getPath())) {
40-
mkdir($this->getPath(), 0755, true);
40+
if (!is_dir($this->getPath())) {
41+
mkdir($this->getPath(), 0755, true);
42+
}
43+
file_put_contents($filePath, serialize([
44+
'data' => $encryptedData,
45+
'created_at' => time(),
46+
'ttl' => $item->getTTL(),
47+
'expires' => $item->getExpiryTime(),
48+
'key' => $item->getKey()
49+
]));
4150
}
42-
file_put_contents($filePath, serialize([
43-
'data' => $encryptedData,
44-
'created_at' => time(),
45-
'ttl' => $item->getTTL(),
46-
'expires' => $item->getExpiryTime(),
47-
'key' => $item->getKey()
48-
]));
4951
}
5052
/**
5153
* Removes an item from the cache.

webfiori/framework/cache/Item.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@ public function getData() {
7070
/**
7171
* Returns cache item data after performing decryption on it.
7272
*
73-
* @return string
73+
* @return mixed
7474
*/
75-
public function getDataDecrypted() : string {
76-
return $this->decrypt($this->getData());
75+
public function getDataDecrypted() {
76+
return unserialize($this->decrypt($this->getData()));
7777
}
7878
/**
7979
* Returns cache data after performing encryption on it.
@@ -83,7 +83,7 @@ public function getDataDecrypted() : string {
8383
* @return string
8484
*/
8585
public function getDataEncrypted() : string {
86-
return $this->encrypt($this->getData());
86+
return $this->encrypt(serialize($this->getData()));
8787
}
8888
/**
8989
* Returns the time at which cache item will expire as Unix timestamp.
@@ -169,7 +169,7 @@ public function setSecret(string $secret) {
169169
* @param int $ttl Time-to-live of the item in cache.
170170
*/
171171
public function setTTL(int $ttl) {
172-
if ($ttl > 0) {
172+
if ($ttl >= 0) {
173173
$this->timeToLive = $ttl;
174174
}
175175
}

webfiori/framework/router/RouteOption.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ class RouteOption {
2828
* An option which is used to indicate if path is case sensitive or not.
2929
*/
3030
const CASE_SENSITIVE = 'case-sensitive';
31+
/**
32+
* An option which is used to set the duration of route cache in seconds.
33+
*/
34+
const CACHE_DURATION = 'cache-ttl';
3135
/**
3236
* An option which is used to set an array as closure parameters (applies to routes of type closure only)
3337
*/

webfiori/framework/router/Router.php

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use webfiori\cli\Runner;
1616
use webfiori\file\exceptions\FileException;
1717
use webfiori\file\File;
18+
use webfiori\framework\cache\Cache;
1819
use webfiori\framework\exceptions\RoutingException;
1920
use webfiori\framework\ui\HTTPCodeView;
2021
use webfiori\framework\ui\StarterPage;
@@ -507,14 +508,16 @@ public static function incSiteMapRoute() {
507508
Response::addHeader('content-type','text/xml');
508509
};
509510
self::closure([
510-
'path' => '/sitemap.xml',
511-
'route-to' => $sitemapFunc,
512-
'in-sitemap' => true
511+
RouteOption::PATH => '/sitemap.xml',
512+
RouteOption::TO => $sitemapFunc,
513+
RouteOption::SITEMAP => true,
514+
RouteOption::CACHE_DURATION => 86400//1 day
513515
]);
514516
self::closure([
515-
'path' => '/sitemap',
516-
'route-to' => $sitemapFunc,
517-
'in-sitemap' => true
517+
RouteOption::PATH => '/sitemap',
518+
RouteOption::TO => $sitemapFunc,
519+
RouteOption::SITEMAP => true,
520+
RouteOption::CACHE_DURATION => 86400//1 day
518521
]);
519522
}
520523
/**
@@ -529,7 +532,8 @@ public static function notFound() {
529532
* Adds new route to a web page.
530533
*
531534
* Note that the route which created using this method will be added to
532-
* 'global' and 'web' middleware groups.
535+
* 'global' and 'web' middleware groups. Additionally, the routes will
536+
* be cached for one hour.
533537
*
534538
* @param array $options An associative array that contains route
535539
* options. Available options are:
@@ -755,13 +759,14 @@ private function addRouteHelper0($options): bool {
755759
$asApi = $options[RouteOption::API];
756760
$closureParams = $options[RouteOption::CLOSURE_PARAMS] ;
757761
$path = $options[RouteOption::PATH];
762+
$cache = $options[RouteOption::CACHE_DURATION];
758763

759764
if ($routeType == self::CLOSURE_ROUTE && !is_callable($routeTo)) {
760765
return false;
761766
}
762767
$routeUri = new RouterUri($this->getBase().$path, $routeTo,$caseSensitive, $closureParams);
763768
$routeUri->setAction($options[RouteOption::ACTION]);
764-
769+
$routeUri->setCacheDuration($cache);
765770
if (!$this->hasRouteHelper($routeUri)) {
766771
if ($asApi === true) {
767772
$routeUri->setType(self::API_ROUTE);
@@ -928,6 +933,12 @@ private function checkOptionsArr(array $options): array {
928933
} else {
929934
$caseSensitive = true;
930935
}
936+
937+
if (isset($options[RouteOption::CACHE_DURATION])) {
938+
$cacheDuration = $options[RouteOption::CACHE_DURATION];
939+
} else {
940+
$cacheDuration = 0;
941+
}
931942

932943
$routeType = $options[RouteOption::TYPE] ?? Router::CUSTOMIZED;
933944

@@ -978,7 +989,8 @@ private function checkOptionsArr(array $options): array {
978989
RouteOption::VALUES => $varValues,
979990
RouteOption::MIDDLEWARE => $mdArr,
980991
RouteOption::REQUEST_METHODS => $this->getRequestMethodsHelper($options),
981-
RouteOption::ACTION => $action
992+
RouteOption::ACTION => $action,
993+
RouteOption::CACHE_DURATION => $cacheDuration
982994
];
983995
}
984996
private function copyOptionsToSub($options, &$subRoute) {
@@ -1376,7 +1388,6 @@ private function routeFound(RouterUri $route, bool $loadResource) {
13761388
if ($route->getType() == self::API_ROUTE && !defined('API_CALL')) {
13771389
define('API_CALL', true);
13781390
}
1379-
13801391
if (is_callable($route->getRouteTo())) {
13811392
if ($loadResource === true) {
13821393
call_user_func_array($route->getRouteTo(),$route->getClosureParams());
@@ -1453,6 +1464,16 @@ private function routeFound(RouterUri $route, bool $loadResource) {
14531464
* @throws RoutingException
14541465
*/
14551466
private function searchRoute(RouterUri $routeUri, string $uri, bool $loadResource, bool $withVars = false): bool {
1467+
$data = Cache::get($uri);
1468+
1469+
if ($data !== null) {
1470+
Response::write($data['body']);
1471+
Response::setCode($data['http-code']);
1472+
foreach ($data['headers'] as $headerObj) {
1473+
Response::addHeader($headerObj->getName(), $headerObj->getValue());
1474+
}
1475+
return true;
1476+
}
14561477
$pathArray = $routeUri->getPathArray();
14571478
$requestMethod = Request::getMethod();
14581479
$indexToSearch = 'static';
@@ -1600,7 +1621,10 @@ private static function view(array $options): bool {
16001621
if (gettype($options) == 'array') {
16011622
$options[RouteOption::TYPE] = Router::VIEW_ROUTE;
16021623
self::addToMiddlewareGroup($options, 'web');
1603-
1624+
if (!isset($options[RouteOption::CACHE_DURATION])) {
1625+
//Cache pages for 1 hour by default
1626+
$options[RouteOption::CACHE_DURATION] = 3600;
1627+
}
16041628
return Router::getInstance()->addRouteHelper1($options);
16051629
}
16061630

webfiori/framework/router/RouterUri.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class RouterUri extends Uri {
4646
*/
4747
private $action;
4848
private $assignedMiddlewareList;
49+
private $cacheDuration;
4950
/**
5051
*
5152
* @var array
@@ -137,6 +138,27 @@ public function __construct(string $requestedUri, $routeTo, bool $caseSensitive
137138
$this->incInSiteMap = false;
138139
$this->languages = [];
139140
$this->addMiddleware('global');
141+
$this->setCacheDuration(0);
142+
}
143+
/**
144+
* Returns the duration of URI cache.
145+
*
146+
* @return int The duration of URI cache. Default value is zero which indicates
147+
* that no caching will happen.
148+
*/
149+
public function getCacheDuration() : int {
150+
return $this->cacheDuration;
151+
}
152+
/**
153+
* Sets the duration of URI cache.
154+
*
155+
* @param int $val A positive value that represent cache duration in seconds.
156+
* If 0 is given, it indicates that no caching will happen.
157+
*/
158+
public function setCacheDuration(int $val) {
159+
if ($val >= 0) {
160+
$this->cacheDuration = $val;
161+
}
140162
}
141163
/**
142164
* Adds a language to the set of languages at which the resource that the URI

0 commit comments

Comments
 (0)