The easiest way to get started with event sourcing in Laravel

Overview

Event sourcing for Artisans 📽

Latest Version on Packagist Tests Total Downloads

This package aims to be the entry point to get started with event sourcing in Laravel. It can help you with setting up aggregates, projectors, and reactors.

If you've never worked with event sourcing, or are uncertain about what aggregates, projectors and reactors are head over to the getting familiar with event sourcing section in our docs.

Event sourcing might be a good choice for your project if:

  • your app needs to make decisions based on the past
  • your app has auditing requirements: the reason why your app is in a certain state is equally as important as the state itself
  • you foresee that there will be a reporting need in the future, but you don't know yet which data you need to collect for those reports

If you want to skip to reading code immediately, here are some example apps. In each of them, you can create accounts and deposit or withdraw money.

Event sourcing in Laravel course

If you want to learn more about event sourcing, check out our course on event sourcing in Laravel

Support us

We invest a lot of resources into creating best in class open source packages. You can support us by buying one of our paid products.

We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on our contact page. We publish all received postcards on our virtual postcard wall.

Documentation

You can find installation instructions and detailed instructions on how to use this package at the dedicated documentation site.

Upgrading from laravel-event-projector

This package supercedes laravel-event-projector. It has the same API. Upgrading from laravel-event-projector to laravel-event-sourcing is easy. Take a look at our upgrade guide.

Changelog

Please see CHANGELOG for more information what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security

If you've found a bug regarding security please mail [email protected] instead of using the issue tracker.

Postcardware

You're free to use this package, but if it makes it to your production environment we highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using.

Our address is: Spatie, Kruikstraat 22, 2018 Antwerp, Belgium.

We publish all received postcards on our company website.

Credits

The aggregate root functionality is heavily inspired by Frank De Jonge's excellent EventSauce package. A big thank you to Dries Vints for giving lots of valuable feedback while we were developing the package.

Footnotes

1 Quote taken from Event Sourcing made Simple

License

The MIT License (MIT). Please see License File for more information.

Comments
  • Duplicate uuid/version events prevent further updates

    Duplicate uuid/version events prevent further updates

    First I want to thank you guys for your awesome packages and the hard work you put into them. :heart:

    I was trying out this package in local development (Nginx + PHP-FPM, MySQL). After some time this system goes dormant and the next request takes some time to be processed. In this state I (accidentally) made 2 concurrent requests to update the same aggregate. The corresponding controller function:

        public function update(UserUpdateRequest $request, User $user)
        {
            UserAggregateRoot::retrieve($user->id)
                ->updateUser($request->validated() + ['id' => $user->id])
                ->persist();
    
            return UserResource::make($user->refresh());
        }
    

    This resulted in a duplicate entry in the database, see:

    image

    Note: The UserAggregateRoot does NOT have protected static bool $allowConcurrency = true;

    Now every update request to that specific aggregate (user) results in the following error:

    [2020-11-19 17:39:58] local.ERROR: Could not persist aggregate UserAggregateRoot (uuid: 8be7ace5-8c98-3823-b858-11cdff2974e7) because it seems to be changed by another process after it was retrieved in the current process. Expect to persist events after version 2, but version 1 was already persisted. {"userId":"9e33aa4f-6efa-3505-ab49-9d667e5b2c39","exception":"[object] (Spatie\\EventSourcing\\Exceptions\\CouldNotPersistAggregate(code: 0): Could not persist aggregate UserAggregateRoot (uuid: 8be7ace5-8c98-3823-b858-11cdff2974e7) because it seems to be changed by another process after it was retrieved in the current process. Expect to persist events after version 2, but version 1 was already persisted. at base/vendor/spatie/laravel-event-sourcing/src/Exceptions/CouldNotPersistAggregate.php:18)
    [stacktrace]
    #0 base/vendor/spatie/laravel-event-sourcing/src/AggregateRoots/AggregateRoot.php(189): Spatie\\EventSourcing\\Exceptions\\CouldNotPersistAggregate::unexpectedVersionAlreadyPersisted()
    #1 base/vendor/spatie/laravel-event-sourcing/src/AggregateRoots/AggregateRoot.php(90): Spatie\\EventSourcing\\AggregateRoots\\AggregateRoot->ensureNoOtherEventsHaveBeenPersisted()
    #2 base/vendor/spatie/laravel-event-sourcing/src/AggregateRoots/AggregateRoot.php(79): Spatie\\EventSourcing\\AggregateRoots\\AggregateRoot->persistWithoutApplyingToEventHandlers()
    #3 base/Modules/User/Http/Controllers/UserController.php(91): Spatie\\EventSourcing\\AggregateRoots\\AggregateRoot->persist()
    
    1. Should this be handled by the package automatically (is this a bug) or should this be prevented in another part of the system?
    2. Should I enforce unique constraints in the database on [aggregate_uuid, aggregate_version]? If so, should this be highlighted in the docs?
    3. FYI: adding allowConcurrency afterwards to the root allows for updating and inserts a new event with version 3.

    Best regards, Marcel

    opened by UncertaintyP 27
  • Laravel 9.x Compatibility

    Laravel 9.x Compatibility

    The league/flyststem requirement had to be widened to include ^2.0 as well. However, I noticed that we're not using any code from that package explicitly anyway, so I removed it.

    EDIT:

    I accidentally based this PR on an older version of the package. I see that it's blocked by https://github.com/spatie/better-types now, as it requires illuminate/collections:^8.58, but I've also opened a PR to address this issue https://github.com/spatie/better-types/pull/2.

    opened by erikgaal 11
  • Add backwards compatibility for eventId

    Add backwards compatibility for eventId

    This PR introduces backwards compatibility for events that don't have the eventId in their metadata.

    Imho eventId shouldn't be in the metadata in the first place. This would also prevent saving, and immediately updating in the EloquentStoredEventRepository. Curious what the thoughts behind this are?

    opened by Robertbaelde 9
  • SchemalessAttributes needed?

    SchemalessAttributes needed?

    Hi! Love the package!

    I'm building custom repositories to store and load events from https://eventstore.com/ so I'm not using Eloquent at all.

    I liked the use of StoredEvent, except for the SchemalessAttributes requirement. This type then enforces all of Eloquent to be brought in.

    https://github.com/spatie/laravel-event-sourcing/blob/ea48283a7a0db3a5c090de799df8cf01f5918f69/src/StoredEvent.php#L24

    At the moment I'm using a workaround, but it's not pretty!

            use Illuminate\Database\Eloquent\Model;
            $emptyModel = new class extends Model { };
            $model = new $emptyModel();
            $model->meta_data = $metadata;
    
            return new StoredEvent([
                ...
                'meta_data' => new SchemalessAttributes($model, 'meta_data'),
                ...
            ]);
    
    help wanted revisit-for-next-major-version 
    opened by morrislaptop 9
  • AggregateRoot Method is called if Argument has no type-hint

    AggregateRoot Method is called if Argument has no type-hint

    PHP Version: 8.1.5 Laravel Version: 9.11.0 spatie/laravel-event-sourcing Version: 7.2.0

    Hi there,

    Today I came across the Situation where Method two was getting called when using the AggregateRoot with Method one inside the Application. I wondered why this was happening cause I had never used the AggregateRoot with Method two anywhere yet. After some experimenting and debugging, I found out that this only happens if the Argument in Method two is not type-hinted.

    Here are some examples for a better understanding:

    Scenario 1 (two is called):

    <?php
    
    class SomethingAggregateRoot extends AggregateRoot
    {
        public function one(string $foo): self
        {
            ...
            $this->recordThat(new SampleEvent());
            ...
            return $this;
        }
    
        public function two($without_typehint): self
        {
            ...
            $this->recordThat(...);
            ...
            return $this;
        }
    }
    
    SomethingAggregateRoot::retrieve($uuid)
        ->one('laravel')
        ->persist();
    // Result: two was called
    

    Scenario 2 (two is not called):

    <?php
    
    class SomethingAggregateRoot extends AggregateRoot
    {
        public function one(string $foo): self
        {
            ...
            $this->recordThat(new SampleEvent());
            ...
            return $this;
        }
    
        public function two(boolean $with_typehint): self
        {
            ...
            $this->recordThat(...);
            ...
            return $this;
        }
    }
    
    SomethingAggregateRoot::retrieve($uuid)
        ->one('laravel')
        ->persist();
    // Result: two was not called
    

    Is this an expected behaviour or a bug/defect?

    Thanks for checking and clarifying, Fabian

    opened by fabianpnke 8
  • Could not persist aggregate because it seems to be changed by another process after it was retrieved in the current process. Current in-memory version is 1

    Could not persist aggregate because it seems to be changed by another process after it was retrieved in the current process. Current in-memory version is 1

    My first time using v7 of the package, and had some issues with aggregates last night.

    Could not persist aggregate PostAggregate (uuid: 19dad81e-b6ab-4012-a04a-401e1d35747d) because it seems to be changed by another process after it was retrieved in the current process. Current in-memory version is 1
    

    Using Laravel 9.2.0 PHP 8.1

    Aggregate:

    class PostAggregate extends AggregateRoot
    {
        protected static bool $allowConcurrency = false;
    
        public function createPost(DataObjectContract $object): self
        {
            $this->recordThat(
                domainEvent: new PostWasCreated(
                    object: $object,
                ),
            );
    
            return $this;
        }
    
        public function getStoredEventRepository(): StoredEventRepository
        {
            return app(PostStoredEventsRepository::class);
        }
    }
    

    Event:

    class PostWasCreated extends ShouldBeStored
    {
        public function __construct(
            public readonly DataObjectContract $object,
        ) {}
    }
    

    Service Provider:

    class EventSourcingServiceProvider extends ServiceProvider
    {
        /**
         * @return void
         */
        public function register(): void
        {
            Projectionist::addProjector(
                projector: PostHandler::class,
            );
    
            Projectionist::addReactor(
                EmailModerators::class,
            );
        }
    }
    

    Projector:

    class PostHandler extends Projector
    {
        public function onPostWasCreated(PostWasCreated $event): void
        {
            /**
             * @var CreatePostContract
             */
            $action = resolve(CreatePostContract::class);
    
            $action->handle($event->object);
        }
    }
    

    The event is persisted in the database during testing with no errors, but when I interact with my code from the web UI - I get this issue. The aggregate is being triggered by a Livewire component that uses a service class to trigger the aggregate:

    Livewire Component:

    class CreateForm extends Component implements HasForms
    {
        use InteractsWithForms;
    
        public bool $moderation = false;
        public null|string $title = null;
        public null|string $description = null;
        public null|string $content = null;
        public null|int $category = null;
    
        public function mount(): void
        {
            $this->form->fill();
        }
    
        public function submit(
            PostFactoryContract $factory,
            PostAggregateServiceContract $service,
        ) {
            $service->createPost(
                $factory->make(
                    attributes: array_merge(
                        $this->form->getState(),
                        ['user_id' => auth()->id()],
                    )
                )
            );
    
            return redirect()->route('dashboard');
        }
    
        protected function getFormSchema(): array
        {
            return [
                Grid::make(4)->schema([
                    TextInput::make('title')->label('Post Title')->columnSpan(2)->required(),
                    Select::make('category')->label('Post Category')->options(Category::get()->pluck('title', 'id'))->columnSpan(2)->required(),
                    TextInput::make('description')->label('Post Description')->columnSpan(4)->required()->maxLength(120),
                    MarkdownEditor::make('content')->label('Post Content')->columnSpan(4)->required(),
                        Toggle::make('moderation')->label('Submit for moderation')->columnSpan(4),
                    ]),
            ];
        }
    
        public function render(): View
        {
            return view('livewire.posts.create-form');
        }
    }
    

    Service class:

    class PostAggregateService implements PostAggregateServiceContract
    {
        public function createPost(DataObjectContract $object): void
        {
            PostAggregate::retrieve(
                uuid: Str::uuid()->toString(),
            )->createPost(
                object: $object,
            )->persist();
        }
    }
    

    As you can see the service class tries to persist the aggregate, and this is where it fails. In my test code all I am doing is making sure that the event is stored:

    it('triggers the aggregate root to store the event that a post was created', function () {
        $category = Category::factory()->create();
        auth()->loginUsingId(User::factory()->create()->id);
    
        expect(PostStoredEvent::query()->count())->toEqual(0);
    
        Livewire::test(CreateForm::class)
            ->set([
                  'title' => 'pest php',
                  'category' => $category->id,
                  'description' => 'pest PHP is awesome, prove me wrong',
                  'content' => 'Here be content, pirates and dragons',
              ])->call('submit')->assertHasNoErrors();
    
        expect(
            PostStoredEvent::query()->count()
        )->toEqual(1);
    })->group('publishing');
    
    opened by JustSteveKing 7
  • Remove re-resolving of handler

    Remove re-resolving of handler

    As per this comment, in V5 the issue that caused the need for re-resolving was fixed. This PR removes that temporary fix in favor of Projectionist::fake() calls.

    @brendt I can imagine this is a breaking change for a small percentage of users, so would require a new major release. I don't think there is a branch for v6 already?

    https://github.com/spatie/laravel-event-sourcing/discussions/181

    opened by Robertbaelde 7
  • Allow custom path as a base path

    Allow custom path as a base path

    When applying the custom directory structure as suggested by the "Laravel Beyond Crud" book, the event discovery fails as it uses the base path to guess the class names from the file names.

    https://github.com/spatie/laravel-event-sourcing/blob/05d0aa072ac6385aebda0d84519a8aa389fe2813/src/Support/DiscoverEventHandlers.php#L72-L83

    So a Projector placed at ./src/App/Projectors/UsersProjector.php is guessed as this class Src\App\Projectors\UsersProjector, which does not exist.

    By allowing a user to specify a custom config key one could add this config key:

    'auto_discover_base_path' => base_path('src'),
    

    And have the src part ignored.

    As it is seems to be an edge case, I didn't add a config key on the config stub.

    If you prefer me to do so, please let know and I will update the PR.

    More reasoning here: https://github.com/spatie/laravel-beyond-crud-demo/issues/7#issuecomment-792965120 (private repo)

    EDIT I pushed more commits to allow for a more descriptive config key

    opened by rodrigopedra 7
  • Allow retrieving an aggregate at a specific version

    Allow retrieving an aggregate at a specific version

    I ran into a situation where I needed to retrieve an aggregate for a specific state in the past. This PR adds an optional 2nd argument to the Aggregate Root, so it's possible to get a previous state of an aggregate, instead of just the latest.

    A concrete use-case is when trying to compare a previous state to the latest state, exactly like this PR 🥁

    I also believe this is another solid use case to use aggregates, in addition to the other benefit of making decisions based on past events.

    Here's how it would work with this PR in place:

    $account = AccountAggregate::retrieve($uuid, 3);
    return $account->balance;
    

    Since this is an optional argument, there should be no breaking changes. I also added the argument to AggregateRoot::loadUuid, for consistency.

    Let me know what you think and if the PR needs any tweaks.

    Co-Author: @lukecurtis93 Credit: Quality checked against https://github.com/spatie/simple-excel/pull/43 due to https://twitter.com/freekmurze/status/1337047675611582464

    opened by morrislaptop 7
  • Release of version 1.1.0 is actually version 2

    Release of version 1.1.0 is actually version 2

    Hi,

    according to the changelog, 1.1.0 is supposed to contain the change countAllStartingFrom. But after updating with composer to 1.1.0 the package now requires PHP 7.4 (the major change of v2). It also doesn't contain the changes related to countAllStartingFrom.

    It looks like the tag has been related to a wrong commit, it points to a merge commit on the master branch.

    I'm not sure, what the best way would be to solve this. It's just that at the moment 1.1.0 doesn't contain the desired feature, and depends on PHP 7.4 ...

    opened by m-bymike 7
  • Change event_version column type from int to unsigned tinyint

    Change event_version column type from int to unsigned tinyint

    Changed the event_version column type from int to unsigned tinyint in the stored_events table migration stub.

    The event version shouldn't be negative, therefore, the new column type would be more semantically correct for the use-case of this feature

    opened by rapkis 6
  • Aggregate Partial is ignored when creating a snapshot

    Aggregate Partial is ignored when creating a snapshot

    I'm playing around with this package and noticed, that when following the documentation for aggregate partials and creating a snapshot of the aggregate root, the state of the partial is not stored in the snapshot. Not sure if that is intended or a bug, as I didn't find a test for this usecase and the documentation didn't mentions snapshots and aggregate partials.

    bug help wanted 
    opened by nlx-sascha 3
Releases(7.3.2)
  • 7.3.2(Jan 3, 2023)

    What's Changed

    • Fixes bug with retrieving last event by @aidan-casey in https://github.com/spatie/laravel-event-sourcing/pull/384

    Full Changelog: https://github.com/spatie/laravel-event-sourcing/compare/7.3.1...7.3.2

    Source code(tar.gz)
    Source code(zip)
  • 7.3.1(Dec 22, 2022)

    What's Changed

    • Refactor tests to pest by @AyoobMH in https://github.com/spatie/laravel-event-sourcing/pull/377
    • Add PHP 8.2 Support by @patinthehat in https://github.com/spatie/laravel-event-sourcing/pull/379
    • update document by @godkinmo in https://github.com/spatie/laravel-event-sourcing/pull/380
    • Use the snapshot with the highest ID by @27pchrisl in https://github.com/spatie/laravel-event-sourcing/pull/381

    New Contributors

    • @AyoobMH made their first contribution in https://github.com/spatie/laravel-event-sourcing/pull/377
    • @patinthehat made their first contribution in https://github.com/spatie/laravel-event-sourcing/pull/379
    • @godkinmo made their first contribution in https://github.com/spatie/laravel-event-sourcing/pull/380
    • @27pchrisl made their first contribution in https://github.com/spatie/laravel-event-sourcing/pull/381

    Full Changelog: https://github.com/spatie/laravel-event-sourcing/compare/7.3.0...7.3.1

    Source code(tar.gz)
    Source code(zip)
  • 7.3.0(Sep 12, 2022)

    What's Changed

    • Support weight property to event handlers by @sebastiandedeyne in https://github.com/spatie/laravel-event-sourcing/pull/365

    Full Changelog: https://github.com/spatie/laravel-event-sourcing/compare/7.2.4...7.3.0

    Source code(tar.gz)
    Source code(zip)
  • 7.2.4(Aug 22, 2022)

    What's Changed

    • Update Reactor docs on how to get the aggregate uuid by @soarecostin in https://github.com/spatie/laravel-event-sourcing/pull/363
    • Update event-sourcing:replay command to work with just one aggregate uuid by @soarecostin in https://github.com/spatie/laravel-event-sourcing/pull/362

    New Contributors

    • @soarecostin made their first contribution in https://github.com/spatie/laravel-event-sourcing/pull/363

    Full Changelog: https://github.com/spatie/laravel-event-sourcing/compare/7.2.3...7.2.4

    Source code(tar.gz)
    Source code(zip)
  • 7.2.3(Jul 29, 2022)

    What's Changed

    • Fix typo in ReadMe by @michael-rubel in https://github.com/spatie/laravel-event-sourcing/pull/353
    • Update AggregateRoot::apply() to utilize acceptsTypes() function by @zackrowe in https://github.com/spatie/laravel-event-sourcing/pull/354

    New Contributors

    • @michael-rubel made their first contribution in https://github.com/spatie/laravel-event-sourcing/pull/353
    • @zackrowe made their first contribution in https://github.com/spatie/laravel-event-sourcing/pull/354

    Full Changelog: https://github.com/spatie/laravel-event-sourcing/compare/7.2.2...7.2.3

    Source code(tar.gz)
    Source code(zip)
  • 7.2.2(Jul 14, 2022)

    What's Changed

    • Fix method annotations in Projection class by @daniser in https://github.com/spatie/laravel-event-sourcing/pull/350
    • Exclude tap from possible handlers by @erikgaal in https://github.com/spatie/laravel-event-sourcing/pull/352

    New Contributors

    • @daniser made their first contribution in https://github.com/spatie/laravel-event-sourcing/pull/350

    Full Changelog: https://github.com/spatie/laravel-event-sourcing/compare/7.2.1...7.2.2

    Source code(tar.gz)
    Source code(zip)
  • 7.2.1(May 27, 2022)

    What's Changed

    • Fix URL to documentation about caching by @rodrigopedra in https://github.com/spatie/laravel-event-sourcing/pull/328
    • Update cache_path in config by @lloricode in https://github.com/spatie/laravel-event-sourcing/pull/329
    • Update Projector docs to reflect changes to getting the aggregate uuid by @RobHarveyDev in https://github.com/spatie/laravel-event-sourcing/pull/331
    • Docs: createdAt() method is camel case by @inmanturbo in https://github.com/spatie/laravel-event-sourcing/pull/332
    • Update migration file to closure by @lloricode in https://github.com/spatie/laravel-event-sourcing/pull/330
    • Fix link to "getting familiar section" by @felixfrey in https://github.com/spatie/laravel-event-sourcing/pull/343
    • Do not assert events given to FakeAggregateRoot as recorded by @itsmarsu in https://github.com/spatie/laravel-event-sourcing/pull/344

    New Contributors

    • @lloricode made their first contribution in https://github.com/spatie/laravel-event-sourcing/pull/329
    • @RobHarveyDev made their first contribution in https://github.com/spatie/laravel-event-sourcing/pull/331
    • @inmanturbo made their first contribution in https://github.com/spatie/laravel-event-sourcing/pull/332
    • @felixfrey made their first contribution in https://github.com/spatie/laravel-event-sourcing/pull/343
    • @itsmarsu made their first contribution in https://github.com/spatie/laravel-event-sourcing/pull/344

    Full Changelog: https://github.com/spatie/laravel-event-sourcing/compare/7.2.0...7.2.1

    Source code(tar.gz)
    Source code(zip)
  • 7.2.0(Mar 4, 2022)

    What's Changed

    • Adds query helpers for event properties by @aidan-casey in https://github.com/spatie/laravel-event-sourcing/pull/326
    • Adds last event helper by @aidan-casey in https://github.com/spatie/laravel-event-sourcing/pull/327

    Full Changelog: https://github.com/spatie/laravel-event-sourcing/compare/7.0.1...7.2.0

    Source code(tar.gz)
    Source code(zip)
  • 7.0.1(Mar 3, 2022)

    What's Changed

    • Update testing-aggregates.md by @rmcdaniel in https://github.com/spatie/laravel-event-sourcing/pull/314
    • Updated the requirement to Laravel 9 by @davidlapham in https://github.com/spatie/laravel-event-sourcing/pull/318
    • Resolves issue with meta data updating on original event. by @aidan-casey in https://github.com/spatie/laravel-event-sourcing/pull/324

    New Contributors

    • @rmcdaniel made their first contribution in https://github.com/spatie/laravel-event-sourcing/pull/314
    • @davidlapham made their first contribution in https://github.com/spatie/laravel-event-sourcing/pull/318
    • @aidan-casey made their first contribution in https://github.com/spatie/laravel-event-sourcing/pull/324

    Full Changelog: https://github.com/spatie/laravel-event-sourcing/compare/7.0.0...7.0.1

    Source code(tar.gz)
    Source code(zip)
  • 7.0.0(Jan 20, 2022)

    What's Changed

    • Laravel 9.x Compatibility by @erikgaal in https://github.com/spatie/laravel-event-sourcing/pull/310

    Full Changelog: https://github.com/spatie/laravel-event-sourcing/compare/6.0.5...7.0.0

    Source code(tar.gz)
    Source code(zip)
  • 6.0.5(Jan 17, 2022)

    What's Changed

    • Add v4 to v5 upgrade overview to UPGRADING.md by @inxilpro in https://github.com/spatie/laravel-event-sourcing/pull/297
    • Typo fix in documentation - subtracting is also a transaction by @ndeblauw in https://github.com/spatie/laravel-event-sourcing/pull/303
    • Repaired URLs to current documentation version. by @Mul-tiMedia in https://github.com/spatie/laravel-event-sourcing/pull/304
    • Add line break to increase readability by @craigpotter in https://github.com/spatie/laravel-event-sourcing/pull/305
    • Change event_version column type from int to unsigned tinyint by @rapkis in https://github.com/spatie/laravel-event-sourcing/pull/306

    Full Changelog: https://github.com/spatie/laravel-event-sourcing/compare/6.0.4...6.0.5

    Source code(tar.gz)
    Source code(zip)
  • 6.0.4(Dec 6, 2021)

  • 6.0.3(Nov 28, 2021)

    What's Changed

    • downgrade symfony finder by @morrislaptop in https://github.com/spatie/laravel-event-sourcing/pull/295

    Full Changelog: https://github.com/spatie/laravel-event-sourcing/compare/6.0.2...6.0.3

    Source code(tar.gz)
    Source code(zip)
  • 6.0.2(Nov 26, 2021)

  • 6.0.1(Nov 26, 2021)

  • 6.0.0(Nov 24, 2021)

    • Support PHP 8.1
    • The EventHandler interface was changed in order to use the spatie/better-types package:
    -    public function handles(): array;
    +    public function handles(StoredEvent $storedEvent): bool;
    
    -    public function handle(StoredEvent $event);
    +    public function handle(StoredEvent $storedEvent): void;
    
    Source code(tar.gz)
    Source code(zip)
  • 5.0.8(Nov 17, 2021)

    What's Changed

    • Fixed tests/VersionedEventTest.php::a_versioned_event_can_be_restored by @etahamer in https://github.com/spatie/laravel-event-sourcing/pull/286
    • Set minimum version of illuminate/database to ^8.34 by @etahamer in https://github.com/spatie/laravel-event-sourcing/pull/290

    Full Changelog: https://github.com/spatie/laravel-event-sourcing/compare/5.0.7...5.0.8

    Source code(tar.gz)
    Source code(zip)
  • 5.0.7(Nov 17, 2021)

    What's Changed

    • Update introduction.md by @WouterBrouwers in https://github.com/spatie/laravel-event-sourcing/pull/266
    • Update installation-setup.md by @WouterBrouwers in https://github.com/spatie/laravel-event-sourcing/pull/265
    • Update introduction.md by @WouterBrouwers in https://github.com/spatie/laravel-event-sourcing/pull/264
    • Update using-projectors-to-transform-events.md by @WouterBrouwers in https://github.com/spatie/laravel-event-sourcing/pull/263
    • Update using-aggregates-to-make-decisions-based-on-the-past.md by @WouterBrouwers in https://github.com/spatie/laravel-event-sourcing/pull/262
    • Update creating-and-configuring-projectors.md by @WouterBrouwers in https://github.com/spatie/laravel-event-sourcing/pull/261
    • Update thinking-in-events.md by @WouterBrouwers in https://github.com/spatie/laravel-event-sourcing/pull/260
    • Update writing-your-first-reactor.md by @WouterBrouwers in https://github.com/spatie/laravel-event-sourcing/pull/259
    • Update writing-your-first-aggregate.md by @WouterBrouwers in https://github.com/spatie/laravel-event-sourcing/pull/258
    • Update replaying-events.md by @WouterBrouwers in https://github.com/spatie/laravel-event-sourcing/pull/257
    • Update storing-metadata.md by @WouterBrouwers in https://github.com/spatie/laravel-event-sourcing/pull/256
    • fix broken link to the course by @macbookandrew in https://github.com/spatie/laravel-event-sourcing/pull/253
    • Fix urls pointing to previous version by @quintenbuis in https://github.com/spatie/laravel-event-sourcing/pull/269
    • [Docs] Add EloquentStoredEvent import to example by @stevebauman in https://github.com/spatie/laravel-event-sourcing/pull/273
    • [Docs] Add missing opening bracket for Account model by @stevebauman in https://github.com/spatie/laravel-event-sourcing/pull/272
    • [Docs] Fix wrong operator for onMoneySubtracted by @avosalmon in https://github.com/spatie/laravel-event-sourcing/pull/279
    • Changed cursor() into lazyById() to preserve memory when working with large amount of events by @etahamer in https://github.com/spatie/laravel-event-sourcing/pull/284

    New Contributors

    • @WouterBrouwers made their first contribution in https://github.com/spatie/laravel-event-sourcing/pull/266
    • @macbookandrew made their first contribution in https://github.com/spatie/laravel-event-sourcing/pull/253
    • @quintenbuis made their first contribution in https://github.com/spatie/laravel-event-sourcing/pull/269
    • @stevebauman made their first contribution in https://github.com/spatie/laravel-event-sourcing/pull/273
    • @avosalmon made their first contribution in https://github.com/spatie/laravel-event-sourcing/pull/279
    • @etahamer made their first contribution in https://github.com/spatie/laravel-event-sourcing/pull/284

    Full Changelog: https://github.com/spatie/laravel-event-sourcing/compare/5.0.6...5.0.7

    Source code(tar.gz)
    Source code(zip)
  • 5.0.6(Sep 12, 2021)

  • 5.0.5(Jul 26, 2021)

  • 5.0.4(Jun 15, 2021)

  • 5.0.3(Jun 14, 2021)

  • 5.0.2(Jun 14, 2021)

  • 5.0.1(Jun 10, 2021)

  • 5.0.0(Jun 9, 2021)

    • Add EloquentStoredEvent::query()->whereEvent(EventA::class, …)

    • Add EventQuery

    • Add AggregateEntity

      • If you're overriding an aggregate root's constructor, make sure to call parent::__construct from it
    • Add command bus and aggregate root handlers

    • Add Projectionist::fake(OriginalReactor::class, FakeReactor::class) (#181)

    • All event listeners are now registered in the same way: by looking at an event's type hint. This applies to all:

      • Aggregate root apply methods
      • Projection listeners
      • Reactor listeners
      • Event queries
    • Moved Spatie\EventSourcing\Exception\CouldNotPersistAggregate to Spatie\EventSourcing\AggregateRoots\Exceptions\CouldNotPersistAggregate

    • Moved Spatie\EventSourcing\Exception\InvalidEloquentSnapshotModel to Spatie\EventSourcing\AggregateRoots\Exceptions\InvalidEloquentSnapshotModel

    • Moved Spatie\EventSourcing\Exception\InvalidEloquentStoredEventModel to Spatie\EventSourcing\AggregateRoots\Exceptions\InvalidEloquentStoredEventModel

    • Moved Spatie\EventSourcing\Exception\MissingAggregateUuid to Spatie\EventSourcing\AggregateRoots\Exceptions\MissingAggregateUuid

    • Moved Spatie\EventSourcing\Exception\InvalidStoredEvent to Spatie\EventSourcing\StoredEvents\Exceptions\InvalidStoredEvent

    • Dependency injection in handlers isn't supported anymore, use constructor injection instead

    • $storedEvent and $aggregateRootUuid are no longer passed to event handler methods. Use $event->storedEventId() and $event->aggregateRootUuid() instead. (#180)

    • Rename EloquentStoredEvent::query()->uuid() to EloquentStoredEvent::query()->whereAggregateRoot()

    • Removed AggregateRoot::$allowConcurrency

    • Removed $aggregateVersion from StoredEventRepository::persist

    • Removed $aggregateVersion from StoredEventRepository::persistMany

    • Event handlers are no longer called with app()->call() (#180)

    • $handlesEvents on Projectors and Reactors isn't supported anymore

    • PHP version requirement is now ^8.0

    • Laravel version requirement is now ^8.0

    Source code(tar.gz)
    Source code(zip)
  • 4.10.2(May 4, 2021)

  • 4.10.1(Apr 21, 2021)

  • 4.10.0(Apr 21, 2021)

    • Deprecate AggregateRoot::$allowConcurrency
    • Fix for race condition in aggregate roots (#170), you will need to run a migration to be able to use it:
    public function up()
    {
        Schema::table('stored_events', function (Blueprint $table) {
            $table->unique(['aggregate_uuid', 'aggregate_version']);
        });
    }
    

    Note: if you run this migration, all aggregate roots using $allowConcurrency will not work any more.

    Source code(tar.gz)
    Source code(zip)
  • 4.9.0(Mar 10, 2021)

Owner
Spatie
We create open source, digital products and courses for the developer community
Spatie
Psalm plugin for patchlevel/event-sourcing

event-sourcing-psalm-plugin psalm plugin for event-sourcing library. installation composer require --dev patchlevel/event-sourcing-psalm-plugin confi

patchlevel 4 Dec 14, 2022
Because every Wedding RSVP website needs to follow DDD, CQRS, Hexagonal Architecture, Event Sourcing, and be deployed on Lambda.

Our Wedding Website Because every Wedding RSVP website needs to follow DDD, CQRS, Hexagonal Architecture, Event Sourcing, and be deployed on Lambda. ?

Edd Mann 3 Aug 21, 2022
Ecotone Framework is Service Bus Implementation. It enables message driven architecture and DDD, CQRS, Event Sourcing PHP

This is Read Only Repository To contribute make use of Ecotone-Dev repository. Ecotone is Service Bus Implementation, which enables message driven arc

EcotoneFramework 308 Dec 29, 2022
A "from scratch" PHP-based implementation of Event-Sourcing

In here, you will find a "from scratch" PHP-based implementation of Event-Sourcing, kept to a minimum on purpose, to allow workshop attendees to explore and experiment with its concepts.

Marco Pivetta 94 Jan 1, 2023
A helpful Laravel package to help me get started in Laravel projects quicker.

Launchpad A helpful Laravel package to help me get started in Laravel projects quicker. This is still a work in progress, so use at your own risk! CLI

Steve McDougall 13 Jun 15, 2023
An all-in-one package with the minimum third-party requirements to get started as quickly as possible with Pokemod Atlas

Pokemod Atlas All-In-One An all-in-one package with the minimum third-party requirements to get started as quickly as possible with Pokemod Atlas. ❤️

Pokemod 12 Oct 10, 2022
Laravel Blog Package. Easiest way to add a blog to your Laravel website. A package which adds wordpress functionality to your website and is compatible with laravel 8.

Laravel Blog Have you worked with Wordpress? Developers call this package wordpress-like laravel blog. Give our package a Star to support us ⭐ ?? Inst

Binshops 279 Dec 28, 2022
The easiest way to match data structures like JSON/PlainText/XML against readable patterns. Sandbox:

PHP Matcher Library created for testing all kinds of JSON/XML/TXT/Scalar values against patterns. API: PHPMatcher::match($value = '{"foo": "bar"}', $p

Coduo 774 Dec 31, 2022
Parsica - PHP Parser Combinators - The easiest way to build robust parsers.

Parsica The easiest way to build robust parsers in PHP. composer require parsica-php/parsica Documentation & API: parsica-php.github.io <?php $parser

null 350 Dec 27, 2022
The Easiest way to start using PHP CS Fixer and PHP_CodeSniffer with 0-knowledge

The Easiest Way to Use Any Coding Standard Features Blazing fast Parallel run Use PHP_CodeSniffer || PHP-CS-Fixer - anything you like 2nd run under fe

null 1.1k Jan 6, 2023
Lightweight PHP wrapper for OVH APIs. That's the easiest way to use OVH.com APIs in your PHP applications.

This PHP package is a lightweight wrapper for OVH APIs. That's the easiest way to use OVH.com APIs in your PHP applications.

OVHcloud 263 Dec 14, 2022
MOP is a php query handling and manipulation library providing easy and reliable way to manipulate query and get result in a fastest way

Mysql Optimizer mysql optimizer also known as MOP is a php query handling and manipulation library providing easy and reliable way to manipulate query

null 2 Nov 20, 2021
A Laravel artisan based package to create the AWS (SES + SNS) infrastructure to receive email event notifications with Http/Https endpoint.

Laravel SES Tracking Setup the AWS infrastructure to handle email events using SES/SNS and http/s endpoints with a single Laravel artisan command. Thi

null 11 Apr 26, 2022
An Infection + Last Man Standing Event plugin written for OwnagePE

KitPvPEvent An Infection + Last Man Standing Event plugin written for OwnagePE This plugin was a speedcode. I kinda woke up really late on the day I w

OwnagePE Network 2 May 26, 2022
This library is an implementation of League\Event for Slim Framework

Slim Event Dispatcher This library is an implementation of League\Event for Slim Framework. This works with the latest version of Slim (V3). Installat

Aneek Mukhopadhyay 7 Aug 23, 2022
Notify instructors about unconfirmed event registrations.

SAC Event Registration Reminder Folgende Idee: Es wird ein Reminder-Tool benötigt, welches Tourenleitende und Bergführer/innen per E-Mail daran erinne

Marko Cupic 2 Apr 25, 2022
True coroutines for PHP>=8.1 without worrying about event loops and callbacks.

Moebius Pure coroutines for PHP 8.1. To promises and callbacks needed. Just pure parallel PHP code inside coroutines. Moebius Band: A loop with only o

Frode Børli 204 Dec 21, 2022
Implement event systems, signal slots, intercepting filters, and observers.

zend-eventmanager Repository abandoned 2019-12-31 This repository has moved to laminas/laminas-eventmanager. zend-eventmanager is designed for the fol

Zend Framework 1.7k Dec 9, 2022
Allows installing Drupal extensions event if not compatible with installed drupal/core package

mglaman/composer-drupal-lenient Lenient with it, Drupal 10 with it. Why? The Drupal community introduced a lenient Composer facade that modified the d

Matt Glaman 14 Dec 18, 2022