From 7a64888887a141654624edc823b1d3735c9f8915 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Mon, 17 Aug 2026 02:56:26 +0800 Subject: [PATCH 1/2] refactor: do not override `Exception`'s `$code` in `RedirectException` --- system/HTTP/Exceptions/RedirectException.php | 8 +++----- user_guide_src/source/changelogs/v4.8.0.rst | 1 + utils/phpstan-baseline/property.phpDocType.neon | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/system/HTTP/Exceptions/RedirectException.php b/system/HTTP/Exceptions/RedirectException.php index a16dfc1a8a2d..b0452638f302 100644 --- a/system/HTTP/Exceptions/RedirectException.php +++ b/system/HTTP/Exceptions/RedirectException.php @@ -27,11 +27,9 @@ class RedirectException extends RuntimeException implements ExceptionInterface, ResponsableInterface, HTTPExceptionInterface { /** - * HTTP status code for redirects - * - * @var int + * Status code applied to a Response that arrives without a 3xx redirect status. */ - protected $code = 302; + protected int $defaultStatusCode = 302; protected ?ResponseInterface $response = null; @@ -61,7 +59,7 @@ public function __construct($message = '', int $code = 0, ?Throwable $previous = } if ($this->response->getStatusCode() < 301 || $this->response->getStatusCode() > 308) { - $this->response->setStatusCode($this->code); + $this->response->setStatusCode($this->defaultStatusCode); } } diff --git a/user_guide_src/source/changelogs/v4.8.0.rst b/user_guide_src/source/changelogs/v4.8.0.rst index dea1a6cb135d..61b410cac32b 100644 --- a/user_guide_src/source/changelogs/v4.8.0.rst +++ b/user_guide_src/source/changelogs/v4.8.0.rst @@ -42,6 +42,7 @@ Behavior Changes - **Filters:** HTTP method matching for method-based filters is now case-sensitive. The keys in ``Config\Filters::$methods`` must exactly match the request method (e.g., ``GET``, ``POST``). Lowercase method names (e.g., ``post``) will no longer match. - **HTTP:** Routes defined with ``$routes->add()`` now also match HTTP ``QUERY`` requests. If the route has CSRF protection, remember that CSRF verification does not protect safe methods such as ``GET`` and ``QUERY``. +- **HTTP:** ``CodeIgniter\HTTP\Exceptions\RedirectException`` no longer redeclares the inherited ``$code`` property. The status applied to a ``Response`` passed to the constructor without a 3xx status now comes from the new ``protected int $defaultStatusCode = 302`` property. Subclasses that overrode ``$code`` to change that status must override ``$defaultStatusCode`` instead. - **Testing:** Tests using the ``FeatureTestTrait`` must now use uppercase HTTP method names when performing a request when using the ``call()`` method directly (e.g., ``$this->call('GET', '/path')`` instead of ``$this->call('get', '/path')``). Additionally, setting method-based routes using ``withRoutes()`` must also use uppercase method names (e.g., ``$this->withRoutes([['GET', 'home', 'Home::index']])``). diff --git a/utils/phpstan-baseline/property.phpDocType.neon b/utils/phpstan-baseline/property.phpDocType.neon index cbdc62c49131..1828bdc1a20a 100644 --- a/utils/phpstan-baseline/property.phpDocType.neon +++ b/utils/phpstan-baseline/property.phpDocType.neon @@ -73,9 +73,9 @@ parameters: path: ../../system/Exceptions/PageNotFoundException.php - - message: '#^PHPDoc type int of property CodeIgniter\\HTTP\\Exceptions\\RedirectException\:\:\$code is not the same as PHPDoc type mixed of overridden property Exception\:\:\$code\.$#' + message: '#^PHPDoc type CodeIgniter\\HTTP\\URI of property CodeIgniter\\HTTP\\IncomingRequest\:\:\$uri is not the same as PHPDoc type CodeIgniter\\HTTP\\URI\|null of overridden property CodeIgniter\\HTTP\\OutgoingRequest\:\:\$uri\.$#' count: 1 - path: ../../system/HTTP/Exceptions/RedirectException.php + path: ../../system/HTTP/IncomingRequest.php - message: '#^PHPDoc type string of property CodeIgniter\\Session\\Handlers\\FileHandler\:\:\$savePath is not the same as PHPDoc type array\\|string of overridden property CodeIgniter\\Session\\Handlers\\BaseHandler\:\:\$savePath\.$#' From 24dd05542f7c74ae40e5d4e08bef2101f6d23b2f Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sun, 23 Aug 2026 20:36:15 +0800 Subject: [PATCH 2/2] apply Copilot review --- system/HTTP/Exceptions/RedirectException.php | 2 +- tests/system/HTTP/RedirectExceptionTest.php | 12 +++++++++++ user_guide_src/source/changelogs/v4.8.0.rst | 2 +- .../source/installation/upgrade_480.rst | 21 +++++++++++++++++++ utils/phpstan-baseline/loader.neon | 2 +- .../phpstan-baseline/property.phpDocType.neon | 7 +------ 6 files changed, 37 insertions(+), 9 deletions(-) diff --git a/system/HTTP/Exceptions/RedirectException.php b/system/HTTP/Exceptions/RedirectException.php index b0452638f302..5ec01110a4a7 100644 --- a/system/HTTP/Exceptions/RedirectException.php +++ b/system/HTTP/Exceptions/RedirectException.php @@ -27,7 +27,7 @@ class RedirectException extends RuntimeException implements ExceptionInterface, ResponsableInterface, HTTPExceptionInterface { /** - * Status code applied to a Response that arrives without a 3xx redirect status. + * Status code applied to a Response whose status is outside the 301-308 range. */ protected int $defaultStatusCode = 302; diff --git a/tests/system/HTTP/RedirectExceptionTest.php b/tests/system/HTTP/RedirectExceptionTest.php index da487e2e57a9..a533f3a8c011 100644 --- a/tests/system/HTTP/RedirectExceptionTest.php +++ b/tests/system/HTTP/RedirectExceptionTest.php @@ -76,6 +76,18 @@ public function testResponseWithoutStatusCode(): void $this->assertSame(302, $response->getStatusCode()); } + public function testResponseWithoutStatusCodeUsesSubclassDefault(): void + { + $exception = new class (service('response')->setHeader('Location', 'location')) extends RedirectException { + protected int $defaultStatusCode = 307; + }; + + $response = $exception->getResponse(); + + $this->assertSame('location', $response->getHeaderLine('location')); + $this->assertSame(307, $response->getStatusCode()); + } + public function testLoggingLocationHeader(): void { Time::setTestNow('2023-11-25 12:00:00'); diff --git a/user_guide_src/source/changelogs/v4.8.0.rst b/user_guide_src/source/changelogs/v4.8.0.rst index 61b410cac32b..ea39987d4240 100644 --- a/user_guide_src/source/changelogs/v4.8.0.rst +++ b/user_guide_src/source/changelogs/v4.8.0.rst @@ -42,7 +42,7 @@ Behavior Changes - **Filters:** HTTP method matching for method-based filters is now case-sensitive. The keys in ``Config\Filters::$methods`` must exactly match the request method (e.g., ``GET``, ``POST``). Lowercase method names (e.g., ``post``) will no longer match. - **HTTP:** Routes defined with ``$routes->add()`` now also match HTTP ``QUERY`` requests. If the route has CSRF protection, remember that CSRF verification does not protect safe methods such as ``GET`` and ``QUERY``. -- **HTTP:** ``CodeIgniter\HTTP\Exceptions\RedirectException`` no longer redeclares the inherited ``$code`` property. The status applied to a ``Response`` passed to the constructor without a 3xx status now comes from the new ``protected int $defaultStatusCode = 302`` property. Subclasses that overrode ``$code`` to change that status must override ``$defaultStatusCode`` instead. +- **HTTP:** ``CodeIgniter\HTTP\Exceptions\RedirectException`` no longer redeclares the inherited ``$code`` property. The status applied to a ``Response`` passed to the constructor whose status is outside the 301-308 range now comes from the new ``protected int $defaultStatusCode = 302`` property. Subclasses that overrode ``$code`` to change that status must override ``$defaultStatusCode`` instead. - **Testing:** Tests using the ``FeatureTestTrait`` must now use uppercase HTTP method names when performing a request when using the ``call()`` method directly (e.g., ``$this->call('GET', '/path')`` instead of ``$this->call('get', '/path')``). Additionally, setting method-based routes using ``withRoutes()`` must also use uppercase method names (e.g., ``$this->withRoutes([['GET', 'home', 'Home::index']])``). diff --git a/user_guide_src/source/installation/upgrade_480.rst b/user_guide_src/source/installation/upgrade_480.rst index 0d7ec9c6bec4..581643d7c246 100644 --- a/user_guide_src/source/installation/upgrade_480.rst +++ b/user_guide_src/source/installation/upgrade_480.rst @@ -82,6 +82,27 @@ the URI. Such calls must now pass a ``URI``: Any other call that omitted ``$uri`` or passed ``null`` already failed with ``Call to a member function getHost() on null``, so it needs no migration. +RedirectException Default Status Code +====================================== + +``CodeIgniter\HTTP\Exceptions\RedirectException`` no longer redeclares the inherited ``$code`` property to store the status applied to a +``Response`` whose status is outside the 301-308 range. If you have a subclass that overrode ``$code`` for this purpose, override the new +``$defaultStatusCode`` property instead: + +.. code-block:: php + + // Before + class MyRedirectException extends RedirectException + { + protected $code = 307; + } + + // After + class MyRedirectException extends RedirectException + { + protected int $defaultStatusCode = 307; + } + ********************* Breaking Enhancements ********************* diff --git a/utils/phpstan-baseline/loader.neon b/utils/phpstan-baseline/loader.neon index df2b8ef14e7a..3cbf8d336a32 100644 --- a/utils/phpstan-baseline/loader.neon +++ b/utils/phpstan-baseline/loader.neon @@ -1,4 +1,4 @@ -# total 689 errors +# total 688 errors includes: - argument.type.neon diff --git a/utils/phpstan-baseline/property.phpDocType.neon b/utils/phpstan-baseline/property.phpDocType.neon index 1828bdc1a20a..d51c912ec6d9 100644 --- a/utils/phpstan-baseline/property.phpDocType.neon +++ b/utils/phpstan-baseline/property.phpDocType.neon @@ -1,4 +1,4 @@ -# total 21 errors +# total 20 errors parameters: ignoreErrors: @@ -72,11 +72,6 @@ parameters: count: 1 path: ../../system/Exceptions/PageNotFoundException.php - - - message: '#^PHPDoc type CodeIgniter\\HTTP\\URI of property CodeIgniter\\HTTP\\IncomingRequest\:\:\$uri is not the same as PHPDoc type CodeIgniter\\HTTP\\URI\|null of overridden property CodeIgniter\\HTTP\\OutgoingRequest\:\:\$uri\.$#' - count: 1 - path: ../../system/HTTP/IncomingRequest.php - - message: '#^PHPDoc type string of property CodeIgniter\\Session\\Handlers\\FileHandler\:\:\$savePath is not the same as PHPDoc type array\\|string of overridden property CodeIgniter\\Session\\Handlers\\BaseHandler\:\:\$savePath\.$#' count: 1