From df2603a59e47c6141fb873691c88c383635cb83b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 Apr 2026 00:30:39 +0000 Subject: [PATCH 1/2] Update actions/github-script action to v9 | datasource | package | from | to | | ----------- | --------------------- | ---- | -- | | github-tags | actions/github-script | v8 | v9 | Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/benchmark.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 60f97d2..5316d72 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -59,7 +59,7 @@ jobs: cat bench.txt >> $GITHUB_ENV echo 'EOF' >> $GITHUB_ENV - - uses: actions/github-script@v8 + - uses: actions/github-script@v9 with: script: | // Get the existing comments. From 0668f18a8f6aa5e09d40bcf646543345e2a401ac Mon Sep 17 00:00:00 2001 From: David Badura Date: Tue, 28 Apr 2026 10:23:50 +0200 Subject: [PATCH 2/2] improve no more middleware exception --- phpstan-baseline.neon | 6 ++++ src/Middleware/NoMoreMiddleware.php | 16 +++++++-- src/Middleware/Stack.php | 4 +-- src/MissingMiddlewares.php | 16 +++++++++ src/StackHydrator.php | 3 ++ tests/Unit/Fixture/DummyMiddleware.php | 36 +++++++++++++++++++ tests/Unit/Middleware/StackTest.php | 30 ++++++++++------ .../Middleware/TransformerMiddlewareTest.php | 4 +-- tests/Unit/StackHydratorBuilderTest.php | 8 +++++ tests/Unit/StackHydratorTest.php | 13 +++++++ 10 files changed, 120 insertions(+), 16 deletions(-) create mode 100644 src/MissingMiddlewares.php create mode 100644 tests/Unit/Fixture/DummyMiddleware.php diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 6f81159..47b6c0a 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -186,6 +186,12 @@ parameters: count: 1 path: src/Normalizer/ReflectionTypeUtil.php + - + message: '#^Parameter \#1 \$middlewares of class Patchlevel\\Hydrator\\Middleware\\Stack constructor expects non\-empty\-list\, list\ given\.$#' + identifier: argument.type + count: 4 + path: src/StackHydrator.php + - message: '#^Property Patchlevel\\Hydrator\\Tests\\Unit\\Extension\\Cryptography\\Fixture\\ChildWithSensitiveDataWithIdentifierDto\:\:\$email is never read, only written\.$#' identifier: property.onlyWritten diff --git a/src/Middleware/NoMoreMiddleware.php b/src/Middleware/NoMoreMiddleware.php index 4d06399..7b0c3a2 100644 --- a/src/Middleware/NoMoreMiddleware.php +++ b/src/Middleware/NoMoreMiddleware.php @@ -7,11 +7,23 @@ use Patchlevel\Hydrator\HydratorException; use RuntimeException; +use function array_map; +use function count; +use function implode; +use function sprintf; + /** @experimental */ final class NoMoreMiddleware extends RuntimeException implements HydratorException { - public function __construct() + /** @param non-empty-list $middlewares */ + public function __construct(array $middlewares) { - parent::__construct('no more middlewares'); + parent::__construct( + sprintf( + 'The next middleware in %s was requested, but no further middleware exists. The following middlewares were executed: %s', + $middlewares[count($middlewares) - 1]::class, + implode(', ', array_map(static fn (Middleware $middleware): string => $middleware::class, $middlewares)), + ), + ); } } diff --git a/src/Middleware/Stack.php b/src/Middleware/Stack.php index 6be11ea..cacb6d7 100644 --- a/src/Middleware/Stack.php +++ b/src/Middleware/Stack.php @@ -9,7 +9,7 @@ final class Stack { private int $index = 0; - /** @param list $middlewares */ + /** @param non-empty-list $middlewares */ public function __construct( private readonly array $middlewares, ) { @@ -20,7 +20,7 @@ public function next(): Middleware $next = $this->middlewares[$this->index] ?? null; if ($next === null) { - throw new NoMoreMiddleware(); + throw new NoMoreMiddleware($this->middlewares); } $this->index++; diff --git a/src/MissingMiddlewares.php b/src/MissingMiddlewares.php new file mode 100644 index 0000000..817ac6b --- /dev/null +++ b/src/MissingMiddlewares.php @@ -0,0 +1,16 @@ + $metadata + * @param array $data + * @param array $context + * + * @return T + * + * @template T of object + */ + public function hydrate(ClassMetadata $metadata, array $data, array $context, Stack $stack): object + { + return $stack->next()->hydrate($metadata, $data, $context, $stack); + } + + /** + * @param array $context + * + * @return array + */ + public function extract(ClassMetadata $metadata, object $object, array $context, Stack $stack): array + { + return $stack->next()->extract($metadata, $object, $context, $stack); + } +} diff --git a/tests/Unit/Middleware/StackTest.php b/tests/Unit/Middleware/StackTest.php index 31f30b2..1daf96d 100644 --- a/tests/Unit/Middleware/StackTest.php +++ b/tests/Unit/Middleware/StackTest.php @@ -4,31 +4,41 @@ namespace Patchlevel\Hydrator\Tests\Unit\Middleware; -use Patchlevel\Hydrator\Middleware\Middleware; use Patchlevel\Hydrator\Middleware\NoMoreMiddleware; use Patchlevel\Hydrator\Middleware\Stack; +use Patchlevel\Hydrator\Tests\Unit\Fixture\DummyMiddleware; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; #[CoversClass(Stack::class)] final class StackTest extends TestCase { - public function testEmptyStack(): void + public function testStack(): void { - $this->expectException(NoMoreMiddleware::class); + $middleware1 = new DummyMiddleware(); + $middleware2 = new DummyMiddleware(); - $stack = new Stack([]); - $stack->next(); + $stack = new Stack([$middleware1, $middleware2]); + + self::assertSame($middleware1, $stack->next()); + self::assertSame($middleware2, $stack->next()); } - public function testStack(): void + public function testStackThrowsExceptionWhenNoMoreMiddlewareIsAvailable(): void { - $middleware1 = $this->createStub(Middleware::class); - $middleware2 = $this->createStub(Middleware::class); + $middleware1 = new DummyMiddleware(); + $middleware2 = new DummyMiddleware(); $stack = new Stack([$middleware1, $middleware2]); - self::assertSame($middleware1, $stack->next()); - self::assertSame($middleware2, $stack->next()); + $stack->next(); + $stack->next(); + + $this->expectException(NoMoreMiddleware::class); + $this->expectExceptionMessage( + 'The next middleware in Patchlevel\Hydrator\Tests\Unit\Fixture\DummyMiddleware was requested, but no further middleware exists. The following middlewares were executed: Patchlevel\Hydrator\Tests\Unit\Fixture\DummyMiddleware, Patchlevel\Hydrator\Tests\Unit\Fixture\DummyMiddleware', + ); + + $stack->next(); } } diff --git a/tests/Unit/Middleware/TransformerMiddlewareTest.php b/tests/Unit/Middleware/TransformerMiddlewareTest.php index b8c4c4a..4190de4 100644 --- a/tests/Unit/Middleware/TransformerMiddlewareTest.php +++ b/tests/Unit/Middleware/TransformerMiddlewareTest.php @@ -30,7 +30,7 @@ public function testHydrate(): void $this->classMetadata(ProfileCreated::class), ['profileId' => '1', 'email' => 'info@patchlevel.de'], [], - new Stack([]), + new Stack([$middleware]), ); self::assertEquals($expected, $event); @@ -49,7 +49,7 @@ public function testExtract(): void Email::fromString('info@patchlevel.de'), ), [], - new Stack([]), + new Stack([$middleware]), ); self::assertEquals($expected, $data); diff --git a/tests/Unit/StackHydratorBuilderTest.php b/tests/Unit/StackHydratorBuilderTest.php index bb4b9e8..274d8db 100644 --- a/tests/Unit/StackHydratorBuilderTest.php +++ b/tests/Unit/StackHydratorBuilderTest.php @@ -51,6 +51,8 @@ public function testAddMetadataEnricherWithPriority(): void $builder->addMetadataEnricher($enricher1, 10); $builder->addMetadataEnricher($enricher2, 20); + $builder->addMiddleware($this->createMock(Middleware::class)); + $hydrator = $builder->build(); $reflection = new ReflectionProperty(StackHydrator::class, 'metadataFactory'); @@ -74,6 +76,8 @@ public function testAddGuesserWithPriority(): void $builder->addGuesser($guesser1, 10); $builder->addGuesser($guesser2, 20); + $builder->addMiddleware($this->createMock(Middleware::class)); + $hydrator = $builder->build(); $reflection = new ReflectionProperty(StackHydrator::class, 'metadataFactory'); @@ -103,6 +107,8 @@ public function testEnableDefaultLazy(): void $builder = new StackHydratorBuilder(); $builder->enableDefaultLazy(); + $builder->addMiddleware($this->createMock(Middleware::class)); + $hydrator = $builder->build(); $reflection = new ReflectionProperty(StackHydrator::class, 'defaultLazy'); @@ -128,6 +134,7 @@ public function testCachePsr6(): void $builder = new StackHydratorBuilder(); $builder->setCache($cache); + $builder->addMiddleware($this->createMock(Middleware::class)); $hydrator = $builder->build(); @@ -143,6 +150,7 @@ public function testCachePsr16(): void $builder = new StackHydratorBuilder(); $builder->setCache($cache); + $builder->addMiddleware($this->createMock(Middleware::class)); $hydrator = $builder->build(); diff --git a/tests/Unit/StackHydratorTest.php b/tests/Unit/StackHydratorTest.php index ba2183b..4ec1fcb 100644 --- a/tests/Unit/StackHydratorTest.php +++ b/tests/Unit/StackHydratorTest.php @@ -11,10 +11,12 @@ use Patchlevel\Hydrator\ClassNotSupported; use Patchlevel\Hydrator\CoreExtension; use Patchlevel\Hydrator\DenormalizationFailure; +use Patchlevel\Hydrator\Metadata\AttributeMetadataFactory; use Patchlevel\Hydrator\Metadata\ClassMetadata; use Patchlevel\Hydrator\Middleware\Middleware; use Patchlevel\Hydrator\Middleware\Stack; use Patchlevel\Hydrator\Middleware\TransformMiddleware; +use Patchlevel\Hydrator\MissingMiddlewares; use Patchlevel\Hydrator\NormalizationFailure; use Patchlevel\Hydrator\Normalizer\HydratorAwareNormalizer; use Patchlevel\Hydrator\StackHydrator; @@ -58,6 +60,17 @@ public function setUp(): void $this->hydrator = new StackHydrator(); } + public function testMissingMiddlewares(): void + { + $this->expectException(MissingMiddlewares::class); + $this->expectExceptionMessage('Missing middlewares.'); + + new StackHydrator( + new AttributeMetadataFactory(), + [], + ); + } + public function testExtract(): void { $event = new ProfileCreated(