From 94c4ed7e896ae656755b9759b0c85c8d0d5ada43 Mon Sep 17 00:00:00 2001 From: codeliner Date: Sun, 15 Oct 2017 21:46:07 +0200 Subject: [PATCH] Retructure docs --- .gitignore | 1 + README.md | 1 + docs/bookdown.json | 6 +- docs/introduction.md | 271 ++++++++++++++++++ docs/snapshots/bookdown.json | 10 + .../introduction.md} | 8 +- 6 files changed, 290 insertions(+), 7 deletions(-) create mode 100644 docs/introduction.md create mode 100644 docs/snapshots/bookdown.json rename docs/{snapshots.md => snapshots/introduction.md} (71%) diff --git a/.gitignore b/.gitignore index 4602855..919470a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ .php_cs.cache nbproject composer.lock +docs/html diff --git a/README.md b/README.md index 12b63af..f43663a 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ with the bundled [AggregateRoot](https://github.com/prooph/event-sourcing/blob/m - Ask questions on Stack Overflow tagged with [#prooph](https://stackoverflow.com/questions/tagged/prooph). - File issues at [https://github.com/prooph/event-sourcing/issues](https://github.com/prooph/event-sourcing/issues). +- Say hello in the [prooph gitter](https://gitter.im/prooph/improoph) chat. # Used Third-Party Libraries diff --git a/docs/bookdown.json b/docs/bookdown.json index e39d3bf..a83d5e8 100644 --- a/docs/bookdown.json +++ b/docs/bookdown.json @@ -1,13 +1,15 @@ { "title": "Event Sourcing", "content": [ - {"intro": "../README.md"}, + {"intro": "introduction.md"}, {"repositories": "repositories.md"}, - {"snapshots": "snapshots.md"}, + {"snapshots": "snapshots/bookdown.json"}, {"inheritance": "inheritance.md"}, {"interop_factories": "interop_factories.md"}, {"migration": "migration.md"} ], + "tocDepth": 1, + "numbering": false, "target": "./html", "template": "../vendor/prooph/bookdown-template/templates/main.php" } diff --git a/docs/introduction.md b/docs/introduction.md new file mode 100644 index 0000000..9babe85 --- /dev/null +++ b/docs/introduction.md @@ -0,0 +1,271 @@ +# Introduction + +Simple and lightweight event sourcing library with out of the box support for [prooph/event-store](https://github.com/prooph/event-store) + +## Installation + +```bash +composer require prooph/event-sourcing +``` + +## Quickstart + +```php +recordThat(UserWasCreated::occur($uuid->toString(), ['name' => $username])); + + return $instance; + } + + public function userId(): Uuid + { + return $this->uuid; + } + + public function name(): string + { + return $this->name; + } + + public function changeName(string $newName): void + { + Assertion::notEmpty($newName); + + if ($newName !== $this->name) { + $this->recordThat(UserWasRenamed::occur( + $this->uuid->toString(), + ['new_name' => $newName, 'old_name' => $this->name] + )); + } + } + + /** + * Every AR needs a hidden method that returns the identifier of the AR as a string + */ + protected function aggregateId(): string + { + return $this->uuid->toString(); + } + + protected function apply(AggregateChanged $event): void + { + switch (get_class($event)) { + case UserWasCreated::class: + //Simply assign the event payload to the appropriate properties + $this->uuid = Uuid::fromString($event->aggregateId()); + $this->name = $event->username(); + break; + case UserWasRenamed::class: + $this->name = $event->newName(); + break; + } + } + } + + /** + * ProophEventSourcing domain events are of the type AggregateChanged + */ + class UserWasCreated extends AggregateChanged + { + public function username(): string + { + return $this->payload['name']; + } + } + + /** + * ProophEventSourcing domain events are of the type AggregateChanged + */ + class UserWasRenamed extends AggregateChanged + { + public function newName(): string + { + return $this->payload['new_name']; + } + + public function oldName(): string + { + return $this->payload['old_name']; + } + } + + /** + * Simple interface for a user repository + */ + interface UserRepository + { + public function save(User $user): void; + + public function get(Uuid $uuid): ?User; + } +} + +namespace My\Infrastructure { + use My\Model\User; + use My\Model\UserRepository; + use Prooph\EventSourcing\Aggregate\AggregateRepository; + use Prooph\EventSourcing\Aggregate\AggregateType; + use Prooph\EventSourcing\EventStoreIntegration\AggregateTranslator; + use Prooph\EventStore\EventStore; + use Ramsey\Uuid\Uuid; + + class UserRepositoryImpl extends AggregateRepository implements UserRepository + { + public function __construct(EventStore $eventStore) + { + //We inject a Prooph\EventSourcing\EventStoreIntegration\AggregateTranslator that can handle our AggregateRoots + parent::__construct( + $eventStore, + AggregateType::fromAggregateRootClass('My\Model\User'), + new AggregateTranslator(), + null, //We don't use a snapshot store in the example + null, //Also a custom stream name is not required + true //But we enable the "one-stream-per-aggregate" mode + ); + } + + public function save(User $user): void + { + $this->saveAggregateRoot($user); + } + + public function get(Uuid $uuid): ?User + { + return $this->getAggregateRoot($uuid->toString()); + } + } +} + +namespace { + //Set up an EventStore with an InMemoryAdapter (Only useful for testing, persistent implementations of ProophEventStore are available) + use My\Infrastructure\UserRepositoryImpl; + use My\Model\User; + use Prooph\Common\Event\ActionEvent; + use Prooph\Common\Event\ProophActionEventEmitter; + use Prooph\EventStore\InMemoryEventStore; + use Prooph\EventStore\TransactionalActionEventEmitterEventStore; + + $eventStore = new TransactionalActionEventEmitterEventStore( + new InMemoryEventStore(), + new ProophActionEventEmitter() + ); + + //Now we set up our user repository and inject the EventStore + //Normally this should be done in an IoC-Container and the receiver of the repository should require My\Model\UserRepository + $userRepository = new UserRepositoryImpl($eventStore); + + //Ok lets start a new transaction and create a user + $eventStore->beginTransaction(); + + $user = User::nameNew('John Doe'); + + //Before we save let's attach a listener to check that the UserWasCreated event is recorded + $eventStore->attach( + TransactionalActionEventEmitterEventStore::EVENT_CREATE, + function (ActionEvent $event): void { + foreach ($event->getParam('stream')->streamEvents() as $streamEvent) { + echo sprintf( + 'Event with name %s was recorded. It occurred on %s UTC /// ', + $streamEvent->messageName(), + $streamEvent->createdAt()->format('Y-m-d H:i:s') + ) . PHP_EOL; + } + }, + -1000 + ); + + $userRepository->save($user); + + //Let's make sure the transaction is written + $eventStore->attach( + TransactionalActionEventEmitterEventStore::EVENT_COMMIT, + function (ActionEvent $event): void { + echo 'Transaction commited' . PHP_EOL; + }, + -1000 + ); + + $eventStore->commit(); + + $userId = $user->userId(); + + unset($user); + + //Ok, great. Now let's see how we can grab the user from the repository and change the name + + //First we need to start a new transaction + $eventStore->beginTransaction(); + + //The repository automatically tracks changes of the user... + $loadedUser = $userRepository->get($userId); + + $loadedUser->changeName('Max Mustermann'); + + //Before we save let's attach a listener again on appendTo to check that the UserWasRenamed event is recorded + $eventStore->attach( + TransactionalActionEventEmitterEventStore::EVENT_APPEND_TO, + function (ActionEvent $event): void { + foreach ($event->getParam('streamEvents') as $streamEvent) { + echo sprintf( + 'Event with name %s was recorded. It occurred on %s UTC /// ', + $streamEvent->messageName(), + $streamEvent->createdAt()->format('Y-m-d H:i:s') + ) . PHP_EOL; + } + }, + -1000 + ); + + $userRepository->save($loadedUser); + + //... so we only need to commit the transaction and the UserWasRenamed event should be recorded + //(check output of the previously attached listener) + $eventStore->commit(); +} + +``` + +## Prooph Event Store Integration + +`prooph/event-sourcing` ships with a [prooph/event-store](https://github.com/prooph/event-store) AggregateTranslator to connect the store +with the bundled [AggregateRoot](https://github.com/prooph/event-sourcing/blob/master/src/Prooph/EventSourcing/AggregateRoot.php). diff --git a/docs/snapshots/bookdown.json b/docs/snapshots/bookdown.json new file mode 100644 index 0000000..30cc4fc --- /dev/null +++ b/docs/snapshots/bookdown.json @@ -0,0 +1,10 @@ +{ + "title": "Aggregate Snapshots", + "content": [ + {"intro": "introduction.md"}, + {"snapshotter": "https://raw.githubusercontent.com/prooph/snapshotter/master/docs/bookdown.json"}, + {"snapshot_store": "https://raw.githubusercontent.com/prooph/snapshot-store/master/docs/bookdown.json"} + ], + "tocDepth": 1, + "numbering": false +} diff --git a/docs/snapshots.md b/docs/snapshots/introduction.md similarity index 71% rename from docs/snapshots.md rename to docs/snapshots/introduction.md index 2da91e2..ca80615 100644 --- a/docs/snapshots.md +++ b/docs/snapshots/introduction.md @@ -1,4 +1,4 @@ -# Snapshots +# Introduction One of the counter-arguments against Event-Sourcing you might heard about is that replaying events takes too much time. @@ -11,12 +11,10 @@ in most cases. If aggregate reconstitution gets slow you can add an additional layer to the system which is capable of providing aggregate snapshots. -Choose one of the `Prooph\SnapshotStore\*` to take snapshots. +Choose one of the `Prooph\SnapshotStore\*` implementations and combine it with `prooph/snapshotter` to take snapshots. Inject the snapshot store into an aggregate repository and the repository will use the snapshot store to speed up aggregate loading. -Our example application [proophessor-do](https://github.com/prooph/proophessor-do) contains a snapshotting tutorial. - *Note: All SnapshotStores ship with interop factories to ease set up.* -For more informations about snapshots and how to configure them, see [Prooph Snapshotter](https://github.com/prooph/snapshotter). +More information about snapshots and how to configure them can be found on the next pages.