Skip to content

Commit 62ceaee

Browse files
committed
improve no more middleware exception
1 parent 85cb452 commit 62ceaee

8 files changed

Lines changed: 117 additions & 11 deletions

File tree

phpstan-baseline.neon

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,12 @@ parameters:
132132
count: 2
133133
path: src/MetadataHydrator.php
134134

135+
-
136+
message: '#^Strict comparison using \=\=\= between non\-empty\-list\<Patchlevel\\Hydrator\\Middleware\\Middleware\> and array\{\} will always evaluate to false\.$#'
137+
identifier: identical.alwaysFalse
138+
count: 1
139+
path: src/Middleware/Stack.php
140+
135141
-
136142
message: '#^Method Patchlevel\\Hydrator\\Middleware\\TransformMiddleware\:\:hydrate\(\) should return T of object but returns mixed\.$#'
137143
identifier: return.type
@@ -186,6 +192,12 @@ parameters:
186192
count: 1
187193
path: src/Normalizer/ReflectionTypeUtil.php
188194

195+
-
196+
message: '#^Parameter \#2 \$middlewares of class Patchlevel\\Hydrator\\StackHydrator constructor expects non\-empty\-list\<Patchlevel\\Hydrator\\Middleware\\Middleware\>, list\<Patchlevel\\Hydrator\\Middleware\\Middleware\> given\.$#'
197+
identifier: argument.type
198+
count: 1
199+
path: src/StackHydratorBuilder.php
200+
189201
-
190202
message: '#^Property Patchlevel\\Hydrator\\Tests\\Unit\\Extension\\Cryptography\\Fixture\\ChildWithSensitiveDataWithIdentifierDto\:\:\$email is never read, only written\.$#'
191203
identifier: property.onlyWritten
@@ -240,6 +252,12 @@ parameters:
240252
count: 1
241253
path: tests/Unit/MetadataHydratorTest.php
242254

255+
-
256+
message: '#^Parameter \#1 \$middlewares of class Patchlevel\\Hydrator\\Middleware\\Stack constructor expects non\-empty\-list\<Patchlevel\\Hydrator\\Middleware\\Middleware\>, array\{\} given\.$#'
257+
identifier: argument.type
258+
count: 1
259+
path: tests/Unit/Middleware/StackTest.php
260+
243261
-
244262
message: '#^Cannot cast mixed to int\.$#'
245263
identifier: cast.int
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Patchlevel\Hydrator\Middleware;
6+
7+
use Patchlevel\Hydrator\HydratorException;
8+
use RuntimeException;
9+
10+
/** @experimental */
11+
final class MissingMiddlewares extends RuntimeException implements HydratorException
12+
{
13+
public function __construct()
14+
{
15+
parent::__construct('No middleware available.');
16+
}
17+
}

src/Middleware/NoMoreMiddleware.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,23 @@
77
use Patchlevel\Hydrator\HydratorException;
88
use RuntimeException;
99

10+
use function array_map;
11+
use function count;
12+
use function implode;
13+
use function sprintf;
14+
1015
/** @experimental */
1116
final class NoMoreMiddleware extends RuntimeException implements HydratorException
1217
{
13-
public function __construct()
18+
/** @param non-empty-list<Middleware> $middlewares */
19+
public function __construct(array $middlewares)
1420
{
15-
parent::__construct('no more middlewares');
21+
parent::__construct(
22+
sprintf(
23+
'The next middleware in %s was requested, but no further middleware exists. The following middlewares were executed: %s',
24+
$middlewares[count($middlewares) - 1]::class,
25+
implode(', ', array_map(static fn (Middleware $middleware): string => $middleware::class, $middlewares)),
26+
),
27+
);
1628
}
1729
}

src/Middleware/Stack.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,21 @@ final class Stack
99
{
1010
private int $index = 0;
1111

12-
/** @param list<Middleware> $middlewares */
12+
/** @param non-empty-list<Middleware> $middlewares */
1313
public function __construct(
1414
private readonly array $middlewares,
1515
) {
16+
if ($middlewares === []) {
17+
throw new MissingMiddlewares();
18+
}
1619
}
1720

1821
public function next(): Middleware
1922
{
2023
$next = $this->middlewares[$this->index] ?? null;
2124

2225
if ($next === null) {
23-
throw new NoMoreMiddleware();
26+
throw new NoMoreMiddleware($this->middlewares);
2427
}
2528

2629
$this->index++;

src/StackHydrator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ final class StackHydrator implements HydratorWithContext
2424
/** @var array<class-string, ClassMetadata> */
2525
private array $classMetadata = [];
2626

27-
/** @param list<Middleware> $middlewares */
27+
/** @param non-empty-list<Middleware> $middlewares */
2828
public function __construct(
2929
private readonly MetadataFactory $metadataFactory = new AttributeMetadataFactory(),
3030
private readonly array $middlewares = [new TransformMiddleware()],
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Patchlevel\Hydrator\Tests\Unit\Fixture;
6+
7+
use Patchlevel\Hydrator\Metadata\ClassMetadata;
8+
use Patchlevel\Hydrator\Middleware\Middleware;
9+
use Patchlevel\Hydrator\Middleware\Stack;
10+
11+
final class DummyMiddleware implements Middleware
12+
{
13+
/**
14+
* @param ClassMetadata<T> $metadata
15+
* @param array<string, mixed> $data
16+
* @param array<string, mixed> $context
17+
*
18+
* @return T
19+
*
20+
* @template T of object
21+
*/
22+
public function hydrate(ClassMetadata $metadata, array $data, array $context, Stack $stack): object
23+
{
24+
return $stack->next()->hydrate($metadata, $data, $context, $stack);
25+
}
26+
27+
/**
28+
* @param array<string, mixed> $context
29+
*
30+
* @return array<string, mixed>
31+
*/
32+
public function extract(ClassMetadata $metadata, object $object, array $context, Stack $stack): array
33+
{
34+
return $stack->next()->extract($metadata, $object, $context, $stack);
35+
}
36+
}

tests/Unit/Middleware/StackTest.php

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44

55
namespace Patchlevel\Hydrator\Tests\Unit\Middleware;
66

7-
use Patchlevel\Hydrator\Middleware\Middleware;
7+
use Patchlevel\Hydrator\Middleware\MissingMiddlewares;
88
use Patchlevel\Hydrator\Middleware\NoMoreMiddleware;
99
use Patchlevel\Hydrator\Middleware\Stack;
10+
use Patchlevel\Hydrator\Tests\Unit\Fixture\DummyMiddleware;
1011
use PHPUnit\Framework\Attributes\CoversClass;
1112
use PHPUnit\Framework\TestCase;
1213

@@ -15,20 +16,39 @@ final class StackTest extends TestCase
1516
{
1617
public function testEmptyStack(): void
1718
{
18-
$this->expectException(NoMoreMiddleware::class);
19+
$this->expectException(MissingMiddlewares::class);
20+
$this->expectExceptionMessage('No middleware available.');
1921

2022
$stack = new Stack([]);
2123
$stack->next();
2224
}
2325

2426
public function testStack(): void
2527
{
26-
$middleware1 = $this->createStub(Middleware::class);
27-
$middleware2 = $this->createStub(Middleware::class);
28+
$middleware1 = new DummyMiddleware();
29+
$middleware2 = new DummyMiddleware();
2830

2931
$stack = new Stack([$middleware1, $middleware2]);
3032

3133
self::assertSame($middleware1, $stack->next());
3234
self::assertSame($middleware2, $stack->next());
3335
}
36+
37+
public function testStackThrowsExceptionWhenNoMoreMiddlewareIsAvailable(): void
38+
{
39+
$middleware1 = new DummyMiddleware();
40+
$middleware2 = new DummyMiddleware();
41+
42+
$stack = new Stack([$middleware1, $middleware2]);
43+
44+
$stack->next();
45+
$stack->next();
46+
47+
$this->expectException(NoMoreMiddleware::class);
48+
$this->expectExceptionMessage(
49+
'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',
50+
);
51+
52+
$stack->next();
53+
}
3454
}

tests/Unit/Middleware/TransformerMiddlewareTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public function testHydrate(): void
3030
$this->classMetadata(ProfileCreated::class),
3131
['profileId' => '1', 'email' => 'info@patchlevel.de'],
3232
[],
33-
new Stack([]),
33+
new Stack([$middleware]),
3434
);
3535

3636
self::assertEquals($expected, $event);
@@ -49,7 +49,7 @@ public function testExtract(): void
4949
Email::fromString('info@patchlevel.de'),
5050
),
5151
[],
52-
new Stack([]),
52+
new Stack([$middleware]),
5353
);
5454

5555
self::assertEquals($expected, $data);

0 commit comments

Comments
 (0)