From f6435c3e8d1c8ad413d253b6125519e3761170d2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 30 Jun 2023 17:20:29 +0900 Subject: [PATCH 01/13] refactor: extract PageCache class --- system/Cache/PageCache.php | 130 ++++++++++++++ system/CodeIgniter.php | 36 ++-- system/Config/BaseService.php | 2 + system/Config/Services.php | 18 ++ tests/system/Cache/PageCacheTest.php | 249 +++++++++++++++++++++++++++ 5 files changed, 415 insertions(+), 20 deletions(-) create mode 100644 system/Cache/PageCache.php create mode 100644 tests/system/Cache/PageCacheTest.php diff --git a/system/Cache/PageCache.php b/system/Cache/PageCache.php new file mode 100644 index 000000000000..ad52f02433bc --- /dev/null +++ b/system/Cache/PageCache.php @@ -0,0 +1,130 @@ + + * + * 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; + } +} diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 06b0c1f5c500..b8625b281978 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -12,6 +12,7 @@ namespace CodeIgniter; use Closure; +use CodeIgniter\Cache\PageCache; use CodeIgniter\Debug\Timer; use CodeIgniter\Events\Events; use CodeIgniter\Exceptions\FrameworkException; @@ -175,6 +176,11 @@ class CodeIgniter */ protected int $bufferLevel; + /** + * Web Page Caching + */ + protected PageCache $pageCache; + /** * Constructor. */ @@ -182,6 +188,8 @@ public function __construct(App $config) { $this->startTime = microtime(true); $this->config = $config; + + $this->pageCache = Services::pagecache(); } /** @@ -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 @@ -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; @@ -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) { @@ -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 { diff --git a/system/Config/BaseService.php b/system/Config/BaseService.php index d517691b0c1f..f98ec9192856 100644 --- a/system/Config/BaseService.php +++ b/system/Config/BaseService.php @@ -14,6 +14,7 @@ use CodeIgniter\Autoloader\Autoloader; use CodeIgniter\Autoloader\FileLocator; use CodeIgniter\Cache\CacheInterface; +use CodeIgniter\Cache\PageCache; use CodeIgniter\CLI\Commands; use CodeIgniter\CodeIgniter; use CodeIgniter\Database\ConnectionInterface; @@ -111,6 +112,7 @@ * @method static Logger logger($getShared = true) * @method static MigrationRunner migrations(Migrations $config = null, ConnectionInterface $db = null, $getShared = true) * @method static Negotiate negotiator(RequestInterface $request = null, $getShared = true) + * @method static PageCache pagecache(?Cache $config = null, ?CacheInterface $cache = null, bool $getShared = true) * @method static Pager pager(ConfigPager $config = null, RendererInterface $view = null, $getShared = true) * @method static Parser parser($viewPath = null, ConfigView $config = null, $getShared = true) * @method static RedirectResponse redirectresponse(App $config = null, $getShared = true) diff --git a/system/Config/Services.php b/system/Config/Services.php index 5e0c4e70b96e..14c9b122cc36 100644 --- a/system/Config/Services.php +++ b/system/Config/Services.php @@ -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; @@ -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. * diff --git a/tests/system/Cache/PageCacheTest.php b/tests/system/Cache/PageCacheTest.php new file mode 100644 index 000000000000..d95c9f10f91f --- /dev/null +++ b/tests/system/Cache/PageCacheTest.php @@ -0,0 +1,249 @@ + + * + * 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\Response; +use CodeIgniter\HTTP\ResponseInterface; +use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\UserAgent; +use CodeIgniter\Test\CIUnitTestCase; +use Config\App as AppConfig; +use Config\Cache as CacheConfig; +use ErrorException; +use Exception; + +/** + * @backupGlobals enabled + * + * @internal + * + * @group Others + */ +final class PageCacheTest extends CIUnitTestCase +{ + private AppConfig $appConfig; + + protected function setUp(): void + { + parent::setUp(); + + $this->appConfig = new AppConfig(); + } + + private function createIncomingRequest( + string $uri = '', + array $query = [], + ?AppConfig $appConfig = null + ): IncomingRequest { + $_POST = $_GET = $_SERVER = $_REQUEST = $_ENV = $_COOKIE = $_SESSION = []; + + $_SERVER['REQUEST_URI'] = '/' . $uri . ($query ? '?' . http_build_query($query) : ''); + $_SERVER['SCRIPT_NAME'] = '/index.php'; + + $appConfig ??= $this->appConfig; + + $siteUri = new URI($appConfig->baseURL . $uri); + if ($query !== []) { + $_GET = $_REQUEST = $query; + $siteUri->setQueryArray($query); + } + + return new IncomingRequest( + $appConfig, + $siteUri, + null, + new UserAgent() + ); + } + + /** + * @phpstan-param list $params + */ + private function createCLIRequest(array $params = [], ?AppConfig $appConfig = null): CLIRequest + { + $_POST = $_GET = $_SERVER = $_REQUEST = $_ENV = $_COOKIE = $_SESSION = []; + + $_SERVER['argv'] = ['public/index.php', ...$params]; + $_SERVER['SCRIPT_NAME'] = 'public/index.php'; + + $appConfig ??= $this->appConfig; + + return new CLIRequest($appConfig); + } + + private function createPageCache(?CacheConfig $cacheConfig = null): pageCache + { + $cache = mock(CacheFactory::class); + + $cacheConfig ??= new CacheConfig(); + + return new PageCache($cacheConfig, $cache); + } + + public function testCachePageIncomingRequest() + { + $pageCache = $this->createPageCache(); + + $request = $this->createIncomingRequest('foo/bar'); + + $response = new Response($this->appConfig); + $response->setHeader('ETag', 'abcd1234'); + $response->setBody('The response body.'); + + $return = $pageCache->cachePage($request, $response, 300); + + $this->assertTrue($return); + + // Check cache with a request with the same URI path. + $request = $this->createIncomingRequest('foo/bar'); + $cachedResponse = $pageCache->getCachedResponse($request, new Response($this->appConfig)); + + $this->assertInstanceOf(ResponseInterface::class, $cachedResponse); + $this->assertSame('The response body.', $cachedResponse->getBody()); + $this->assertSame('abcd1234', $cachedResponse->getHeaderLine('ETag')); + + // Check cache with a request with the same URI path and different query string. + $request = $this->createIncomingRequest('foo/bar', ['foo' => 'bar', 'bar' => 'baz']); + $cachedResponse = $pageCache->getCachedResponse($request, new Response($this->appConfig)); + + $this->assertInstanceOf(ResponseInterface::class, $cachedResponse); + $this->assertSame('The response body.', $cachedResponse->getBody()); + $this->assertSame('abcd1234', $cachedResponse->getHeaderLine('ETag')); + + // Check cache with another request with the different URI path. + $request = $this->createIncomingRequest('another'); + + $cachedResponse = $pageCache->getCachedResponse($request, new Response($this->appConfig)); + + $this->assertNull($cachedResponse); + } + + public function testCachePageIncomingRequestWithCacheQueryString() + { + $cacheConfig = new CacheConfig(); + $cacheConfig->cacheQueryString = true; + $pageCache = $this->createPageCache($cacheConfig); + + $request = $this->createIncomingRequest('foo/bar', ['foo' => 'bar', 'bar' => 'baz']); + + $response = new Response($this->appConfig); + $response->setHeader('ETag', 'abcd1234'); + $response->setBody('The response body.'); + + $return = $pageCache->cachePage($request, $response, 300); + + $this->assertTrue($return); + + // Check cache with a request with the same URI path and same query string. + $this->createIncomingRequest('foo/bar', ['foo' => 'bar', 'bar' => 'baz']); + $cachedResponse = $pageCache->getCachedResponse($request, new Response($this->appConfig)); + + $this->assertInstanceOf(ResponseInterface::class, $cachedResponse); + $this->assertSame('The response body.', $cachedResponse->getBody()); + $this->assertSame('abcd1234', $cachedResponse->getHeaderLine('ETag')); + + // Check cache with a request with the same URI path and different query string. + $request = $this->createIncomingRequest('foo/bar', ['xfoo' => 'bar', 'bar' => 'baz']); + $cachedResponse = $pageCache->getCachedResponse($request, new Response($this->appConfig)); + + $this->assertNull($cachedResponse); + + // Check cache with another request with the different URI path. + $request = $this->createIncomingRequest('another'); + + $cachedResponse = $pageCache->getCachedResponse($request, new Response($this->appConfig)); + + $this->assertNull($cachedResponse); + } + + public function testCachePageCLIRequest() + { + $pageCache = $this->createPageCache(); + + $request = $this->createCLIRequest(['foo', 'bar']); + + $response = new Response($this->appConfig); + $response->setBody('The response body.'); + + $return = $pageCache->cachePage($request, $response, 300); + + $this->assertTrue($return); + + // Check cache with a request with the same params. + $request = $this->createCLIRequest(['foo', 'bar']); + $cachedResponse = $pageCache->getCachedResponse($request, new Response($this->appConfig)); + + $this->assertInstanceOf(ResponseInterface::class, $cachedResponse); + $this->assertSame('The response body.', $cachedResponse->getBody()); + + // Check cache with another request with the different params. + $request = $this->createCLIRequest(['baz']); + + $cachedResponse = $pageCache->getCachedResponse($request, new Response($this->appConfig)); + + $this->assertNull($cachedResponse); + } + + public function testUnserializeError() + { + $this->expectException(ErrorException::class); + $this->expectExceptionMessage('unserialize(): Error at offset 0 of 12 bytes'); + + $cache = mock(CacheFactory::class); + $cacheConfig = new CacheConfig(); + $pageCache = new PageCache($cacheConfig, $cache); + + $request = $this->createIncomingRequest('foo/bar'); + + $response = new Response($this->appConfig); + $response->setHeader('ETag', 'abcd1234'); + $response->setBody('The response body.'); + + $pageCache->cachePage($request, $response, 300); + + $cacheKey = $pageCache->generateCacheKey($request); + + // Save invalid data. + $cache->save($cacheKey, 'Invalid data'); + + // Check cache with a request with the same URI path. + $pageCache->getCachedResponse($request, new Response($this->appConfig)); + } + + public function testInvalidCacheError() + { + $this->expectException(Exception::class); + $this->expectExceptionMessage('Error unserializing page cache'); + + $cache = mock(CacheFactory::class); + $cacheConfig = new CacheConfig(); + $pageCache = new PageCache($cacheConfig, $cache); + + $request = $this->createIncomingRequest('foo/bar'); + + $response = new Response($this->appConfig); + $response->setHeader('ETag', 'abcd1234'); + $response->setBody('The response body.'); + + $pageCache->cachePage($request, $response, 300); + + $cacheKey = $pageCache->generateCacheKey($request); + + // Save invalid data. + $cache->save($cacheKey, serialize(['a' => '1'])); + + // Check cache with a request with the same URI path. + $pageCache->getCachedResponse($request, new Response($this->appConfig)); + } +} From 28f4a88166c7a6d455a9af1c38b65823a7a7bcbb Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 30 Jun 2023 20:04:57 +0900 Subject: [PATCH 02/13] fix: [BC] fix wrong types for Requests Fixes the following errors: ------ ------------------------------------------------------------------ Line system/CodeIgniter.php ------ ------------------------------------------------------------------ 529 Parameter #1 $request of method CodeIgniter\Cache\PageCache::cachePage() expects CodeIgniter\HTTP\CLIRequest|CodeIgniter\HTTP\IncomingRequest, CodeIgniter\HTTP\Request|null given. 685 Parameter #1 $request of method CodeIgniter\Cache\PageCache::getCachedResponse() expects CodeIgniter\HTTP\CLIRequest|CodeIgniter\HTTP\IncomingRequest, CodeIgniter\HTTP\Request|null given. ------ ------------------------------------------------------------------ --- phpstan-baseline.neon.dist | 10 ---------- system/CodeIgniter.php | 8 +++++--- system/Test/FeatureTestCase.php | 16 +++++++++++----- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/phpstan-baseline.neon.dist b/phpstan-baseline.neon.dist index 2d60b2b599d2..e1ecece1f5f0 100644 --- a/phpstan-baseline.neon.dist +++ b/phpstan-baseline.neon.dist @@ -25,16 +25,6 @@ parameters: count: 1 path: system/Cache/Handlers/RedisHandler.php - - - message: "#^Call to an undefined method CodeIgniter\\\\HTTP\\\\Request\\:\\:getPost\\(\\)\\.$#" - count: 1 - path: system/CodeIgniter.php - - - - message: "#^Call to an undefined method CodeIgniter\\\\HTTP\\\\Request\\:\\:setLocale\\(\\)\\.$#" - count: 1 - path: system/CodeIgniter.php - - message: "#^Property CodeIgniter\\\\Database\\\\BaseBuilder\\:\\:\\$db \\(CodeIgniter\\\\Database\\\\BaseConnection\\) in empty\\(\\) is not falsy\\.$#" count: 1 diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index b8625b281978..1d4ccd12fed0 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -85,7 +85,7 @@ class CodeIgniter /** * Current request. * - * @var CLIRequest|IncomingRequest|Request|null + * @var CLIRequest|IncomingRequest|null */ protected $request; @@ -471,7 +471,7 @@ protected function handleRequest(?RouteCollectionInterface $routes, Cache $cache return $possibleResponse; } - if ($possibleResponse instanceof Request) { + if ($possibleResponse instanceof IncomingRequest || $possibleResponse instanceof CLIRequest) { $this->request = $possibleResponse; } } @@ -611,9 +611,11 @@ protected function startBenchmark() * Sets a Request object to be used for this request. * Used when running certain tests. * + * @param CLIRequest|IncomingRequest $request + * * @return $this */ - public function setRequest(Request $request) + public function setRequest($request) { $this->request = $request; diff --git a/system/Test/FeatureTestCase.php b/system/Test/FeatureTestCase.php index 7163d3e85717..371e302c59ae 100644 --- a/system/Test/FeatureTestCase.php +++ b/system/Test/FeatureTestCase.php @@ -12,6 +12,7 @@ namespace CodeIgniter\Test; use CodeIgniter\Events\Events; +use CodeIgniter\HTTP\CLIRequest; use CodeIgniter\HTTP\Exceptions\RedirectException; use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\Request; @@ -328,11 +329,13 @@ protected function setupHeaders(IncomingRequest $request) * * Always populate the GET vars based on the URI. * - * @return Request + * @param CLIRequest|IncomingRequest $request + * + * @return CLIRequest|IncomingRequest * * @throws ReflectionException */ - protected function populateGlobals(string $method, Request $request, ?array $params = null) + protected function populateGlobals(string $method, $request, ?array $params = null) { // $params should set the query vars if present, // otherwise set it from the URL. @@ -357,10 +360,13 @@ protected function populateGlobals(string $method, Request $request, ?array $par * This allows the body to be formatted in a way that the controller is going to * expect as in the case of testing a JSON or XML API. * - * @param array|null $params The parameters to be formatted and put in the body. If this is empty, it will get the - * what has been loaded into the request global of the request class. + * @param CLIRequest|IncomingRequest $request + * @param array|null $params The parameters to be formatted and put in the body. If this is empty, it will get the + * what has been loaded into the request global of the request class. + * + * @return CLIRequest|IncomingRequest */ - protected function setRequestBody(Request $request, ?array $params = null): Request + protected function setRequestBody($request, ?array $params = null) { if (isset($this->requestBody) && $this->requestBody !== '') { $request->setBody($this->requestBody); From 397194166a413518e94a325b6aa32f691a0bb294 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 30 Jun 2023 20:09:09 +0900 Subject: [PATCH 03/13] chore: add exemptions for CodeIgniter\Cache\PageCache --- deptrac.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/deptrac.yaml b/deptrac.yaml index bf39d4f54734..96cfc8fe522a 100644 --- a/deptrac.yaml +++ b/deptrac.yaml @@ -222,6 +222,10 @@ parameters: - Cache skip_violations: # Individual class exemptions + CodeIgniter\Cache\PageCache: + - CodeIgniter\HTTP\CLIRequest + - CodeIgniter\HTTP\IncomingRequest + - CodeIgniter\HTTP\ResponseInterface CodeIgniter\Entity\Cast\URICast: - CodeIgniter\HTTP\URI CodeIgniter\Log\Handlers\ChromeLoggerHandler: From b2afd719fde71229afa1e2082baa5ca7e6dbcceb Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 3 Jul 2023 11:31:07 +0900 Subject: [PATCH 04/13] refactor: rename PageCache to ResponseCache --- .../Cache/{PageCache.php => ResponseCache.php} | 2 +- system/CodeIgniter.php | 6 +++--- system/Config/BaseService.php | 4 ++-- system/Config/Services.php | 12 ++++++------ .../{PageCacheTest.php => ResponseCacheTest.php} | 16 ++++++++-------- 5 files changed, 20 insertions(+), 20 deletions(-) rename system/Cache/{PageCache.php => ResponseCache.php} (99%) rename tests/system/Cache/{PageCacheTest.php => ResponseCacheTest.php} (94%) diff --git a/system/Cache/PageCache.php b/system/Cache/ResponseCache.php similarity index 99% rename from system/Cache/PageCache.php rename to system/Cache/ResponseCache.php index ad52f02433bc..a04b369b348c 100644 --- a/system/Cache/PageCache.php +++ b/system/Cache/ResponseCache.php @@ -20,7 +20,7 @@ /** * Web Page Caching */ -class PageCache +class ResponseCache { /** * Whether to take the URL query string into consideration when generating diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 1d4ccd12fed0..5ce7ac69b2c4 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -12,7 +12,7 @@ namespace CodeIgniter; use Closure; -use CodeIgniter\Cache\PageCache; +use CodeIgniter\Cache\ResponseCache; use CodeIgniter\Debug\Timer; use CodeIgniter\Events\Events; use CodeIgniter\Exceptions\FrameworkException; @@ -179,7 +179,7 @@ class CodeIgniter /** * Web Page Caching */ - protected PageCache $pageCache; + protected ResponseCache $pageCache; /** * Constructor. @@ -189,7 +189,7 @@ public function __construct(App $config) $this->startTime = microtime(true); $this->config = $config; - $this->pageCache = Services::pagecache(); + $this->pageCache = Services::responsecache(); } /** diff --git a/system/Config/BaseService.php b/system/Config/BaseService.php index f98ec9192856..133805a6a585 100644 --- a/system/Config/BaseService.php +++ b/system/Config/BaseService.php @@ -14,7 +14,7 @@ use CodeIgniter\Autoloader\Autoloader; use CodeIgniter\Autoloader\FileLocator; use CodeIgniter\Cache\CacheInterface; -use CodeIgniter\Cache\PageCache; +use CodeIgniter\Cache\ResponseCache; use CodeIgniter\CLI\Commands; use CodeIgniter\CodeIgniter; use CodeIgniter\Database\ConnectionInterface; @@ -112,13 +112,13 @@ * @method static Logger logger($getShared = true) * @method static MigrationRunner migrations(Migrations $config = null, ConnectionInterface $db = null, $getShared = true) * @method static Negotiate negotiator(RequestInterface $request = null, $getShared = true) - * @method static PageCache pagecache(?Cache $config = null, ?CacheInterface $cache = null, bool $getShared = true) * @method static Pager pager(ConfigPager $config = null, RendererInterface $view = null, $getShared = true) * @method static Parser parser($viewPath = null, ConfigView $config = null, $getShared = true) * @method static RedirectResponse redirectresponse(App $config = null, $getShared = true) * @method static View renderer($viewPath = null, ConfigView $config = null, $getShared = true) * @method static IncomingRequest|CLIRequest request(App $config = null, $getShared = true) * @method static ResponseInterface response(App $config = null, $getShared = true) + * @method static ResponseCache responsecache(?Cache $config = null, ?CacheInterface $cache = null, bool $getShared = true) * @method static Router router(RouteCollectionInterface $routes = null, Request $request = null, $getShared = true) * @method static RouteCollection routes($getShared = true) * @method static Security security(App $config = null, $getShared = true) diff --git a/system/Config/Services.php b/system/Config/Services.php index 14c9b122cc36..c8ded8034257 100644 --- a/system/Config/Services.php +++ b/system/Config/Services.php @@ -13,7 +13,7 @@ use CodeIgniter\Cache\CacheFactory; use CodeIgniter\Cache\CacheInterface; -use CodeIgniter\Cache\PageCache; +use CodeIgniter\Cache\ResponseCache; use CodeIgniter\CLI\Commands; use CodeIgniter\CodeIgniter; use CodeIgniter\Database\ConnectionInterface; @@ -440,20 +440,20 @@ public static function negotiator(?RequestInterface $request = null, bool $getSh } /** - * Return the PageCache. + * Return the ResponseCache. * - * @return PageCache + * @return ResponseCache */ - public static function pagecache(?Cache $config = null, ?CacheInterface $cache = null, bool $getShared = true) + public static function responsecache(?Cache $config = null, ?CacheInterface $cache = null, bool $getShared = true) { if ($getShared) { - return static::getSharedInstance('pagecache', $config, $cache); + return static::getSharedInstance('responsecache', $config, $cache); } $config ??= config(Cache::class); $cache ??= AppServices::cache(); - return new PageCache($config, $cache); + return new ResponseCache($config, $cache); } /** diff --git a/tests/system/Cache/PageCacheTest.php b/tests/system/Cache/ResponseCacheTest.php similarity index 94% rename from tests/system/Cache/PageCacheTest.php rename to tests/system/Cache/ResponseCacheTest.php index d95c9f10f91f..75038e2753fa 100644 --- a/tests/system/Cache/PageCacheTest.php +++ b/tests/system/Cache/ResponseCacheTest.php @@ -30,7 +30,7 @@ * * @group Others */ -final class PageCacheTest extends CIUnitTestCase +final class ResponseCacheTest extends CIUnitTestCase { private AppConfig $appConfig; @@ -82,18 +82,18 @@ private function createCLIRequest(array $params = [], ?AppConfig $appConfig = nu return new CLIRequest($appConfig); } - private function createPageCache(?CacheConfig $cacheConfig = null): pageCache + private function createResponseCache(?CacheConfig $cacheConfig = null): ResponseCache { $cache = mock(CacheFactory::class); $cacheConfig ??= new CacheConfig(); - return new PageCache($cacheConfig, $cache); + return new ResponseCache($cacheConfig, $cache); } public function testCachePageIncomingRequest() { - $pageCache = $this->createPageCache(); + $pageCache = $this->createResponseCache(); $request = $this->createIncomingRequest('foo/bar'); @@ -133,7 +133,7 @@ public function testCachePageIncomingRequestWithCacheQueryString() { $cacheConfig = new CacheConfig(); $cacheConfig->cacheQueryString = true; - $pageCache = $this->createPageCache($cacheConfig); + $pageCache = $this->createResponseCache($cacheConfig); $request = $this->createIncomingRequest('foo/bar', ['foo' => 'bar', 'bar' => 'baz']); @@ -169,7 +169,7 @@ public function testCachePageIncomingRequestWithCacheQueryString() public function testCachePageCLIRequest() { - $pageCache = $this->createPageCache(); + $pageCache = $this->createResponseCache(); $request = $this->createCLIRequest(['foo', 'bar']); @@ -202,7 +202,7 @@ public function testUnserializeError() $cache = mock(CacheFactory::class); $cacheConfig = new CacheConfig(); - $pageCache = new PageCache($cacheConfig, $cache); + $pageCache = new ResponseCache($cacheConfig, $cache); $request = $this->createIncomingRequest('foo/bar'); @@ -228,7 +228,7 @@ public function testInvalidCacheError() $cache = mock(CacheFactory::class); $cacheConfig = new CacheConfig(); - $pageCache = new PageCache($cacheConfig, $cache); + $pageCache = new ResponseCache($cacheConfig, $cache); $request = $this->createIncomingRequest('foo/bar'); From d0b986802f5d8c82a9c70c5d4421ebdd3e762ac5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 3 Jul 2023 11:33:05 +0900 Subject: [PATCH 05/13] refactor: rename cachePage() to make() --- system/Cache/ResponseCache.php | 2 +- system/CodeIgniter.php | 2 +- tests/system/Cache/ResponseCacheTest.php | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/system/Cache/ResponseCache.php b/system/Cache/ResponseCache.php index a04b369b348c..20e871cc2f3c 100644 --- a/system/Cache/ResponseCache.php +++ b/system/Cache/ResponseCache.php @@ -74,7 +74,7 @@ public function generateCacheKey($request): string * * @params int $ttl time to live in seconds. */ - public function cachePage($request, ResponseInterface $response, int $ttl): bool + public function make($request, ResponseInterface $response, int $ttl): bool { $headers = []; diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 5ce7ac69b2c4..ace073b5ed9e 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -526,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->pageCache->cachePage($this->request, $this->response, static::$cacheTTL); + $this->pageCache->make($this->request, $this->response, static::$cacheTTL); } // Update the performance metrics diff --git a/tests/system/Cache/ResponseCacheTest.php b/tests/system/Cache/ResponseCacheTest.php index 75038e2753fa..a24a91e2ea52 100644 --- a/tests/system/Cache/ResponseCacheTest.php +++ b/tests/system/Cache/ResponseCacheTest.php @@ -101,7 +101,7 @@ public function testCachePageIncomingRequest() $response->setHeader('ETag', 'abcd1234'); $response->setBody('The response body.'); - $return = $pageCache->cachePage($request, $response, 300); + $return = $pageCache->make($request, $response, 300); $this->assertTrue($return); @@ -141,7 +141,7 @@ public function testCachePageIncomingRequestWithCacheQueryString() $response->setHeader('ETag', 'abcd1234'); $response->setBody('The response body.'); - $return = $pageCache->cachePage($request, $response, 300); + $return = $pageCache->make($request, $response, 300); $this->assertTrue($return); @@ -176,7 +176,7 @@ public function testCachePageCLIRequest() $response = new Response($this->appConfig); $response->setBody('The response body.'); - $return = $pageCache->cachePage($request, $response, 300); + $return = $pageCache->make($request, $response, 300); $this->assertTrue($return); @@ -210,7 +210,7 @@ public function testUnserializeError() $response->setHeader('ETag', 'abcd1234'); $response->setBody('The response body.'); - $pageCache->cachePage($request, $response, 300); + $pageCache->make($request, $response, 300); $cacheKey = $pageCache->generateCacheKey($request); @@ -236,7 +236,7 @@ public function testInvalidCacheError() $response->setHeader('ETag', 'abcd1234'); $response->setBody('The response body.'); - $pageCache->cachePage($request, $response, 300); + $pageCache->make($request, $response, 300); $cacheKey = $pageCache->generateCacheKey($request); From 8b0230a2278d08bbaccb297197be156e254e0937 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 3 Jul 2023 11:33:53 +0900 Subject: [PATCH 06/13] refactor: rename getCachedResponse() to get() --- deptrac.yaml | 2 +- system/Cache/ResponseCache.php | 2 +- system/CodeIgniter.php | 2 +- tests/system/Cache/ResponseCacheTest.php | 20 ++++++++++---------- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/deptrac.yaml b/deptrac.yaml index 96cfc8fe522a..d2db0605103b 100644 --- a/deptrac.yaml +++ b/deptrac.yaml @@ -222,7 +222,7 @@ parameters: - Cache skip_violations: # Individual class exemptions - CodeIgniter\Cache\PageCache: + CodeIgniter\Cache\ResponseCache: - CodeIgniter\HTTP\CLIRequest - CodeIgniter\HTTP\IncomingRequest - CodeIgniter\HTTP\ResponseInterface diff --git a/system/Cache/ResponseCache.php b/system/Cache/ResponseCache.php index 20e871cc2f3c..3328f3824e1e 100644 --- a/system/Cache/ResponseCache.php +++ b/system/Cache/ResponseCache.php @@ -94,7 +94,7 @@ public function make($request, ResponseInterface $response, int $ttl): bool * * @param CLIRequest|IncomingRequest $request */ - public function getCachedResponse($request, ResponseInterface $response): ?ResponseInterface + public function get($request, ResponseInterface $response): ?ResponseInterface { if ($cachedResponse = $this->cache->get($this->generateCacheKey($request))) { $cachedResponse = unserialize($cachedResponse); diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index ace073b5ed9e..f61e99936aa4 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -684,7 +684,7 @@ protected function forceSecureAccess($duration = 31_536_000) */ public function displayCache(Cache $config) { - if ($cachedResponse = $this->pageCache->getCachedResponse($this->request, $this->response)) { + if ($cachedResponse = $this->pageCache->get($this->request, $this->response)) { $this->response = $cachedResponse; $this->totalTime = $this->benchmark->getElapsedTime('total_execution'); diff --git a/tests/system/Cache/ResponseCacheTest.php b/tests/system/Cache/ResponseCacheTest.php index a24a91e2ea52..b97efa223233 100644 --- a/tests/system/Cache/ResponseCacheTest.php +++ b/tests/system/Cache/ResponseCacheTest.php @@ -107,7 +107,7 @@ public function testCachePageIncomingRequest() // Check cache with a request with the same URI path. $request = $this->createIncomingRequest('foo/bar'); - $cachedResponse = $pageCache->getCachedResponse($request, new Response($this->appConfig)); + $cachedResponse = $pageCache->get($request, new Response($this->appConfig)); $this->assertInstanceOf(ResponseInterface::class, $cachedResponse); $this->assertSame('The response body.', $cachedResponse->getBody()); @@ -115,7 +115,7 @@ public function testCachePageIncomingRequest() // Check cache with a request with the same URI path and different query string. $request = $this->createIncomingRequest('foo/bar', ['foo' => 'bar', 'bar' => 'baz']); - $cachedResponse = $pageCache->getCachedResponse($request, new Response($this->appConfig)); + $cachedResponse = $pageCache->get($request, new Response($this->appConfig)); $this->assertInstanceOf(ResponseInterface::class, $cachedResponse); $this->assertSame('The response body.', $cachedResponse->getBody()); @@ -124,7 +124,7 @@ public function testCachePageIncomingRequest() // Check cache with another request with the different URI path. $request = $this->createIncomingRequest('another'); - $cachedResponse = $pageCache->getCachedResponse($request, new Response($this->appConfig)); + $cachedResponse = $pageCache->get($request, new Response($this->appConfig)); $this->assertNull($cachedResponse); } @@ -147,7 +147,7 @@ public function testCachePageIncomingRequestWithCacheQueryString() // Check cache with a request with the same URI path and same query string. $this->createIncomingRequest('foo/bar', ['foo' => 'bar', 'bar' => 'baz']); - $cachedResponse = $pageCache->getCachedResponse($request, new Response($this->appConfig)); + $cachedResponse = $pageCache->get($request, new Response($this->appConfig)); $this->assertInstanceOf(ResponseInterface::class, $cachedResponse); $this->assertSame('The response body.', $cachedResponse->getBody()); @@ -155,14 +155,14 @@ public function testCachePageIncomingRequestWithCacheQueryString() // Check cache with a request with the same URI path and different query string. $request = $this->createIncomingRequest('foo/bar', ['xfoo' => 'bar', 'bar' => 'baz']); - $cachedResponse = $pageCache->getCachedResponse($request, new Response($this->appConfig)); + $cachedResponse = $pageCache->get($request, new Response($this->appConfig)); $this->assertNull($cachedResponse); // Check cache with another request with the different URI path. $request = $this->createIncomingRequest('another'); - $cachedResponse = $pageCache->getCachedResponse($request, new Response($this->appConfig)); + $cachedResponse = $pageCache->get($request, new Response($this->appConfig)); $this->assertNull($cachedResponse); } @@ -182,7 +182,7 @@ public function testCachePageCLIRequest() // Check cache with a request with the same params. $request = $this->createCLIRequest(['foo', 'bar']); - $cachedResponse = $pageCache->getCachedResponse($request, new Response($this->appConfig)); + $cachedResponse = $pageCache->get($request, new Response($this->appConfig)); $this->assertInstanceOf(ResponseInterface::class, $cachedResponse); $this->assertSame('The response body.', $cachedResponse->getBody()); @@ -190,7 +190,7 @@ public function testCachePageCLIRequest() // Check cache with another request with the different params. $request = $this->createCLIRequest(['baz']); - $cachedResponse = $pageCache->getCachedResponse($request, new Response($this->appConfig)); + $cachedResponse = $pageCache->get($request, new Response($this->appConfig)); $this->assertNull($cachedResponse); } @@ -218,7 +218,7 @@ public function testUnserializeError() $cache->save($cacheKey, 'Invalid data'); // Check cache with a request with the same URI path. - $pageCache->getCachedResponse($request, new Response($this->appConfig)); + $pageCache->get($request, new Response($this->appConfig)); } public function testInvalidCacheError() @@ -244,6 +244,6 @@ public function testInvalidCacheError() $cache->save($cacheKey, serialize(['a' => '1'])); // Check cache with a request with the same URI path. - $pageCache->getCachedResponse($request, new Response($this->appConfig)); + $pageCache->get($request, new Response($this->appConfig)); } } From f0748dde688a8004851480f58a5c19246e3749bb Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 3 Jul 2023 11:55:04 +0900 Subject: [PATCH 07/13] refactor: add ResponseCache::$ttl and use it --- system/Cache/ResponseCache.php | 28 ++++++++++++++++++++---- system/CodeIgniter.php | 10 ++++++--- system/Controller.php | 7 +++--- tests/system/Cache/ResponseCacheTest.php | 12 +++++----- tests/system/CodeIgniterTest.php | 2 +- 5 files changed, 42 insertions(+), 17 deletions(-) diff --git a/system/Cache/ResponseCache.php b/system/Cache/ResponseCache.php index 3328f3824e1e..8a3865b3814e 100644 --- a/system/Cache/ResponseCache.php +++ b/system/Cache/ResponseCache.php @@ -37,6 +37,13 @@ class ResponseCache */ protected $cacheQueryString = false; + /** + * Cache time to live. + * + * @var int seconds + */ + protected int $ttl = 0; + protected CacheInterface $cache; public function __construct(CacheConfig $config, CacheInterface $cache) @@ -45,6 +52,21 @@ public function __construct(CacheConfig $config, CacheInterface $cache) $this->cache = $cache; } + public function getTtl(): int + { + return $this->ttl; + } + + /** + * @return $this + */ + public function setTtl(int $ttl) + { + $this->ttl = $ttl; + + return $this; + } + /** * Generates the cache key to use from the current request. * @@ -71,10 +93,8 @@ public function generateCacheKey($request): string * Caches the full response from the current request. * * @param CLIRequest|IncomingRequest $request - * - * @params int $ttl time to live in seconds. */ - public function make($request, ResponseInterface $response, int $ttl): bool + public function make($request, ResponseInterface $response): bool { $headers = []; @@ -85,7 +105,7 @@ public function make($request, ResponseInterface $response, int $ttl): bool return $this->cache->save( $this->generateCacheKey($request), serialize(['headers' => $headers, 'output' => $response->getBody()]), - $ttl + $this->ttl ); } diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index f61e99936aa4..20d788132677 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -128,6 +128,8 @@ class CodeIgniter * Cache expiration time * * @var int seconds + * + * @deprecated 4.4.0 Moved to ResponseCache::$ttl. No longer used. */ protected static $cacheTTL = 0; @@ -338,7 +340,7 @@ public function run(?RouteCollectionInterface $routes = null, bool $returnRespon ); } - static::$cacheTTL = 0; + $this->pageCache->setTtl(0); $this->bufferLevel = ob_get_level(); $this->startBenchmark(); @@ -525,8 +527,8 @@ protected function handleRequest(?RouteCollectionInterface $routes, Cache $cache // Cache it without the performance metrics replaced // 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->pageCache->make($this->request, $this->response, static::$cacheTTL); + if ($this->pageCache->getTtl() > 0) { + $this->pageCache->make($this->request, $this->response); } // Update the performance metrics @@ -699,6 +701,8 @@ public function displayCache(Cache $config) /** * Tells the app that the final output should be cached. + * + * @deprecated 4.4.0 Moved to ResponseCache::setTtl(). to No longer used. */ public static function cache(int $time) { diff --git a/system/Controller.php b/system/Controller.php index 64de91ab2938..e808e0b8c20f 100644 --- a/system/Controller.php +++ b/system/Controller.php @@ -104,12 +104,13 @@ protected function forceHTTPS(int $duration = 31_536_000) } /** - * Provides a simple way to tie into the main CodeIgniter class and - * tell it how long to cache the current page for. + * How long to cache the current page for. + * + * @params int $time time to live in seconds. */ protected function cachePage(int $time) { - CodeIgniter::cache($time); + Services::responsecache()->setTtl($time); } /** diff --git a/tests/system/Cache/ResponseCacheTest.php b/tests/system/Cache/ResponseCacheTest.php index b97efa223233..a1079e63a463 100644 --- a/tests/system/Cache/ResponseCacheTest.php +++ b/tests/system/Cache/ResponseCacheTest.php @@ -88,7 +88,7 @@ private function createResponseCache(?CacheConfig $cacheConfig = null): Response $cacheConfig ??= new CacheConfig(); - return new ResponseCache($cacheConfig, $cache); + return (new ResponseCache($cacheConfig, $cache))->setTtl(300); } public function testCachePageIncomingRequest() @@ -101,7 +101,7 @@ public function testCachePageIncomingRequest() $response->setHeader('ETag', 'abcd1234'); $response->setBody('The response body.'); - $return = $pageCache->make($request, $response, 300); + $return = $pageCache->make($request, $response); $this->assertTrue($return); @@ -141,7 +141,7 @@ public function testCachePageIncomingRequestWithCacheQueryString() $response->setHeader('ETag', 'abcd1234'); $response->setBody('The response body.'); - $return = $pageCache->make($request, $response, 300); + $return = $pageCache->make($request, $response); $this->assertTrue($return); @@ -176,7 +176,7 @@ public function testCachePageCLIRequest() $response = new Response($this->appConfig); $response->setBody('The response body.'); - $return = $pageCache->make($request, $response, 300); + $return = $pageCache->make($request, $response); $this->assertTrue($return); @@ -210,7 +210,7 @@ public function testUnserializeError() $response->setHeader('ETag', 'abcd1234'); $response->setBody('The response body.'); - $pageCache->make($request, $response, 300); + $pageCache->make($request, $response); $cacheKey = $pageCache->generateCacheKey($request); @@ -236,7 +236,7 @@ public function testInvalidCacheError() $response->setHeader('ETag', 'abcd1234'); $response->setBody('The response body.'); - $pageCache->make($request, $response, 300); + $pageCache->make($request, $response); $cacheKey = $pageCache->generateCacheKey($request); diff --git a/tests/system/CodeIgniterTest.php b/tests/system/CodeIgniterTest.php index b2430a26a7c8..25ee4eda832a 100644 --- a/tests/system/CodeIgniterTest.php +++ b/tests/system/CodeIgniterTest.php @@ -838,7 +838,7 @@ public function testPageCacheWithCacheQueryString( $routePath = explode('?', $testingUrl)[0]; $string = 'This is a test page, to check cache configuration'; $routes->add($routePath, static function () use ($string) { - CodeIgniter::cache(60); + Services::responsecache()->setTtl(60); $response = Services::response(); return $response->setBody($string); From fd4e951280dd21cf6900ccd891899043d895d757 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 3 Jul 2023 12:42:27 +0900 Subject: [PATCH 08/13] test: set $_SERVER['SCRIPT_NAME'] --- tests/system/CodeIgniterTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/system/CodeIgniterTest.php b/tests/system/CodeIgniterTest.php index 25ee4eda832a..584310ba08c6 100644 --- a/tests/system/CodeIgniterTest.php +++ b/tests/system/CodeIgniterTest.php @@ -96,6 +96,7 @@ public function testRunClosureRoute() $_SERVER['argc'] = 2; $_SERVER['REQUEST_URI'] = '/pages/about'; + $_SERVER['SCRIPT_NAME'] = '/index.php'; // Inject mock router. $routes = Services::routes(); @@ -193,6 +194,7 @@ public function testControllersCanReturnString() $_SERVER['argc'] = 2; $_SERVER['REQUEST_URI'] = '/pages/about'; + $_SERVER['SCRIPT_NAME'] = '/index.php'; // Inject mock router. $routes = Services::routes(); @@ -216,6 +218,7 @@ public function testControllersCanReturnResponseObject() $_SERVER['argc'] = 2; $_SERVER['REQUEST_URI'] = '/pages/about'; + $_SERVER['SCRIPT_NAME'] = '/index.php'; // Inject mock router. $routes = Services::routes(); @@ -244,6 +247,7 @@ public function testControllersCanReturnDownloadResponseObject() $_SERVER['argc'] = 2; $_SERVER['REQUEST_URI'] = '/pages/about'; + $_SERVER['SCRIPT_NAME'] = '/index.php'; // Inject mock router. $routes = Services::routes(); @@ -268,6 +272,7 @@ public function testRunExecuteFilterByClassName() $_SERVER['argc'] = 2; $_SERVER['REQUEST_URI'] = '/pages/about'; + $_SERVER['SCRIPT_NAME'] = '/index.php'; // Inject mock router. $routes = Services::routes(); @@ -298,6 +303,7 @@ public function testRegisterSameFilterTwiceWithDifferentArgument() $_SERVER['argc'] = 2; $_SERVER['REQUEST_URI'] = '/pages/about'; + $_SERVER['SCRIPT_NAME'] = '/index.php'; $routes = Services::routes(); $routes->add( @@ -331,6 +337,7 @@ public function testDisableControllerFilters() $_SERVER['argc'] = 2; $_SERVER['REQUEST_URI'] = '/pages/about'; + $_SERVER['SCRIPT_NAME'] = '/index.php'; // Inject mock router. $routes = Services::routes(); @@ -452,6 +459,7 @@ public function testRunRedirectionWithNamed() $_SERVER['argc'] = 2; $_SERVER['REQUEST_URI'] = '/example'; + $_SERVER['SCRIPT_NAME'] = '/index.php'; // Inject mock router. $routes = Services::routes(); @@ -475,6 +483,7 @@ public function testRunRedirectionWithURI() $_SERVER['argc'] = 2; $_SERVER['REQUEST_URI'] = '/example'; + $_SERVER['SCRIPT_NAME'] = '/index.php'; // Inject mock router. $routes = Services::routes(); @@ -501,6 +510,7 @@ public function testRunRedirectionWithGET() $_SERVER['argc'] = 2; $_SERVER['REQUEST_URI'] = '/example'; + $_SERVER['SCRIPT_NAME'] = '/index.php'; $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1'; $_SERVER['REQUEST_METHOD'] = 'GET'; @@ -527,6 +537,7 @@ public function testRunRedirectionWithGETAndHTTPCode301() $_SERVER['argc'] = 2; $_SERVER['REQUEST_URI'] = '/example'; + $_SERVER['SCRIPT_NAME'] = '/index.php'; $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1'; $_SERVER['REQUEST_METHOD'] = 'GET'; @@ -551,6 +562,7 @@ public function testRunRedirectionWithPOSTAndHTTPCode301() $_SERVER['argc'] = 2; $_SERVER['REQUEST_URI'] = '/example'; + $_SERVER['SCRIPT_NAME'] = '/index.php'; $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1'; $_SERVER['REQUEST_METHOD'] = 'POST'; @@ -615,6 +627,7 @@ public function testNotStoresPreviousURL() $_SERVER['argc'] = 2; $_SERVER['REQUEST_URI'] = '/example'; + $_SERVER['SCRIPT_NAME'] = '/index.php'; $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1'; $_SERVER['REQUEST_METHOD'] = 'GET'; @@ -638,6 +651,7 @@ public function testNotStoresPreviousURLByCheckingContentType() $_SERVER['argc'] = 2; $_SERVER['REQUEST_URI'] = '/image'; + $_SERVER['SCRIPT_NAME'] = '/index.php'; // Inject mock router. $routes = Services::routes(); @@ -679,6 +693,7 @@ public function testRunCLIRoute() $_SERVER['argc'] = 2; $_SERVER['REQUEST_URI'] = '/cli'; + $_SERVER['SCRIPT_NAME'] = 'public/index.php'; $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1'; $_SERVER['REQUEST_METHOD'] = 'CLI'; @@ -698,6 +713,7 @@ public function testSpoofRequestMethodCanUsePUT() $_SERVER['argc'] = 1; $_SERVER['REQUEST_URI'] = '/'; + $_SERVER['SCRIPT_NAME'] = '/index.php'; $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1'; $_SERVER['REQUEST_METHOD'] = 'POST'; @@ -722,6 +738,7 @@ public function testSpoofRequestMethodCannotUseGET() $_SERVER['argc'] = 1; $_SERVER['REQUEST_URI'] = '/'; + $_SERVER['SCRIPT_NAME'] = '/index.php'; $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1'; $_SERVER['REQUEST_METHOD'] = 'POST'; @@ -754,6 +771,7 @@ public function testPageCacheSendSecureHeaders() command('cache:clear'); $_SERVER['REQUEST_URI'] = '/test'; + $_SERVER['SCRIPT_NAME'] = '/index.php'; $routes = Services::routes(); $routes->add('test', static function () { @@ -832,6 +850,7 @@ public function testPageCacheWithCacheQueryString( foreach ($testingUrls as $testingUrl) { $this->resetServices(); $_SERVER['REQUEST_URI'] = '/' . $testingUrl; + $_SERVER['SCRIPT_NAME'] = '/index.php'; $this->codeigniter = new MockCodeIgniter(new App()); $routes = Services::routes(true); From cd5b817cc08deb0666e316f9f5fe24da50d40ae2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 3 Jul 2023 13:38:35 +0900 Subject: [PATCH 09/13] refactor: don't make cahce if $ttl is 0 --- system/Cache/ResponseCache.php | 11 +++++------ system/CodeIgniter.php | 4 +--- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/system/Cache/ResponseCache.php b/system/Cache/ResponseCache.php index 8a3865b3814e..b4c2fe9187fa 100644 --- a/system/Cache/ResponseCache.php +++ b/system/Cache/ResponseCache.php @@ -52,11 +52,6 @@ public function __construct(CacheConfig $config, CacheInterface $cache) $this->cache = $cache; } - public function getTtl(): int - { - return $this->ttl; - } - /** * @return $this */ @@ -90,12 +85,16 @@ public function generateCacheKey($request): string } /** - * Caches the full response from the current request. + * Caches the response. * * @param CLIRequest|IncomingRequest $request */ public function make($request, ResponseInterface $response): bool { + if ($this->ttl === 0) { + return true; + } + $headers = []; foreach ($response->headers() as $header) { diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 20d788132677..2ff8da02d456 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -527,9 +527,7 @@ protected function handleRequest(?RouteCollectionInterface $routes, Cache $cache // Cache it without the performance metrics replaced // so that we can have live speed updates along the way. // Must be run after filters to preserve the Response headers. - if ($this->pageCache->getTtl() > 0) { - $this->pageCache->make($this->request, $this->response); - } + $this->pageCache->make($this->request, $this->response); // Update the performance metrics $body = $this->response->getBody(); From eb288ec342262ac3ced5ad09a38184c14a176230 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 3 Jul 2023 14:13:53 +0900 Subject: [PATCH 10/13] docs: group items of the same class --- user_guide_src/source/changelogs/v4.4.0.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/user_guide_src/source/changelogs/v4.4.0.rst b/user_guide_src/source/changelogs/v4.4.0.rst index c686450ef864..f8b3768a78ef 100644 --- a/user_guide_src/source/changelogs/v4.4.0.rst +++ b/user_guide_src/source/changelogs/v4.4.0.rst @@ -52,11 +52,12 @@ Parameter Type Changes - **Services:** The first parameter of ``Services::security()`` has been changed from ``Config\App`` to ``Config\Security``. -- **Session:** The second parameter of ``Session::__construct()`` has been - changed from ``Config\App`` to ``Config\Session``. -- **Session:** The first parameter of ``__construct()`` in ``BaseHandler``, - ``DatabaseHandler``, ``FileHandler``, ``MemcachedHandler``, and ``RedisHandler`` - has been changed from ``Config\App`` to ``Config\Session``. +- **Session:** + - The second parameter of ``Session::__construct()`` has been changed from + ``Config\App`` to ``Config\Session``. + - The first parameter of ``__construct()`` in ``BaseHandler``, + ``DatabaseHandler``, ``FileHandler``, ``MemcachedHandler``, and ``RedisHandler`` + has been changed from ``Config\App`` to ``Config\Session``. - **Security:** The first parameter of ``Security::__construct()`` has been changed from ``Config\App`` to ``Config\Security``. - **Validation:** The method signature of ``Validation::check()`` has been changed. From 7d31f522c78c7ff935a077edad473b46439f543f Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 3 Jul 2023 14:14:27 +0900 Subject: [PATCH 11/13] docs: add "Parameter Type Changes" and "Deprecations" --- user_guide_src/source/changelogs/v4.4.0.rst | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/changelogs/v4.4.0.rst b/user_guide_src/source/changelogs/v4.4.0.rst index f8b3768a78ef..b101decaad4d 100644 --- a/user_guide_src/source/changelogs/v4.4.0.rst +++ b/user_guide_src/source/changelogs/v4.4.0.rst @@ -62,6 +62,14 @@ Parameter Type Changes changed from ``Config\App`` to ``Config\Security``. - **Validation:** The method signature of ``Validation::check()`` has been changed. The ``string`` typehint on the ``$rule`` parameter was removed. +- **CodeIgniter:** The method signature of ``CodeIgniter::setRequest()`` has been + changed. The ``Request`` typehint on the ``$request`` parameter was removed. +- **FeatureTestCase:** + - The method signature of ``FeatureTestCase::populateGlobals()`` has been + changed. The ``Request`` typehint on the ``$request`` parameter was removed. + - The method signature of ``FeatureTestCase::setRequestBody()`` has been + changed. The ``Request`` typehint on the ``$request`` parameter and the + return type ``Request`` were removed. Added Parameters ---------------- @@ -180,7 +188,12 @@ Deprecations are deprecated. Because these methods have been moved to ``BaseExceptionHandler`` or ``ExceptionHandler``. - **Autoloader:** ``Autoloader::sanitizeFilename()`` is deprecated. -- **CodeIgniter:** ``CodeIgniter::$returnResponse`` property is deprecated. No longer used. +- **CodeIgniter:** + - ``CodeIgniter::$returnResponse`` property is deprecated. No longer used. + - ``CodeIgniter::$cacheTTL`` property is deprecated. No longer used. Use ``ResponseCache`` instead. + - ``CodeIgniter::cache()`` method is deprecated. No longer used. Use ``ResponseCache`` instead. + - ``CodeIgniter::cachePage()`` method is deprecated. No longer used. Use ``ResponseCache`` instead. + - ``CodeIgniter::generateCacheName()`` method is deprecated. No longer used. Use ``ResponseCache`` instead. - **RedirectException:** ``\CodeIgniter\Router\Exceptions\RedirectException`` is deprecated. Use ``\CodeIgniter\HTTP\Exceptions\RedirectException`` instead. - **Session:** The property ``$sessionDriverName``, ``$sessionCookieName``, ``$sessionExpiration``, ``$sessionSavePath``, ``$sessionMatchIP``, From 42ea49371ad78be79c0d319385a376c2013edac3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 4 Jul 2023 09:46:23 +0900 Subject: [PATCH 12/13] docs: fix by proofreading Co-authored-by: MGatner --- user_guide_src/source/changelogs/v4.4.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/changelogs/v4.4.0.rst b/user_guide_src/source/changelogs/v4.4.0.rst index b101decaad4d..8bf257532fb4 100644 --- a/user_guide_src/source/changelogs/v4.4.0.rst +++ b/user_guide_src/source/changelogs/v4.4.0.rst @@ -55,7 +55,7 @@ Parameter Type Changes - **Session:** - The second parameter of ``Session::__construct()`` has been changed from ``Config\App`` to ``Config\Session``. - - The first parameter of ``__construct()`` in ``BaseHandler``, + - The first parameter of ``__construct()`` in the database's ``BaseHandler``, ``DatabaseHandler``, ``FileHandler``, ``MemcachedHandler``, and ``RedisHandler`` has been changed from ``Config\App`` to ``Config\Session``. - **Security:** The first parameter of ``Security::__construct()`` has been From 789015666afae712308721b12010b91021044074 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 5 Jul 2023 07:38:13 +0900 Subject: [PATCH 13/13] refactor: make ResponseCache final --- system/Cache/ResponseCache.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/system/Cache/ResponseCache.php b/system/Cache/ResponseCache.php index b4c2fe9187fa..44da42947633 100644 --- a/system/Cache/ResponseCache.php +++ b/system/Cache/ResponseCache.php @@ -20,7 +20,7 @@ /** * Web Page Caching */ -class ResponseCache +final class ResponseCache { /** * Whether to take the URL query string into consideration when generating @@ -35,16 +35,16 @@ class ResponseCache * * @var bool|string[] */ - protected $cacheQueryString = false; + private $cacheQueryString = false; /** * Cache time to live. * * @var int seconds */ - protected int $ttl = 0; + private int $ttl = 0; - protected CacheInterface $cache; + private CacheInterface $cache; public function __construct(CacheConfig $config, CacheInterface $cache) {