Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions docs/aggregate-id.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ use Patchlevel\EventSourcing\Aggregate\Uuid;
$uuid = Uuid::generate();
$uuid = Uuid::fromString('d6e8d7a0-4b0b-4e6a-8a9a-3a0b2d9d0e4e');
```

:::note
We implemented the version 7 of the uuid, because it is most suitable for event sourcing.
More information about uuid versions can be found [here](https://uuid.ramsey.dev/en/stable/rfc4122.html).
Expand All @@ -65,9 +64,8 @@ final class Profile extends BasicAggregateRoot
private CustomId $id;
}
```

:::warning
If you want to use a custom id that is not an uuid,
If you want to use a custom id that is not an uuid,
you need to change the `aggregate_id_type` to `string` in the store configuration.
More information can be found [here](store.md).
:::
Expand Down
24 changes: 4 additions & 20 deletions docs/aggregate.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ One main difference is that we don't save the current state, but only the indivi
This means it is always possible to build the current state again from the events.

:::note
The term aggregate itself comes from DDD and has nothing to do with event sourcing and can be used independently as a pattern.
The term aggregate itself comes from DDD and has nothing to do with event sourcing and can be used independently as a pattern.
You can find out more about Aggregates [here](https://martinfowler.com/bliki/DDD_Aggregate.html).
:::

Expand Down Expand Up @@ -44,7 +44,6 @@ final class Profile extends BasicAggregateRoot
}
}
```

:::warning
The aggregate is not yet finished and has only been built to the point that you can instantiate the object.
:::
Expand Down Expand Up @@ -77,7 +76,6 @@ final class CreateProfileHandler
}
}
```

:::warning
If you look in the database now, you would see that nothing has been saved.
This is because only events are stored in the database and as long as no events exist,
Expand Down Expand Up @@ -109,7 +107,6 @@ final class ProfileRegistered
}
}
```

:::note
You can find out more about events [here](events.md).
:::
Expand Down Expand Up @@ -151,7 +148,6 @@ final class Profile extends BasicAggregateRoot
}
}
```

:::tip
Prefixing the apply methods with "apply" improves readability.
:::
Expand Down Expand Up @@ -185,7 +181,6 @@ final class NameChanged
}
}
```

:::note
Events should best be written in the past, as they describe a state that has happened.
:::
Expand Down Expand Up @@ -262,7 +257,6 @@ final class ChangeNameHandler
}
}
```

:::success
Our aggregate can now be changed and saved.
:::
Expand Down Expand Up @@ -309,9 +303,8 @@ final class Profile extends BasicAggregateRoot
}
}
```

:::tip
You don't necessarily need to define multiple `Apply` attributes with the event class
You don't necessarily need to define multiple `Apply` attributes with the event class
if you define the event types in the method using a union type.
:::

Expand Down Expand Up @@ -366,7 +359,6 @@ final class Profile extends BasicAggregateRoot
}
}
```

:::warning
When all events are suppressed, debugging becomes more difficult if you forget an apply method.
:::
Expand Down Expand Up @@ -399,7 +391,6 @@ final class PersonalInformation extends BasicAggregateRoot
{
}
```

:::warning
You need to define the `SharedApplyContext` attribute on all aggregates that share the apply context.
:::
Expand Down Expand Up @@ -443,7 +434,6 @@ final class GuestList extends BasicAggregateRoot
// ...
}
```

:::tip
You can find more about splitting aggregates [here](aggregate.md#splitting-aggregates).
:::
Expand Down Expand Up @@ -486,7 +476,6 @@ final class Profile extends BasicAggregateRoot
}
}
```

:::danger
Validations during "apply" should not happen, they will break the rebuilding of the aggregate!
Instead validate the data *before* the event will be recorded.
Expand Down Expand Up @@ -573,7 +562,6 @@ final class NameChanged
}
}
```

:::warning
You need to create a normalizer for the `Name` value object.
So the payload must be serializable and unserializable as json.
Expand Down Expand Up @@ -793,7 +781,6 @@ final class Shipping extends BasicAggregateRoot
}
}
```

:::tip
With the [SharedApplyContext](aggregate.md#shared-apply-context) attribute,
you can suppress missing applies for events that are handled by other aggregates.
Expand Down Expand Up @@ -842,7 +829,6 @@ final class Shipping extends BasicChildAggregate
}
}
```

:::warning
The apply method must be public, otherwise the root aggregate cannot call it.
:::
Expand Down Expand Up @@ -890,16 +876,15 @@ final class Order extends BasicAggregateRoot
}
}
```

## Auto Initialize

:::experimental
This feature is still experimental and may change in the future.
Use it with caution.
:::

Sometimes you want to be able to access an aggregate even if it has not yet been created in the system.
In this case, the aggregate should be automatically initialized if it cannot be found in the store.
Sometimes you want to be able to access an aggregate even if it has not yet been created in the system.
In this case, the aggregate should be automatically initialized if it cannot be found in the store.
To achieve this, the aggregate must mark the initialization method with the `AutoInitialize` attribute.
The method must be static, receives the aggregate ID as an argument and must return an instance of the aggregate.

Expand Down Expand Up @@ -933,7 +918,6 @@ final class Profile extends BasicAggregateRoot
}
}
```

:::note
Recording events in the `initialize` method is optional but recommended.
:::
Expand Down
3 changes: 1 addition & 2 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,8 @@ $cli->addCommands([
new Command\VersionCommand($dependencyFactory, 'event-sourcing:migrations:version'),
]);
```

:::note
Here you can find more information on how to
Here you can find more information on how to
[configure doctrine migration](https://www.doctrine-project.org/projects/doctrine-migrations/en/3.3/reference/custom-configuration.html).
:::

Expand Down
1 change: 0 additions & 1 deletion docs/clock.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ $clock = new FrozenClock($firstDate);

$clock->sleep(10); // sleep 10 seconds
```

:::note
The instance of the frozen datetime will be cloned internally, so the it's not the same instance but equals.
:::
Expand Down
16 changes: 3 additions & 13 deletions docs/command-bus.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ final class CreateProfileHandler
}
}
```

:::note
To use Service Handler you need to register the handler in the `ServiceHandlerProvider`.
:::
Expand All @@ -65,7 +64,6 @@ final class CreateProfileHandler
}
}
```

### Union Types

You can also use union types to handle multiple commands and the library will automatically detect the commands.
Expand All @@ -82,7 +80,6 @@ final class CreateProfileHandler
}
}
```

### Inheritance

The handler will also be invoked if the command implements an interface or extends a class that the handler expects.
Expand All @@ -99,15 +96,14 @@ final class CreateProfileHandler
}
}
```

### Aggregate Handler

Another way to handle commands is to use the aggregates themselves.
To do this, you need to mark the method that handles the command with the `#[Handle]` attribute.

:::note
The aggregates themselves are of course not a service.
The AggregateHandlerProvider uses the aggregates to create the handlers for you.
The aggregates themselves are of course not a service.
The AggregateHandlerProvider uses the aggregates to create the handlers for you.
You can find out more about this in the [providers](command-bus.md#provider) section.
:::

Expand Down Expand Up @@ -140,7 +136,6 @@ final class Profile extends BasicAggregateRoot
// ... apply methods
}
```

:::tip
You can find more information about aggregates [here](aggregate.md).
:::
Expand Down Expand Up @@ -193,9 +188,8 @@ final class Profile extends BasicAggregateRoot
// ... apply methods
}
```

:::tip
If you want to automatically initialize an aggregate if it cannot be found in the store,
If you want to automatically initialize an aggregate if it cannot be found in the store,
you can use the [Auto Initialize](aggregate.md#auto-initialize) feature.
:::

Expand Down Expand Up @@ -233,7 +227,6 @@ final class Profile extends BasicAggregateRoot
// ... apply methods
}
```

:::note
The service must be registered in the service locator.
:::
Expand Down Expand Up @@ -274,7 +267,6 @@ final class Profile extends BasicAggregateRoot
// ... apply methods
}
```

:::note
Injection in handler methods is only possible with the `AggregateHandlerProvider`.
:::
Expand Down Expand Up @@ -327,7 +319,6 @@ final class CreateProfile
}
}
```

:::tip
You can override the default values for the maximum number of retries and the conditions
by passing them to the `InstantRetry` attribute.
Expand Down Expand Up @@ -405,7 +396,6 @@ $provider = new AggregateHandlerProvider(
]), // or other psr-11 compatible container
);
```

:::tip
You can find suitable implementations of psr-11 containers on [packagist](https://packagist.org/search/?tags=PSR-11).
:::
Expand Down
5 changes: 0 additions & 5 deletions docs/event-bus.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ use Patchlevel\EventSourcing\EventBus\DefaultEventBus;

$eventBus = DefaultEventBus::create([$mailListener]);
```

:::note
The order in which the listeners are executed is determined by the order in which they are passed to the factory.
:::
Expand Down Expand Up @@ -56,7 +55,6 @@ $eventBus = new DefaultEventBus(
new DefaultConsumer($listenerProvider),
);
```

:::tip
The `DefaultEventBus::create` method uses the `DefaultConsumer` and `AttributeListenerProvider` by default.
:::
Expand All @@ -80,7 +78,6 @@ $listenerProvider = new class implements ListenerProvider {
}
};
```

:::tip
You can use `$listenerDiscriptor->name()` to get the name of the listener.
:::
Expand All @@ -103,7 +100,6 @@ final class WelcomeSubscriber
}
}
```

:::tip
If you use psalm, you can use the [event sourcing plugin](https://github.com/patchlevel/event-sourcing-psalm-plugin) for better type support.
:::
Expand Down Expand Up @@ -136,7 +132,6 @@ use Patchlevel\EventSourcing\EventBus\Psr14EventBus;

$eventBus = new Psr14EventBus($psr14EventDispatcher);
```

:::warning
You can't use the `Subscribe` attribute with the psr-14 event bus.
:::
Expand Down
8 changes: 3 additions & 5 deletions docs/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ final class ProfileCreated
}
}
```

:::warning
The payload must be serializable and unserializable as json.
:::
Expand All @@ -41,7 +40,7 @@ Here are some examples:
* `profile.created`
* `profile.name_changed`
* `hotel.guest_checked_out`
:::
:::

## Alias

Expand Down Expand Up @@ -109,14 +108,13 @@ final class ProfileCreated
}
}
```

:::tip
Built-in normalizers like `IdNormalizer` and `DateTimeImmutableNormalizer` can be inferred from the type hint
Built-in normalizers like `IdNormalizer` and `DateTimeImmutableNormalizer` can be inferred from the type hint
and so you don't have to specify them. If you want to configure the Normalizer, you still have to do it.
:::

:::note
You can find out more about normalizer [here](normalizer.md).
You can find out more about normalizer [here](normalizer.md).
:::

## Event Registry
Expand Down
Loading
Loading