Skip to content

Commit

Permalink
refactor: extract PageCache class
Browse files Browse the repository at this point in the history
  • Loading branch information
kenjis committed Jun 30, 2023
1 parent e3bc5e9 commit 54ed30f
Show file tree
Hide file tree
Showing 4 changed files with 410 additions and 20 deletions.
130 changes: 130 additions & 0 deletions system/Cache/PageCache.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<?php

/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace CodeIgniter\Cache;

use CodeIgniter\HTTP\CLIRequest;
use CodeIgniter\HTTP\IncomingRequest;
use CodeIgniter\HTTP\ResponseInterface;
use Config\Cache as CacheConfig;
use Exception;

/**
* Web Page Caching
*/
class PageCache
{
/**
* Whether to take the URL query string into consideration when generating
* output cache files. Valid options are:
*
* false = Disabled
* true = Enabled, take all query parameters into account.
* Please be aware that this may result in numerous cache
* files generated for the same page over and over again.
* array('q') = Enabled, but only take into account the specified list
* of query parameters.
*
* @var bool|string[]
*/
protected $cacheQueryString = false;

protected CacheInterface $cache;

public function __construct(CacheConfig $config, CacheInterface $cache)
{
$this->cacheQueryString = $config->cacheQueryString;
$this->cache = $cache;
}

/**
* Generates the cache key to use from the current request.
*
* @param CLIRequest|IncomingRequest $request
*
* @internal for testing purposes only
*/
public function generateCacheKey($request): string
{
if ($request instanceof CLIRequest) {
return md5($request->getPath());
}

$uri = clone $request->getUri();

$query = $this->cacheQueryString
? $uri->getQuery(is_array($this->cacheQueryString) ? ['only' => $this->cacheQueryString] : [])
: '';

return md5($uri->setFragment('')->setQuery($query));
}

/**
* Caches the full response from the current request.
*
* @param CLIRequest|IncomingRequest $request
*
* @params int $ttl time to live in seconds.
*/
public function cachePage($request, ResponseInterface $response, int $ttl): bool
{
$headers = [];

foreach ($response->headers() as $header) {
$headers[$header->getName()] = $header->getValueLine();
}

return $this->cache->save(
$this->generateCacheKey($request),
serialize(['headers' => $headers, 'output' => $response->getBody()]),
$ttl
);
}

/**
* Gets the cached response for the request.
*
* @param CLIRequest|IncomingRequest $request
*/
public function getCachedResponse($request, ResponseInterface $response): ?ResponseInterface
{
if ($cachedResponse = $this->cache->get($this->generateCacheKey($request))) {
$cachedResponse = unserialize($cachedResponse);

if (
! is_array($cachedResponse)
|| ! isset($cachedResponse['output'])
|| ! isset($cachedResponse['headers'])
) {
throw new Exception('Error unserializing page cache');
}

$headers = $cachedResponse['headers'];
$output = $cachedResponse['output'];

// Clear all default headers
foreach (array_keys($response->headers()) as $key) {
$response->removeHeader($key);
}

// Set cached headers
foreach ($headers as $name => $value) {
$response->setHeader($name, $value);
}

$response->setBody($output);

return $response;
}

return null;
}
}
36 changes: 16 additions & 20 deletions system/CodeIgniter.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace CodeIgniter;

use Closure;
use CodeIgniter\Cache\PageCache;
use CodeIgniter\Debug\Timer;
use CodeIgniter\Events\Events;
use CodeIgniter\Exceptions\FrameworkException;
Expand Down Expand Up @@ -175,13 +176,20 @@ class CodeIgniter
*/
protected int $bufferLevel;

/**
* Web Page Caching
*/
protected PageCache $pageCache;

/**
* Constructor.
*/
public function __construct(App $config)
{
$this->startTime = microtime(true);
$this->config = $config;

$this->pageCache = Services::pagecache();
}

/**
Expand Down Expand Up @@ -518,7 +526,7 @@ protected function handleRequest(?RouteCollectionInterface $routes, Cache $cache
// so that we can have live speed updates along the way.
// Must be run after filters to preserve the Response headers.
if (static::$cacheTTL > 0) {
$this->cachePage($cacheConfig);
$this->pageCache->cachePage($this->request, $this->response, static::$cacheTTL);
}

// Update the performance metrics
Expand Down Expand Up @@ -674,27 +682,11 @@ protected function forceSecureAccess($duration = 31_536_000)
*/
public function displayCache(Cache $config)
{
if ($cachedResponse = cache()->get($this->generateCacheName($config))) {
$cachedResponse = unserialize($cachedResponse);
if (! is_array($cachedResponse) || ! isset($cachedResponse['output']) || ! isset($cachedResponse['headers'])) {
throw new Exception('Error unserializing page cache');
}

$headers = $cachedResponse['headers'];
$output = $cachedResponse['output'];

// Clear all default headers
foreach (array_keys($this->response->headers()) as $key) {
$this->response->removeHeader($key);
}

// Set cached headers
foreach ($headers as $name => $value) {
$this->response->setHeader($name, $value);
}
if ($cachedResponse = $this->pageCache->getCachedResponse($this->request, $this->response)) {
$this->response = $cachedResponse;

$this->totalTime = $this->benchmark->getElapsedTime('total_execution');
$output = $this->displayPerformanceMetrics($output);
$output = $this->displayPerformanceMetrics($cachedResponse->getBody());
$this->response->setBody($output);

return $this->response;
Expand All @@ -716,6 +708,8 @@ public static function cache(int $time)
* full-page caching for very high performance.
*
* @return bool
*
* @deprecated 4.4.0 No longer used.
*/
public function cachePage(Cache $config)
{
Expand All @@ -741,6 +735,8 @@ public function getPerformanceStats(): array

/**
* Generates the cache name to use for our full-page caching.
*
* @deprecated 4.4.0 No longer used.
*/
protected function generateCacheName(Cache $config): string
{
Expand Down
18 changes: 18 additions & 0 deletions system/Config/Services.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use CodeIgniter\Cache\CacheFactory;
use CodeIgniter\Cache\CacheInterface;
use CodeIgniter\Cache\PageCache;
use CodeIgniter\CLI\Commands;
use CodeIgniter\CodeIgniter;
use CodeIgniter\Database\ConnectionInterface;
Expand Down Expand Up @@ -438,6 +439,23 @@ public static function negotiator(?RequestInterface $request = null, bool $getSh
return new Negotiate($request);
}

/**
* Return the PageCache.
*
* @return PageCache
*/
public static function pagecache(?Cache $config = null, ?CacheInterface $cache = null, bool $getShared = true)
{
if ($getShared) {
return static::getSharedInstance('pagecache', $config, $cache);
}

$config ??= config(Cache::class);
$cache ??= AppServices::cache();

return new PageCache($config, $cache);
}

/**
* Return the appropriate pagination handler.
*
Expand Down
Loading

0 comments on commit 54ed30f

Please sign in to comment.