From 6e02db4eaa04f7d829664ffa0e54eddf7e2ffaaa Mon Sep 17 00:00:00 2001 From: Alexej Leinweber Date: Fri, 17 Jan 2025 14:11:04 +0100 Subject: [PATCH 1/2] feat: Update composer-deps --- .github/workflows/test-redis.yml | 2 +- .github/workflows/test.yml | 2 +- composer.json | 12 ++++---- phpstan.neon.dist | 3 ++ .../BrainbitsBlockingExtension.php | 8 +++-- src/Owner/SymfonySessionOwnerFactory.php | 4 --- src/Storage/FilesystemStorage.php | 30 +++++++++++-------- src/Storage/PredisStorage.php | 21 +++++++------ 8 files changed, 46 insertions(+), 36 deletions(-) diff --git a/.github/workflows/test-redis.yml b/.github/workflows/test-redis.yml index bb6c938..877dc40 100644 --- a/.github/workflows/test-redis.yml +++ b/.github/workflows/test-redis.yml @@ -14,8 +14,8 @@ jobs: matrix: dependencies: ["lowest", "highest"] php-version: - - "8.2" - "8.3" + - "8.4" operating-system: ["ubuntu-latest"] steps: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 94422ad..9962d78 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,8 +14,8 @@ jobs: matrix: dependencies: ["lowest", "highest"] php-version: - - "8.2" - "8.3" + - "8.4" operating-system: ["ubuntu-latest"] steps: diff --git a/composer.json b/composer.json index dc51340..2706725 100644 --- a/composer.json +++ b/composer.json @@ -11,17 +11,17 @@ } ], "require": { - "php": "^8.2", + "php": "^8.3", "psr/clock": "^1.0" }, "require-dev": { "brainbits/phpcs-standard": "^7.0.1", - "brainbits/phpstan-rules": "^3.1", + "brainbits/phpstan-rules": "^4.0", "matthiasnoback/symfony-config-test": "^5.1", "matthiasnoback/symfony-dependency-injection-test": "^6.0", "mikey179/vfsstream": "^1.6.11", - "phpstan/phpstan": "^1.10.67", - "phpunit/phpunit": "^11.3.6", + "phpstan/phpstan": "^2.1.1", + "phpunit/phpunit": "^11.5", "predis/predis": "^2.2", "symfony/clock": "^6.4|^7.0", "symfony/config": "^6.4|^7.0", @@ -30,8 +30,8 @@ "symfony/http-kernel": "^6.4|^7.0", "symfony/routing": "^6.4|^7.0", "symfony/security-core": "^6.4|^7.0", - "phpstan/phpstan-phpunit": "^1.3", - "phpstan/phpstan-symfony": "^1.3" + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-symfony": "^2.0" }, "suggest": { "predis/predis": "If you want to use the PredisStorage", diff --git a/phpstan.neon.dist b/phpstan.neon.dist index ea8fbc6..8868394 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -4,6 +4,9 @@ parameters: - src bootstrapFiles: - vendor/autoload.php + excludePaths: + # Declaring types for static function parameters is not possible + - src/Bundle/DependencyInjection/Configuration.php includes: - vendor/brainbits/phpstan-rules/rules.neon - vendor/phpstan/phpstan-phpunit/rules.neon diff --git a/src/Bundle/DependencyInjection/BrainbitsBlockingExtension.php b/src/Bundle/DependencyInjection/BrainbitsBlockingExtension.php index 0062e1b..be2a343 100644 --- a/src/Bundle/DependencyInjection/BrainbitsBlockingExtension.php +++ b/src/Bundle/DependencyInjection/BrainbitsBlockingExtension.php @@ -20,7 +20,6 @@ use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\HttpKernel\DependencyInjection\Extension; -use function assert; use function sprintf; class BrainbitsBlockingExtension extends Extension @@ -32,8 +31,11 @@ public function load(array $configs, ContainerBuilder $container): void $yamlLoader->load('services.yaml'); $configuration = $this->getConfiguration($configs, $container); - assert($configuration instanceof Configuration); - + /** @var array{ + * storage: non-empty-array, + * clock?: class-string, + * block_interval: int, + * owner_factory: array{value?: string, driver: string, service: string}} $config */ $config = $this->processConfiguration($configuration, $configs); if (isset($config['storage']['predis'])) { diff --git a/src/Owner/SymfonySessionOwnerFactory.php b/src/Owner/SymfonySessionOwnerFactory.php index 78c5331..1666843 100644 --- a/src/Owner/SymfonySessionOwnerFactory.php +++ b/src/Owner/SymfonySessionOwnerFactory.php @@ -16,7 +16,6 @@ use Brainbits\Blocking\Exception\NoSessionException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\HttpFoundation\Session\SessionInterface; final readonly class SymfonySessionOwnerFactory implements OwnerFactoryInterface { @@ -32,9 +31,6 @@ public function createOwner(): Owner } $session = $request->getSession(); - if (!$session instanceof SessionInterface) { - throw NoSessionException::create(); - } return new Owner($session->getId()); } diff --git a/src/Storage/FilesystemStorage.php b/src/Storage/FilesystemStorage.php index 5957fde..fbccdc2 100644 --- a/src/Storage/FilesystemStorage.php +++ b/src/Storage/FilesystemStorage.php @@ -22,13 +22,13 @@ use Brainbits\Blocking\Owner\Owner; use DateTimeImmutable; use Psr\Clock\ClockInterface; +use Throwable; use function assert; use function dirname; use function file_exists; use function file_get_contents; use function file_put_contents; -use function is_array; use function is_string; use function is_writable; use function json_decode; @@ -137,13 +137,16 @@ public function exists(BlockIdentity $identity): bool $metaContent = file_get_contents($metaFilename); assert(is_string($metaContent)); assert($metaContent !== ''); + /** @var array{ttl: int, updatedAt: string} $metaData */ $metaData = json_decode($metaContent, true); - assert(is_array($metaData)); $now = $this->clock->now(); - - $expiresAt = (new DateTimeImmutable((string) $metaData['updatedAt'], $now->getTimezone())) - ->modify('+' . $metaData['ttl'] . ' seconds'); + try { + $expiresAt = (new DateTimeImmutable((string) $metaData['updatedAt'], $now->getTimezone())) + ->modify('+' . $metaData['ttl'] . ' seconds'); + } catch (Throwable) { + throw UnserializeFailedException::createFromInput($metaContent); + } return $expiresAt > $now; } @@ -162,16 +165,19 @@ public function get(BlockIdentity $identity): Block|null throw UnserializeFailedException::createFromInput($content); } + /** @var array{identity: string, owner: string} $data */ $data = json_decode($content, true); - assert(is_array($data)); - assert($data['identity'] ?? false); - assert($data['owner'] ?? false); + try { + $block = new Block( + new BlockIdentity($data['identity']), + new Owner($data['owner']), + ); + } catch (Throwable) { + throw UnserializeFailedException::createFromInput($content); + } - return new Block( - new BlockIdentity($data['identity']), - new Owner($data['owner']), - ); + return $block; } private function getFilename(BlockIdentity $identifier): string diff --git a/src/Storage/PredisStorage.php b/src/Storage/PredisStorage.php index f13cfc8..7ef86a0 100644 --- a/src/Storage/PredisStorage.php +++ b/src/Storage/PredisStorage.php @@ -15,13 +15,13 @@ use Brainbits\Blocking\Block; use Brainbits\Blocking\Exception\IOException; +use Brainbits\Blocking\Exception\UnserializeFailedException; use Brainbits\Blocking\Identity\BlockIdentity; use Brainbits\Blocking\Owner\Owner; use Predis\ClientInterface; use Predis\PredisException; +use Throwable; -use function assert; -use function is_array; use function json_decode; use function json_encode; @@ -110,16 +110,19 @@ public function get(BlockIdentity $identity): Block|null throw IOException::getFailed((string) $identity); } + /** @var array{identity: string, owner: string} $data */ $data = json_decode($content, true); - assert(is_array($data)); - assert($data['identity'] ?? false); - assert($data['owner'] ?? false); + try { + $block = new Block( + new BlockIdentity($data['identity']), + new Owner($data['owner']), + ); + } catch (Throwable) { + throw UnserializeFailedException::createFromInput($content); + } - return new Block( - new BlockIdentity($data['identity']), - new Owner($data['owner']), - ); + return $block; } private function createKey(BlockIdentity $identity): string From b5c94405c9be68ab2ffd048fcd7844295ffda4fd Mon Sep 17 00:00:00 2001 From: Alexej Leinweber Date: Tue, 28 Jan 2025 10:03:41 +0100 Subject: [PATCH 2/2] feat: Rename BlockFailedException to AlreadyBlockedException --- src/Blocker.php | 4 ++-- .../{BlockFailedException.php => AlreadyBlockedException.php} | 2 +- tests/Functional/FilesystemTest.php | 4 ++-- tests/Functional/InMemoryTest.php | 4 ++-- tests/Functional/PredisTest.php | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) rename src/Exception/{BlockFailedException.php => AlreadyBlockedException.php} (91%) diff --git a/src/Blocker.php b/src/Blocker.php index f047ae2..80e1bbd 100644 --- a/src/Blocker.php +++ b/src/Blocker.php @@ -13,7 +13,7 @@ namespace Brainbits\Blocking; -use Brainbits\Blocking\Exception\BlockFailedException; +use Brainbits\Blocking\Exception\AlreadyBlockedException; use Brainbits\Blocking\Identity\BlockIdentity; use Brainbits\Blocking\Owner\OwnerFactoryInterface; use Brainbits\Blocking\Storage\StorageInterface; @@ -32,7 +32,7 @@ public function block(BlockIdentity $identifier, int|null $ttl = null): Block $block = $this->tryBlock($identifier, $ttl); if ($block === null) { - throw BlockFailedException::createAlreadyBlocked($identifier); + throw AlreadyBlockedException::createAlreadyBlocked($identifier); } return $block; diff --git a/src/Exception/BlockFailedException.php b/src/Exception/AlreadyBlockedException.php similarity index 91% rename from src/Exception/BlockFailedException.php rename to src/Exception/AlreadyBlockedException.php index 931d02f..2d57fb6 100644 --- a/src/Exception/BlockFailedException.php +++ b/src/Exception/AlreadyBlockedException.php @@ -17,7 +17,7 @@ use function sprintf; -class BlockFailedException extends RuntimeException +class AlreadyBlockedException extends RuntimeException { public static function createAlreadyBlocked(BlockIdentity $identity): self { diff --git a/tests/Functional/FilesystemTest.php b/tests/Functional/FilesystemTest.php index 687ed60..22852fb 100644 --- a/tests/Functional/FilesystemTest.php +++ b/tests/Functional/FilesystemTest.php @@ -14,7 +14,7 @@ namespace Brainbits\Blocking\Tests\Functional; use Brainbits\Blocking\Blocker; -use Brainbits\Blocking\Exception\BlockFailedException; +use Brainbits\Blocking\Exception\AlreadyBlockedException; use Brainbits\Blocking\Identity\BlockIdentity; use Brainbits\Blocking\Owner\ValueOwnerFactory; use Brainbits\Blocking\Storage\FilesystemStorage; @@ -61,7 +61,7 @@ public function testSelfBlock(): void public function testOtherBlock(): void { - $this->expectException(BlockFailedException::class); + $this->expectException(AlreadyBlockedException::class); $this->expectExceptionMessage('Identifier my_item is already blocked.'); file_put_contents( diff --git a/tests/Functional/InMemoryTest.php b/tests/Functional/InMemoryTest.php index de22c5a..55c7f0a 100644 --- a/tests/Functional/InMemoryTest.php +++ b/tests/Functional/InMemoryTest.php @@ -15,7 +15,7 @@ use Brainbits\Blocking\Block; use Brainbits\Blocking\Blocker; -use Brainbits\Blocking\Exception\BlockFailedException; +use Brainbits\Blocking\Exception\AlreadyBlockedException; use Brainbits\Blocking\Identity\BlockIdentity; use Brainbits\Blocking\Owner\Owner; use Brainbits\Blocking\Owner\ValueOwnerFactory; @@ -56,7 +56,7 @@ public function testSelfBlock(): void public function testOtherBlock(): void { - $this->expectException(BlockFailedException::class); + $this->expectException(AlreadyBlockedException::class); $this->expectExceptionMessage('Identifier my_item is already blocked.'); $storage = new InMemoryStorage($this->clock); diff --git a/tests/Functional/PredisTest.php b/tests/Functional/PredisTest.php index e58154f..f660466 100644 --- a/tests/Functional/PredisTest.php +++ b/tests/Functional/PredisTest.php @@ -14,7 +14,7 @@ namespace Brainbits\Blocking\Tests\Functional; use Brainbits\Blocking\Blocker; -use Brainbits\Blocking\Exception\BlockFailedException; +use Brainbits\Blocking\Exception\AlreadyBlockedException; use Brainbits\Blocking\Identity\BlockIdentity; use Brainbits\Blocking\Owner\ValueOwnerFactory; use Brainbits\Blocking\Storage\PredisStorage; @@ -67,7 +67,7 @@ public function testSelfBlock(): void public function testOtherBlock(): void { - $this->expectException(BlockFailedException::class); + $this->expectException(AlreadyBlockedException::class); $this->expectExceptionMessage('Identifier my_item is already blocked.'); $this->client->set('block:my_item', json_encode(['identity' => 'my_item', 'owner' => 'other_owner']));