From 5201fe0d3b607af5689711aaed13df817970c270 Mon Sep 17 00:00:00 2001 From: Dimitri Sitchet Tomkeu Date: Mon, 20 Apr 2026 19:55:44 +0100 Subject: [PATCH 1/6] feat: possibility to use `only` in routes configuration --- src/Auth.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Auth.php b/src/Auth.php index fedee8a97..e47c04492 100644 --- a/src/Auth.php +++ b/src/Auth.php @@ -20,6 +20,7 @@ use CodeIgniter\Shield\Config\Auth as AuthConfig; use CodeIgniter\Shield\Entities\User; use CodeIgniter\Shield\Models\UserModel; +use InvalidArgumentException; /** * Facade for Authentication @@ -134,13 +135,27 @@ public function authenticate(array $credentials): Result */ public function routes(RouteCollection &$routes, array $config = []): void { + if (isset($config['only'], $config['except'])) { + throw new InvalidArgumentException( + 'The "only" and "except" options cannot be used at the same time.', + ); + } + $authRoutes = config('AuthRoutes')->routes; $namespace = $config['namespace'] ?? 'CodeIgniter\Shield\Controllers'; $routes->group('/', ['namespace' => $namespace], static function (RouteCollection $routes) use ($authRoutes, $config): void { foreach ($authRoutes as $name => $row) { - if (! isset($config['except']) || ! in_array($name, $config['except'], true)) { + $shouldInclude = true; + + if (isset($config['only'])) { + $shouldInclude = in_array($name, $config['only'], true); + } elseif (isset($config['except'])) { + $shouldInclude = ! in_array($name, $config['except'], true); + } + + if ($shouldInclude) { foreach ($row as $params) { $options = isset($params[3]) ? ['as' => $params[3]] From b79322544c696b1cfea0d8960b2fd63fb69de88f Mon Sep 17 00:00:00 2001 From: Dimitri Sitchet Tomkeu Date: Mon, 20 Apr 2026 19:56:46 +0100 Subject: [PATCH 2/6] test: tests for `only` options in routes configuartion --- tests/Unit/AuthRoutesTest.php | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/Unit/AuthRoutesTest.php b/tests/Unit/AuthRoutesTest.php index d4e568121..191331a7b 100644 --- a/tests/Unit/AuthRoutesTest.php +++ b/tests/Unit/AuthRoutesTest.php @@ -16,6 +16,7 @@ use CodeIgniter\CodeIgniter; use CodeIgniter\Router\RouteCollection; use CodeIgniter\Shield\Auth; +use InvalidArgumentException; use Tests\Support\TestCase; /** @@ -65,6 +66,36 @@ public function testRoutesExcept(): void $this->assertArrayHasKey('auth/a/show', $routes); } + public function testRoutesOnly(): void + { + $collection = single_service('routes'); + $auth = service('auth'); + + $auth->routes($collection, ['only' => ['login']]); + + if (version_compare(CodeIgniter::CI_VERSION, '4.5') >= 0) { + $routes = $collection->getRoutes('GET'); + } else { + $routes = $collection->getRoutes('get'); + } + + $this->assertArrayHasKey('login', $routes); + $this->assertArrayNotHasKey('register', $routes); + $this->assertArrayNotHasKey('login/magic-link', $routes); + $this->assertArrayNotHasKey('logout', $routes); + $this->assertArrayNotHasKey('auth/a/show', $routes); + } + + public function testRoutesUseOnlyAndExceptOptionsSimultaneous(): void + { + $this->expectException(InvalidArgumentException::class); + + $collection = single_service('routes'); + $auth = service('auth'); + + $auth->routes($collection, ['only' => ['login'], 'except' => ['register']]); + } + public function testRoutesCustomNamespace(): void { $collection = single_service('routes'); From 0cc5dacc33cd384cceb689bd3a35f2756db95f17 Mon Sep 17 00:00:00 2001 From: Dimitri Sitchet Tomkeu Date: Mon, 20 Apr 2026 19:58:03 +0100 Subject: [PATCH 3/6] docs: add docs for `only` options in routes configuartion --- docs/customization/route_config.md | 8 ++++++++ docs/quick_start_guide/using_session_auth.md | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/docs/customization/route_config.md b/docs/customization/route_config.md index 7b06c7d70..f0b05f619 100644 --- a/docs/customization/route_config.md +++ b/docs/customization/route_config.md @@ -17,6 +17,14 @@ $routes->get('login', '\App\Controllers\Auth\LoginController::loginView'); $routes->get('register', '\App\Controllers\Auth\RegisterController::registerView'); ``` +If you only need a specific route (or a small set of routes), you can use the `only` option instead + +```php +service('auth')->routes($routes, ['only' => ['login']]); +``` + +In this case, you must manage all other routes manually. + After customization, check your routes with the [spark routes](https://codeigniter.com/user_guide/incoming/routing.html#spark-routes) command. ## Change Namespace diff --git a/docs/quick_start_guide/using_session_auth.md b/docs/quick_start_guide/using_session_auth.md index 4613fabac..8b72d56f7 100644 --- a/docs/quick_start_guide/using_session_auth.md +++ b/docs/quick_start_guide/using_session_auth.md @@ -89,6 +89,14 @@ $routes->get('login', '\App\Controllers\Auth\LoginController::loginView'); $routes->get('register', '\App\Controllers\Auth\RegisterController::registerView'); ``` +If you only need a specific route (or a small set of routes), you can use the `only` option instead + +```php +service('auth')->routes($routes, ['only' => ['login']]); +``` + +In this case, you must manage all other routes manually. + Check your routes with the [spark routes](https://codeigniter.com/user_guide/incoming/routing.html#spark-routes) command. From 6d4684a5307accce19d7d509dcb75f7913669d15 Mon Sep 17 00:00:00 2001 From: John Paul E Balandan Date: Wed, 22 Apr 2026 00:31:36 +0800 Subject: [PATCH 4/6] chore: fix code styles (#1324) --- src/Config/Auth.php | 4 ++-- tests/Authentication/MagicLinkTest.php | 9 +++------ tests/Language/AbstractTranslationTestCase.php | 3 +-- tests/Unit/UserIdentityModelTest.php | 1 - 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/Config/Auth.php b/src/Config/Auth.php index b4f007b2c..c6c27bf1e 100644 --- a/src/Config/Auth.php +++ b/src/Config/Auth.php @@ -29,7 +29,7 @@ class Auth extends BaseConfig { - /** + /* * //////////////////////////////////////////////////////////////////// * AUTHENTICATION * //////////////////////////////////////////////////////////////////// @@ -378,7 +378,7 @@ class Auth extends BaseConfig */ public int $hashCost = 12; - /** + /* * //////////////////////////////////////////////////////////////////// * OTHER SETTINGS * //////////////////////////////////////////////////////////////////// diff --git a/tests/Authentication/MagicLinkTest.php b/tests/Authentication/MagicLinkTest.php index 19e5c52f8..f421a03fd 100644 --- a/tests/Authentication/MagicLinkTest.php +++ b/tests/Authentication/MagicLinkTest.php @@ -75,9 +75,7 @@ public function testMagicLinkSubmitBadEmail(): void public function testMagicLinkSubmitSuccess(): void { - /** - * @phpstan-var User - */ + /** @phpstan-var User $user */ $user = fake(UserModel::class); $user->createEmailIdentity(['email' => 'foo@example.com', 'password' => 'secret123']); @@ -105,9 +103,8 @@ public function testMagicLinkVerifyNoToken(): void public function testMagicLinkVerifyExpired(): void { $identities = new UserIdentityModel(); - /** - * @phpstan-var User - */ + + /** @phpstan-var User $user */ $user = fake(UserModel::class); $user->createEmailIdentity(['email' => 'foo@example.com', 'password' => 'secret123']); $identities->insert([ diff --git a/tests/Language/AbstractTranslationTestCase.php b/tests/Language/AbstractTranslationTestCase.php index 6085443e9..38ae4138a 100644 --- a/tests/Language/AbstractTranslationTestCase.php +++ b/tests/Language/AbstractTranslationTestCase.php @@ -220,8 +220,7 @@ final public function testAllIncludedLanguageKeysAreTranslated(string $locale): { // These keys are usually not translated because they contain either // universal abbreviations or simply combine parameters with signs. - static $excludedKeyTranslations = [ - ]; + static $excludedKeyTranslations = []; $excludedKeys = array_unique(array_merge($excludedKeyTranslations, $this->excludedLocaleKeyTranslations)); $availableSets = array_intersect($this->expectedSets(), $this->foundSets($locale)); diff --git a/tests/Unit/UserIdentityModelTest.php b/tests/Unit/UserIdentityModelTest.php index 00133a98a..e552a3b19 100644 --- a/tests/Unit/UserIdentityModelTest.php +++ b/tests/Unit/UserIdentityModelTest.php @@ -85,7 +85,6 @@ public function testCreateCodeIdentityThrowsExceptionIfUniqueCodeIsNotGot(): voi public function testForceMultiplePasswordReset(): void { - /** @var Fabricator $fabricator */ $fabricator = new Fabricator(UserIdentityModel::class); $fabricator->create(10); From b7583c59ac00573d62a01a88d7ab3aff434a1798 Mon Sep 17 00:00:00 2001 From: John Paul E Balandan Date: Wed, 22 Apr 2026 00:31:58 +0800 Subject: [PATCH 5/6] chore: fix phpstan (#1325) --- phpstan-baseline.php | 12 ------------ src/Authentication/Authenticators/JWT.php | 4 +--- src/Authentication/Authenticators/Session.php | 2 +- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/phpstan-baseline.php b/phpstan-baseline.php index 8612560f9..53ff869cc 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -427,18 +427,6 @@ 'count' => 1, 'path' => __DIR__ . '/tests/Authentication/Authenticators/SessionAuthenticatorTest.php', ]; -$ignoreErrors[] = [ - 'rawMessage' => 'Parameter #1 $headers of method Tests\\Authentication\\Filters\\AbstractFilterTestCase::withHeaders() expects array>, array{Authorization: non-falsy-string} given.', - 'identifier' => 'argument.type', - 'count' => 7, - 'path' => __DIR__ . '/tests/Authentication/Filters/HmacFilterTest.php', -]; -$ignoreErrors[] = [ - 'rawMessage' => 'Parameter #1 $headers of method Tests\\Authentication\\Filters\\JWTFilterTest::withHeaders() expects array>, array{Authorization: non-falsy-string} given.', - 'identifier' => 'argument.type', - 'count' => 1, - 'path' => __DIR__ . '/tests/Authentication/Filters/JWTFilterTest.php', -]; $ignoreErrors[] = [ 'rawMessage' => 'Implicit array creation is not allowed - variable $users might not exist.', 'identifier' => 'variable.implicitArray', diff --git a/src/Authentication/Authenticators/JWT.php b/src/Authentication/Authenticators/JWT.php index 61deddb20..2a4c2e721 100644 --- a/src/Authentication/Authenticators/JWT.php +++ b/src/Authentication/Authenticators/JWT.php @@ -221,9 +221,7 @@ public function getTokenFromRequest(RequestInterface $request): string /** @var AuthJWT $config */ $config = config('AuthJWT'); - $tokenHeader = $request->getHeaderLine( - $config->authenticatorHeader ?? 'Authorization', - ); + $tokenHeader = $request->getHeaderLine($config->authenticatorHeader); if (str_starts_with($tokenHeader, 'Bearer')) { return trim(substr($tokenHeader, 6)); diff --git a/src/Authentication/Authenticators/Session.php b/src/Authentication/Authenticators/Session.php index 6897854b7..2b800c2a5 100644 --- a/src/Authentication/Authenticators/Session.php +++ b/src/Authentication/Authenticators/Session.php @@ -280,7 +280,7 @@ private function recordLoginAttempt( // Determine the type of ID we're using. // Standard fields would be email, username, // but any column within config('Auth')->validFields can be used. - $field = array_intersect(config('Auth')->validFields ?? [], array_keys($credentials)); + $field = array_intersect(config('Auth')->validFields, array_keys($credentials)); if (count($field) !== 1) { throw new InvalidArgumentException('Invalid credentials passed to recordLoginAttempt.'); From 0b0dba2b7cebae178713d62afeb02d571c3f1bf8 Mon Sep 17 00:00:00 2001 From: John Paul E Balandan Date: Wed, 22 Apr 2026 00:32:21 +0800 Subject: [PATCH 6/6] chore: remove deprecated rector class (#1326) --- rector.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/rector.php b/rector.php index d596c8712..d2d9a6e6a 100644 --- a/rector.php +++ b/rector.php @@ -45,7 +45,6 @@ use Rector\EarlyReturn\Rector\Return_\PreparedValueToEarlyReturnRector; use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector; use Rector\Php73\Rector\FuncCall\StringifyStrNeedlesRector; -use Rector\Php81\Rector\ClassMethod\NewInInitializerRector; use Rector\PHPUnit\AnnotationsToAttributes\Rector\Class_\AnnotationWithValueToAttributeRector; use Rector\PHPUnit\CodeQuality\Rector\Class_\YieldDataProviderRector; use Rector\PHPUnit\CodeQuality\Rector\MethodCall\AssertEmptyNullableObjectToAssertInstanceofRector; @@ -138,9 +137,6 @@ // Ignore some PHPUnit rules AssertEmptyNullableObjectToAssertInstanceofRector::class, - // Ignore to prevent BC break - NewInInitializerRector::class, - // Ignore for readability RemoveNullArgOnNullDefaultParamRector::class, ]);