diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 34baf10..ecc05eb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -32,4 +32,4 @@ jobs: os: >- ['ubuntu-latest', 'windows-latest'] php: >- - ['8.1', '8.2', '8.3'] + ['8.1', '8.2', '8.3', '8.4'] diff --git a/.github/workflows/composer-require-checker.yml b/.github/workflows/composer-require-checker.yml index a857bce..a93390b 100644 --- a/.github/workflows/composer-require-checker.yml +++ b/.github/workflows/composer-require-checker.yml @@ -31,4 +31,4 @@ jobs: os: >- ['ubuntu-latest'] php: >- - ['8.1', '8.2', '8.3'] + ['8.1', '8.2', '8.3', '8.4'] diff --git a/.github/workflows/rector.yml b/.github/workflows/rector.yml index 457772a..5d6931d 100644 --- a/.github/workflows/rector.yml +++ b/.github/workflows/rector.yml @@ -21,4 +21,4 @@ jobs: os: >- ['ubuntu-latest'] php: >- - ['8.3'] + ['8.4'] diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index e33eca8..d03874d 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -29,4 +29,4 @@ jobs: os: >- ['ubuntu-latest'] php: >- - ['8.1', '8.2', '8.3'] + ['8.1', '8.2', '8.3', '8.4'] diff --git a/CHANGELOG.md b/CHANGELOG.md index 7deb59f..5011689 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ - Chg #101: Rename `UserAuth` to `WebAuth`, mark `UserAuth` as deprecated (@olegbaturin) - New #101: Add `ApiAuth` authentication method (@olegbaturin) +- Chg #109: Change PHP constraint in `composer.json` to `~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0` (@vjik) +- Bug #109: Explicitly mark nullable parameters (@vjik) +- Enh #109: Improve debug message "Unable to authenticate user…" in `LogginMiddleware` (@vjik) ## 2.2.0 May 07, 2024 diff --git a/README.md b/README.md index 264bc88..2fae34c 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,6 @@ The package handles user-related functionality: ## Requirements - PHP 8.1 or higher. -- `JSON` PHP extension. ## Installation diff --git a/composer.json b/composer.json index cfe49ae..bd0282d 100644 --- a/composer.json +++ b/composer.json @@ -27,30 +27,29 @@ } ], "require": { - "php": "^8.1", - "ext-json": "*", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", "psr/event-dispatcher": "^1.0", - "psr/http-message": "^1.0|^2.0", + "psr/http-message": "^1.0 || ^2.0", "psr/http-factory": "^1.0", "psr/http-server-handler": "^1.0", "psr/http-server-middleware": "^1.0", - "psr/log": "^1.1|^2.0|^3.0", + "psr/log": "^1.1 || ^2.0 || ^3.0", "yiisoft/access": "^2.0", - "yiisoft/auth": "^2.0|^3.0", + "yiisoft/auth": "^2.0 || ^3.0", "yiisoft/cookies": "^1.2", - "yiisoft/session": "^1.0|^2.0", + "yiisoft/session": "^1.0 || ^2.0", "yiisoft/http": "^1.2" }, "require-dev": { - "httpsoft/http-message": "^1.0", - "maglnet/composer-require-checker": "^4.2", - "phpunit/phpunit": "^10.5", - "rector/rector": "^2.0.0", - "roave/infection-static-analysis-plugin": "^1.16", - "spatie/phpunit-watcher": "^1.23", - "vimeo/psalm": "^5.23", - "yiisoft/di": "^1.0", - "yiisoft/test-support": "^3.0" + "httpsoft/http-message": "^1.1.6", + "maglnet/composer-require-checker": "^4.7.1", + "phpunit/phpunit": "^10.5.45", + "rector/rector": "^2.0.9", + "roave/infection-static-analysis-plugin": "^1.35", + "spatie/phpunit-watcher": "^1.24", + "vimeo/psalm": "^5.26.1 || ^6.8.6", + "yiisoft/di": "^1.3", + "yiisoft/test-support": "^3.0.2" }, "autoload": { "psr-4": { @@ -73,6 +72,7 @@ }, "config": { "sort-packages": true, + "bump-after-update": "dev", "allow-plugins": { "infection/extension-installer": true, "composer/package-versions-deprecated": true diff --git a/psalm.xml b/psalm.xml index 73ed715..44f8eab 100644 --- a/psalm.xml +++ b/psalm.xml @@ -3,6 +3,8 @@ errorLevel="1" findUnusedBaselineEntry="true" findUnusedCode="false" + ensureOverrideAttribute="false" + strictBinaryOperands="false" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://getpsalm.org/schema/config" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" diff --git a/rector.php b/rector.php index 137e59d..8a9320a 100644 --- a/rector.php +++ b/rector.php @@ -5,6 +5,7 @@ use Rector\CodeQuality\Rector\Class_\InlineConstructorDefaultToPropertyRector; use Rector\Config\RectorConfig; use Rector\Php74\Rector\Closure\ClosureToArrowFunctionRector; +use Rector\Php81\Rector\ClassMethod\NewInInitializerRector; use Rector\Php81\Rector\Property\ReadOnlyPropertyRector; use Rector\Php81\Rector\FuncCall\NullToStrictStringFuncCallArgRector; use Rector\Set\ValueObject\LevelSetList; @@ -27,5 +28,6 @@ ClosureToArrowFunctionRector::class, ReadOnlyPropertyRector::class, NullToStrictStringFuncCallArgRector::class, + NewInInitializerRector::class, ]); }; diff --git a/src/CurrentUser.php b/src/CurrentUser.php index 3258807..45d3230 100644 --- a/src/CurrentUser.php +++ b/src/CurrentUser.php @@ -42,7 +42,7 @@ final class CurrentUser public function __construct( private IdentityRepositoryInterface $identityRepository, private EventDispatcherInterface $eventDispatcher, - GuestIdentityFactoryInterface $guestIdentityFactory = null + ?GuestIdentityFactoryInterface $guestIdentityFactory = null ) { $this->guestIdentityFactory = $guestIdentityFactory ?? new GuestIdentityFactory(); } diff --git a/src/Login/LoginMiddleware.php b/src/Login/LoginMiddleware.php index 633ef93..5064cf8 100644 --- a/src/Login/LoginMiddleware.php +++ b/src/Login/LoginMiddleware.php @@ -13,6 +13,10 @@ use Yiisoft\Auth\Middleware\Authentication; use Yiisoft\User\CurrentUser; +use function is_bool; +use function is_scalar; +use function sprintf; + /** * `LoginMiddleware` automatically logs user in if {@see IdentityInterface} instance presents in a request * attribute. It is usually put there by {@see Authentication}. @@ -47,10 +51,16 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface if ($identity instanceof IdentityInterface) { $this->currentUser->login($identity); } else { - $this->logger->debug(sprintf( - 'Unable to authenticate user by token %s. Identity not found.', - is_scalar($identity) ? ('"' . $identity . '"') : ('of type ' . get_debug_type($identity)), - )); + if (is_scalar($identity)) { + $token = is_bool($identity) + ? ($identity ? 'true' : 'false') + : ('"' . $identity . '"'); + } else { + $token = 'of type ' . get_debug_type($identity); + } + $this->logger->debug( + sprintf('Unable to authenticate user by token %s. Identity not found.', $token) + ); } return $handler->handle($request); diff --git a/tests/Login/Cookie/CookieLoginMiddlewareTest.php b/tests/Login/Cookie/CookieLoginMiddlewareTest.php index 3b31f4f..f4aaaea 100644 --- a/tests/Login/Cookie/CookieLoginMiddlewareTest.php +++ b/tests/Login/Cookie/CookieLoginMiddlewareTest.php @@ -428,7 +428,7 @@ private function getIdentityRepository(IdentityInterface $identity): IdentityRep private function getRequestWithAutoLoginCookie( string $authKey = CookieLoginIdentity::KEY_CORRECT, - int $expires = null + ?int $expires = null ): ServerRequestInterface { return $this->getRequestWithCookies([ 'autoLogin' => json_encode([CookieLoginIdentity::ID, $authKey, $expires ?? time() + 3600], JSON_THROW_ON_ERROR), diff --git a/tests/Login/LoginMiddlewareTest.php b/tests/Login/LoginMiddlewareTest.php index 78180b7..2b5b30a 100644 --- a/tests/Login/LoginMiddlewareTest.php +++ b/tests/Login/LoginMiddlewareTest.php @@ -5,9 +5,11 @@ namespace Yiisoft\User\Tests\Login; use HttpSoft\Message\ServerRequest; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; +use stdClass; use Yiisoft\Auth\Middleware\Authentication; use Yiisoft\Test\Support\EventDispatcher\SimpleEventDispatcher; use Yiisoft\User\CurrentUser; @@ -82,10 +84,35 @@ public function testIdentityNotFound(): void $middleware->process($this->createServerRequest(false), $this->createRequestHandler()); $this->assertInstanceOf(GuestIdentity::class, $this->currentUser->getIdentity()); - $this->assertNull($this->currentUser - ->getIdentity() - ->getId()); - $this->assertSame('Unable to authenticate user by token of type null. Identity not found.', $this->logger->getLastMessage()); + $this->assertNull($this->currentUser->getIdentity()->getId()); + } + + public static function dataUnableToAuthenticateUserDebugMessage(): iterable + { + yield ['true', true]; + yield ['false', false]; + yield ['"123"', 123]; + yield ['"10.4"', 10.4]; + yield ['"hello"', 'hello']; + yield ['of type null', null]; + yield ['of type stdClass', new stdClass()]; + yield ['of type array', ['a', 'b']]; + } + + #[DataProvider('dataUnableToAuthenticateUserDebugMessage')] + public function testUnableToAuthenticateUserDebugMessage(string $expectedType, mixed $identity): void + { + $middleware = new LoginMiddleware($this->currentUser, $this->logger); + + $middleware->process( + (new ServerRequest())->withAttribute(Authentication::class, $identity), + $this->createRequestHandler() + ); + + $this->assertSame( + 'Unable to authenticate user by token ' . $expectedType . '. Identity not found.', + $this->logger->getLastMessage() + ); } private function createServerRequest(bool $withIdentity = true): ServerRequestInterface