Skip to content

Commit f2a55cc

Browse files
authored
Merge pull request #861 from patchlevel/docs-upgrade-4.0
docs: complete 4.0 upgrade guide for merged breaking changes
2 parents 543bd2c + 05b81e4 commit f2a55cc

3 files changed

Lines changed: 125 additions & 7 deletions

File tree

docs/UPGRADE-4.0.md

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,75 @@ Further changes:
140140
* `ProcessedResult` now extends `Result`, so the `execute` method always returns a `Result`. The `Boot` and `Run` commands return a `ProcessedResult`.
141141
* The `DefaultSubscriptionEngine` accepts an optional `EventDispatcherInterface` as last constructor argument to hook into the engine with own listeners.
142142

143+
### SubscriberHelper and SubscriberUtil
144+
145+
The deprecated `Patchlevel\EventSourcing\Subscription\Subscriber\SubscriberHelper`
146+
and the `Patchlevel\EventSourcing\Subscription\Subscriber\SubscriberUtil` trait have been removed.
147+
148+
If you used them inside a projector to keep the projector id and the table name in sync,
149+
use a constant instead:
150+
151+
```php
152+
use Doctrine\DBAL\Connection;
153+
use Patchlevel\EventSourcing\Attribute\Projector;
154+
155+
#[Projector(self::TABLE)]
156+
final class HotelProjector
157+
{
158+
// use a const for easier access in the projector & to keep projector id and table name in sync
159+
private const TABLE = 'hotel';
160+
161+
public function __construct(
162+
private readonly Connection $db,
163+
) {
164+
}
165+
166+
/** @return list<array{id: string, name: string, guests: int}> */
167+
public function getHotels(): array
168+
{
169+
return $this->db->fetchAllAssociative(sprintf('SELECT id, name, guests FROM %s;', self::TABLE));
170+
}
171+
172+
// ...
173+
}
174+
```
175+
176+
If you still need the subscriber id elsewhere, read it from the metadata instead:
177+
178+
```php
179+
use Patchlevel\EventSourcing\Metadata\Subscriber\AttributeSubscriberMetadataFactory;
180+
181+
$metadata = (new AttributeSubscriberMetadataFactory())->metadata($subscriber::class);
182+
$subscriberId = $metadata->id;
183+
```
184+
185+
### SubscriberAccessor and RealSubscriberAccessor
186+
187+
The `Patchlevel\EventSourcing\Subscription\Subscriber\SubscriberAccessor` and
188+
`Patchlevel\EventSourcing\Subscription\Subscriber\RealSubscriberAccessor` interfaces have been removed.
189+
Use `Patchlevel\EventSourcing\Subscription\Subscriber\MetadataSubscriberAccessor` directly.
190+
191+
Accordingly, `SubscriberAccessorRepository::get()` now returns a `MetadataSubscriberAccessor|null`
192+
instead of a `SubscriberAccessor|null`.
193+
194+
The deprecated methods `id()`, `group()` and `runMode()` on `MetadataSubscriberAccessor` have been removed.
195+
Use `->metadata()->id`, `->metadata()->group` and `->metadata()->runMode` instead.
196+
197+
### AggregateIdArgumentResolver
198+
199+
The deprecated `Patchlevel\EventSourcing\Subscription\Subscriber\ArgumentResolver\AggregateIdArgumentResolver`
200+
has been removed. Automatically resolving the aggregate id in a stream store is not possible.
201+
Add the aggregate id to your events instead.
202+
203+
### ArgumentMetadata
204+
205+
The subscriber argument resolver now uses `symfony/type-info` to describe argument types.
206+
207+
`Patchlevel\EventSourcing\Metadata\Subscriber\ArgumentMetadata` no longer carries a `string $type`
208+
and a `bool $allowsNull` property. Instead it now has a single `Symfony\Component\TypeInfo\Type $type` property.
209+
210+
If you implemented a custom `ArgumentResolver`, adjust it to read the type from the new `Type` object.
211+
143212
## Store
144213

145214
### StreamStore
@@ -160,6 +229,49 @@ And all the associated classes:
160229

161230
`StreamReadOnlyStore` was been merged in `ReadOnlyStore`.
162231

232+
## Stream
233+
234+
The stream handling has been reworked. Previously the `Stream` was an interface that every store had to
235+
implement on its own (`ArrayStream`, `StreamDoctrineDbalStoreStream`, `TaggableDoctrineDbalStoreStream`,
236+
`GeneratorStream`, ...). Now there is a single generic implementation that you can reuse.
237+
238+
### Stream interface
239+
240+
The `Patchlevel\EventSourcing\Store\Stream` interface has been removed and replaced by the concrete final
241+
class `Patchlevel\EventSourcing\Message\Stream`.
242+
243+
All stores now return a `Patchlevel\EventSourcing\Message\Stream` from their `load()` method.
244+
The following store specific stream implementations have been removed:
245+
246+
* `Patchlevel\EventSourcing\Store\ArrayStream`
247+
* `Patchlevel\EventSourcing\Store\StreamDoctrineDbalStoreStream`
248+
* `Patchlevel\EventSourcing\Store\TaggableDoctrineDbalStoreStream`
249+
* `Patchlevel\EventSourcing\Subscription\Engine\GeneratorStream`
250+
251+
The new `Stream` class implements `Iterator` and accepts any `iterable<Message>` in its constructor.
252+
The `index()`, `position()`, `end()` and `close()` methods remain available.
253+
In addition there are now the helper methods `toList()`, `toArray()`, `transform()` and `chunk()`.
254+
255+
### Pipe
256+
257+
`Patchlevel\EventSourcing\Message\Pipe` has been removed. Use `Stream::transform()` instead.
258+
259+
before:
260+
261+
```php
262+
use Patchlevel\EventSourcing\Message\Pipe;
263+
264+
$messages = (new Pipe($messages, $translator))->toArray();
265+
```
266+
267+
after:
268+
269+
```php
270+
use Patchlevel\EventSourcing\Message\Stream;
271+
272+
$messages = (new Stream($messages))->transform($translator)->toList();
273+
```
274+
163275
## Message
164276

165277
### AggregateHeader

docs/getting-started.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ final class HotelProjector
178178
/** @return list<array{id: string, name: string, guests: int}> */
179179
public function getHotels(): array
180180
{
181-
return $this->db->fetchAllAssociative(sprintf('SELECT id, name, guests FROM %s;'), self::TABLE);
181+
return $this->db->fetchAllAssociative(sprintf('SELECT id, name, guests FROM %s;', self::TABLE));
182182
}
183183

184184
#[Subscribe(HotelCreated::class)]

docs/message.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,27 +97,33 @@ use Patchlevel\EventSourcing\Message\Message;
9797
/** @var Message $message */
9898
$message->header(ApplicationHeader::class);
9999
```
100-
## Pipe
100+
## Stream
101101

102-
The `Pipe` is a construct that allows you to chain multiple translators.
102+
A `Stream` wraps an iterable of messages and allows you to chain multiple translators with `transform`.
103103
This can be used to manipulate, filter or expand messages or events.
104104
This can be used for anti-corruption layers, data migration, or to fix errors in the event stream.
105105

106106
```php
107-
use Patchlevel\EventSourcing\Message\Pipe;
107+
use Patchlevel\EventSourcing\Message\Stream;
108108
use Patchlevel\EventSourcing\Message\Translator\ExcludeEventTranslator;
109109
use Patchlevel\EventSourcing\Message\Translator\RecalculatePlayheadTranslator;
110110

111-
$messages = new Pipe(
112-
$messages,
111+
$stream = (new Stream($messages))->transform(
113112
new ExcludeEventTranslator([ProfileCreated::class]),
114113
new RecalculatePlayheadTranslator(),
115114
);
116115

117-
foreach ($messages as $message) {
116+
foreach ($stream as $message) {
118117
// do something with the message
119118
}
120119
```
120+
121+
:::tip
122+
A `Stream` is also what every store returns from its `load` method, so you can apply the same
123+
transformations to the messages you read from the store. Besides iterating, a `Stream` offers
124+
`toList()`, `toArray()` and `chunk()` to consume the messages.
125+
:::
126+
121127
## Translator
122128

123129
Translator can be used to manipulate, filter or expand messages or events.

0 commit comments

Comments
 (0)