Skip to content
This repository has been archived by the owner on Sep 20, 2019. It is now read-only.

Commit

Permalink
Merge 812f157 into cf14dc5
Browse files Browse the repository at this point in the history
  • Loading branch information
Rias committed Aug 27, 2019
2 parents cf14dc5 + 812f157 commit 69d6827
Show file tree
Hide file tree
Showing 24 changed files with 318 additions and 189 deletions.
13 changes: 7 additions & 6 deletions composer.json
Expand Up @@ -22,19 +22,20 @@
],
"require": {
"php": "^7.3",
"illuminate/console": "5.8.*",
"illuminate/database": "5.8.*",
"illuminate/events": "5.8.*",
"illuminate/support": "5.8.*",
"illuminate/console": "6.*",
"illuminate/database": "6.*",
"illuminate/events": "6.*",
"illuminate/support": "6.*",
"league/flysystem": "^1.0.45",
"spatie/laravel-schemaless-attributes": "^1.4",
"symfony/finder": "^4.2",
"symfony/property-access": "^4.0",
"symfony/serializer": "^4.0"
},
"minimum-stability": "dev",
"prefer-stable": true,
"require-dev": {
"mockery/mockery": "^1.1",
"orchestra/testbench": "3.8.*",
"orchestra/testbench": "^4.0",
"phpunit/phpunit": "^8.0",
"spatie/phpunit-snapshot-assertions": "^2.1"
},
Expand Down
4 changes: 2 additions & 2 deletions config/event-projector.php
Expand Up @@ -44,9 +44,9 @@
/*
* This class is responsible for storing events. To add extra behaviour you
* can change this to a class of your own. The only restriction is that
* it should extend \Spatie\EventProjector\Models\StoredEvent.
* it should implement \Spatie\EventProjector\StoredEventRepository.
*/
'stored_event_model' => \Spatie\EventProjector\Models\StoredEvent::class,
'stored_event_repository' => \Spatie\EventProjector\EloquentStoredEventRepository::class,

/*
* This class is responsible for handling stored events. To add extra behaviour you
Expand Down
14 changes: 9 additions & 5 deletions src/AggregateRoot.php
Expand Up @@ -34,18 +34,22 @@ public function recordThat(ShouldBeStored $domainEvent): AggregateRoot

public function persist(): AggregateRoot
{
call_user_func(
[$this->getStoredEventModel(), 'storeMany'],
$storedEvents = call_user_func(
[$this->getStoredEventRepository(), 'persistMany'],
$this->getAndClearRecordedEvents(),
$this->aggregateUuid
);

$storedEvents->each(function (StoredEvent $storedEvent) {
$storedEvent->handle();
});

return $this;
}

protected function getStoredEventModel(): string
protected function getStoredEventRepository(): StoredEventRepository
{
return $this->storedEventModel ?? config('event-projector.stored_event_model');
return app($this->storedEventRepository ?? config('event-projector.stored_event_repository'));
}

public function getRecordedEvents(): array
Expand All @@ -64,7 +68,7 @@ private function getAndClearRecordedEvents(): array

private function reconstituteFromEvents(): AggregateRoot
{
$this->getStoredEventModel()::uuid($this->aggregateUuid)
$this->getStoredEventRepository()->retrieveAll($this->aggregateUuid)
->each(function (StoredEvent $storedEvent) {
$this->apply($storedEvent->event);
});
Expand Down
27 changes: 5 additions & 22 deletions src/Console/ReplayCommand.php
Expand Up @@ -3,11 +3,10 @@
namespace Spatie\EventProjector\Console;

use Exception;
use InvalidArgumentException;
use Illuminate\Console\Command;
use Illuminate\Support\Collection;
use Spatie\EventProjector\Projectionist;
use Spatie\EventProjector\Models\StoredEvent;
use Spatie\EventProjector\StoredEventRepository;

class ReplayCommand extends Command
{
Expand All @@ -20,9 +19,6 @@ class ReplayCommand extends Command
/** @var \Spatie\EventProjector\Projectionist */
protected $projectionist;

/** @var string */
protected $storedEventModelClass;

public function __construct(Projectionist $projectionist)
{
parent::__construct();
Expand All @@ -32,8 +28,6 @@ public function __construct(Projectionist $projectionist)

public function handle(): void
{
$this->storedEventModelClass = $this->getStoredEventClass();

$projectors = $this->selectProjectors($this->argument('projector'));

if (is_null($projectors)) {
Expand Down Expand Up @@ -70,7 +64,9 @@ public function selectProjectors(array $projectorClassNames): ?Collection

public function replay(Collection $projectors, int $startingFrom): void
{
$replayCount = $this->getStoredEventClass()::startingFrom($startingFrom)->count();
$repository = app(StoredEventRepository::class);
$events = $repository->retrieveAllStartingFrom($startingFrom);
$replayCount = $events->count();

if ($replayCount === 0) {
$this->warn('There are no events to replay');
Expand All @@ -80,7 +76,7 @@ public function replay(Collection $projectors, int $startingFrom): void

$this->comment("Replaying {$replayCount} events...");

$bar = $this->output->createProgressBar($this->getStoredEventClass()::count());
$bar = $this->output->createProgressBar($events->count());
$onEventReplayed = function () use ($bar) {
$bar->advance();
};
Expand All @@ -99,17 +95,4 @@ private function emptyLine(int $amount = 1): void
$this->line('');
}
}

private function getStoredEventClass(): string
{
if ($storedEventModel = $this->option('stored-event-model')) {
if (! is_subclass_of($storedEventModel, StoredEvent::class)) {
throw new InvalidArgumentException(
"Stored event model class `$storedEventModel` does not implement `".StoredEvent::class.'`'
);
}
}

return $storedEventModel ?? config('event-projector.stored_event_model');
}
}
92 changes: 92 additions & 0 deletions src/EloquentStoredEventRepository.php
@@ -0,0 +1,92 @@
<?php

namespace Spatie\EventProjector;

use Carbon\Carbon;
use Illuminate\Support\LazyCollection;
use Spatie\EventProjector\Models\StoredEvent;
use Spatie\EventProjector\Models\EloquentStoredEvent;
use Spatie\EventProjector\EventSerializers\EventSerializer;

class EloquentStoredEventRepository implements StoredEventRepository
{
protected $storedEventModel = EloquentStoredEvent::class;

public function retrieveAll(string $uuid = null): LazyCollection
{
/** @var \Illuminate\Database\Query\Builder $query */
$query = $this->storedEventModel::query();

if ($uuid) {
$query->uuid($uuid);
}

return $query->cursor()->map(function (EloquentStoredEvent $storedEvent) {
return $storedEvent->toStoredEvent();
});
}

public function retrieveAllStartingFrom(int $startingFrom, string $uuid = null): LazyCollection
{
/** @var \Illuminate\Database\Query\Builder $query */
$query = $this->storedEventModel::query()->startingFrom($startingFrom);

if ($uuid) {
$query->uuid($uuid);
}

return $query->cursor()->map(function (EloquentStoredEvent $storedEvent) {
return $storedEvent->toStoredEvent();
});
}

public function persist(ShouldBeStored $event, string $uuid = null): StoredEvent
{
/** @var EloquentStoredEvent $eloquentStoredEvent */
$eloquentStoredEvent = new $this->storedEventModel();

$eloquentStoredEvent->setRawAttributes([
'event_properties' => app(EventSerializer::class)->serialize(clone $event),
'aggregate_uuid' => $uuid,
'event_class' => self::getEventClass(get_class($event)),
'meta_data' => json_encode([]),
'created_at' => Carbon::now(),
]);

$eloquentStoredEvent->save();

return $eloquentStoredEvent->toStoredEvent();
}

public function persistMany(array $events, string $uuid = null): LazyCollection
{
$storedEvents = [];

foreach ($events as $event) {
$storedEvents[] = self::persist($event, $uuid);
}

return new LazyCollection($storedEvents);
}

public function update(StoredEvent $storedEvent): StoredEvent
{
/** @var EloquentStoredEvent $eloquentStoredEvent */
$eloquentStoredEvent = $this->storedEventModel::find($storedEvent->id);

$eloquentStoredEvent->update($storedEvent->toArray());

return $eloquentStoredEvent->toStoredEvent();
}

private function getEventClass(string $class): string
{
$map = config('event-projector.event_class_map', []);

if (! empty($map) && in_array($class, $map)) {
return array_search($class, $map, true);
}

return $class;
}
}
6 changes: 4 additions & 2 deletions src/EventProjectorServiceProvider.php
Expand Up @@ -53,14 +53,16 @@ public function register(): void

$this->app->alias(Projectionist::class, 'event-projector');

$this->app->singleton(StoredEventRepository::class, config('event-projector.stored_event_repository'));

$this->app->singleton(EventSubscriber::class, function () {
return new EventSubscriber(config('event-projector.stored_event_model'));
return new EventSubscriber(config('event-projector.stored_event_repository'));
});

$this->app
->when(ReplayCommand::class)
->needs('$storedEventModelClass')
->give(config('event-projector.stored_event_model'));
->give(config('event-projector.stored_event_repository'));

$this->app->bind(EventSerializer::class, config('event-projector.event_serializer'));

Expand Down
11 changes: 6 additions & 5 deletions src/EventSubscriber.php
Expand Up @@ -4,12 +4,12 @@

final class EventSubscriber
{
/** @var string */
private $storedEventModel;
/** @var \Spatie\EventProjector\StoredEventRepository */
private $repository;

public function __construct(string $storedEventModel)
public function __construct(string $storedEventRepository)
{
$this->storedEventModel = $storedEventModel;
$this->repository = app($storedEventRepository);
}

public function subscribe($events): void
Expand All @@ -28,7 +28,8 @@ public function handle(string $eventName, $payload): void

public function storeEvent(ShouldBeStored $event): void
{
$this->storedEventModel::store($event);
$storedEvent = $this->repository->persist($event);
$storedEvent->handle();
}

private function shouldBeStored($event): bool
Expand Down
2 changes: 1 addition & 1 deletion src/Events/EventHandlerFailedHandlingEvent.php
Expand Up @@ -11,7 +11,7 @@ final class EventHandlerFailedHandlingEvent
/** @var \Spatie\EventProjector\EventHandlers\EventHandler */
public $eventHandler;

/** @var \Spatie\EventProjector\Models\StoredEvent */
/** @var \Spatie\EventProjector\Models\EloquentStoredEvent */
public $storedEvent;

/** @var \Exception */
Expand Down
2 changes: 1 addition & 1 deletion src/HandleStoredEventJob.php
Expand Up @@ -12,7 +12,7 @@ final class HandleStoredEventJob implements ShouldQueue
{
use InteractsWithQueue, Queueable, SerializesModels;

/** @var \Spatie\EventProjector\Models\StoredEvent */
/** @var \Spatie\EventProjector\Models\EloquentStoredEvent */
public $storedEvent;

/** @var array */
Expand Down
48 changes: 48 additions & 0 deletions src/Models/EloquentStoredEvent.php
@@ -0,0 +1,48 @@
<?php

namespace Spatie\EventProjector\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Spatie\EventProjector\ShouldBeStored;

class EloquentStoredEvent extends Model
{
public $guarded = [];

public $timestamps = false;

protected $table = 'stored_events';

public $casts = [
'event_properties' => 'array',
'meta_data' => 'array',
];

public function toStoredEvent(): StoredEvent
{
return new StoredEvent([
'id' => $this->id,
'event_properties' => $this->event_properties,
'aggregate_uuid' => $this->aggregate_uuid,
'event_class' => $this->event_class,
'meta_data' => $this->meta_data,
'created_at' => $this->created_at,
]);
}

public function getEventAttribute(): ShouldBeStored
{
return $this->toStoredEvent()->event;
}

public function scopeStartingFrom(Builder $query, int $storedEventId): void
{
$query->where('id', '>=', $storedEventId);
}

public function scopeUuid(Builder $query, string $uuid): void
{
$query->where('aggregate_uuid', $uuid);
}
}

0 comments on commit 69d6827

Please sign in to comment.