Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restructure docs #69

Merged
merged 1 commit into from
Oct 15, 2017
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
Retructure docs
  • Loading branch information
codeliner committed Oct 15, 2017
commit 94c4ed7e896ae656755b9759b0c85c8d0d5ada43
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
.php_cs.cache
nbproject
composer.lock
docs/html
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
6 changes: 4 additions & 2 deletions docs/bookdown.json
Original file line number Diff line number Diff line change
@@ -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"
}
271 changes: 271 additions & 0 deletions docs/introduction.md
Original file line number Diff line number Diff line change
@@ -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
<?php

declare(strict_types=1);

namespace {
require_once __DIR__ . '/../vendor/autoload.php';
}

namespace My\Model {
use Assert\Assertion;
use Prooph\EventSourcing\AggregateChanged;
use Prooph\EventSourcing\AggregateRoot;
use Ramsey\Uuid\Uuid;

class User extends AggregateRoot
{
/**
* @var Uuid
*/
private $uuid;

/**
* @var string
*/
private $name;

/**
* ARs should be created via static factory methods
*/
public static function nameNew(string $username): User
{
//Perform assertions before raising a event
Assertion::notEmpty($username);

$uuid = Uuid::uuid4();

//AggregateRoot::__construct is defined as protected so it can be called in a static factory of
//an extending class
$instance = new self();

//Use AggregateRoot::recordThat method to apply a new Event
$instance->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).
10 changes: 10 additions & 0 deletions docs/snapshots/bookdown.json
Original file line number Diff line number Diff line change
@@ -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
}
8 changes: 3 additions & 5 deletions docs/snapshots.md → docs/snapshots/introduction.md
Original file line number Diff line number Diff line change
@@ -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.

Expand All @@ -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.