Skip to content

Commit f4fc2a2

Browse files
committed
Add MissingHeader, it will be created in the HeaderSerializer, if the Registry cannot find the header
1 parent 135d68b commit f4fc2a2

3 files changed

Lines changed: 77 additions & 4 deletions

File tree

src/Message/MissingHeader.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Patchlevel\EventSourcing\Message;
6+
7+
/**
8+
* Represents a header whose name could not be resolved to a registered class
9+
*/
10+
final class MissingHeader
11+
{
12+
/** @param array<string, mixed> $payload */
13+
public function __construct(
14+
public readonly string $name,
15+
public readonly array $payload,
16+
) {
17+
}
18+
}

src/Message/Serializer/DefaultHeadersSerializer.php

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

55
namespace Patchlevel\EventSourcing\Message\Serializer;
66

7+
use Patchlevel\EventSourcing\Message\MissingHeader;
78
use Patchlevel\EventSourcing\Metadata\Message\AttributeMessageHeaderRegistryFactory;
9+
use Patchlevel\EventSourcing\Metadata\Message\HeaderNameNotRegistered;
810
use Patchlevel\EventSourcing\Metadata\Message\MessageHeaderRegistry;
911
use Patchlevel\EventSourcing\Serializer\Encoder\Encoder;
1012
use Patchlevel\EventSourcing\Serializer\Encoder\JsonEncoder;
@@ -30,6 +32,12 @@ public function serialize(array $headers, array $options = []): string
3032
{
3133
$serializedHeaders = [];
3234
foreach ($headers as $header) {
35+
if ($header instanceof MissingHeader) {
36+
$serializedHeaders[$header->name] = $header->payload;
37+
38+
continue;
39+
}
40+
3341
$serializedHeaders[$this->messageHeaderRegistry->headerName($header::class)] = $this->hydrator->extract($header);
3442
}
3543

@@ -51,10 +59,14 @@ public function deserialize(string $string, array $options = []): array
5159
throw new InvalidArgument('header payload must be an array');
5260
}
5361

54-
$headers[] = $this->hydrator->hydrate(
55-
$this->messageHeaderRegistry->headerClass($headerName),
56-
$headerPayload,
57-
);
62+
try {
63+
$headers[] = $this->hydrator->hydrate(
64+
$this->messageHeaderRegistry->headerClass($headerName),
65+
$headerPayload,
66+
);
67+
} catch (HeaderNameNotRegistered) {
68+
$headers[] = new MissingHeader($headerName, $headerPayload);
69+
}
5870
}
5971

6072
return $headers;

tests/Unit/Message/Serializer/DefaultHeadersSerializerTest.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Patchlevel\EventSourcing\Tests\Unit\Message\Serializer;
66

77
use DateTimeImmutable;
8+
use Patchlevel\EventSourcing\Message\MissingHeader;
89
use Patchlevel\EventSourcing\Message\Serializer\DefaultHeadersSerializer;
910
use Patchlevel\EventSourcing\Metadata\Message\AttributeMessageHeaderRegistryFactory;
1011
use Patchlevel\EventSourcing\Serializer\Encoder\JsonEncoder;
@@ -60,4 +61,46 @@ public function testDeserialize(): void
6061
$deserializedMessage,
6162
);
6263
}
64+
65+
public function testDeserializeUnknownHeaderAsMissingHeader(): void
66+
{
67+
$serializer = new DefaultHeadersSerializer(
68+
(new AttributeMessageHeaderRegistryFactory())->create([
69+
__DIR__ . '/../../Fixture',
70+
]),
71+
new MetadataHydrator(),
72+
new JsonEncoder(),
73+
);
74+
75+
$deserializedMessage = $serializer->deserialize('{"streamName":{"streamName":"profile-1"},"removed":{"foo":"bar"}}');
76+
77+
self::assertEquals(
78+
[
79+
new StreamNameHeader('profile-1'),
80+
new MissingHeader('removed', ['foo' => 'bar']),
81+
],
82+
$deserializedMessage,
83+
);
84+
}
85+
86+
public function testSerializeMissingHeaderRoundTrip(): void
87+
{
88+
$serializer = new DefaultHeadersSerializer(
89+
(new AttributeMessageHeaderRegistryFactory())->create([
90+
__DIR__ . '/../../Fixture',
91+
]),
92+
new MetadataHydrator(),
93+
new JsonEncoder(),
94+
);
95+
96+
$content = $serializer->serialize([
97+
new StreamNameHeader('profile-1'),
98+
new MissingHeader('removed', ['foo' => 'bar']),
99+
]);
100+
101+
self::assertEquals(
102+
'{"streamName":{"streamName":"profile-1"},"removed":{"foo":"bar"}}',
103+
$content,
104+
);
105+
}
63106
}

0 commit comments

Comments
 (0)