PHPackages                             markkimsal/laravel-event-sourcing - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. markkimsal/laravel-event-sourcing

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

markkimsal/laravel-event-sourcing
=================================

The easiest way to get started with event sourcing in Laravel

v3.3.0(3y ago)0789MITPHPPHP ^7.2|^8.0

Since Sep 20Pushed 3y ago1 watchersCompare

[ Source](https://github.com/markkimsal/laravel-event-sourcing)[ Packagist](https://packagist.org/packages/markkimsal/laravel-event-sourcing)[ Docs](https://github.com/markkimsal/laravel-event-sourcing)[ Fund](https://spatie.be/open-source/support-us)[ RSS](/packages/markkimsal-laravel-event-sourcing/feed)WikiDiscussions master Synced 2d ago

READMEChangelogDependencies (13)Versions (21)Used By (0)

Event sourcing with no concurrency bugs
=======================================

[](#event-sourcing-with-no-concurrency-bugs)

I haven't found a PHP library yet that does event sourcing properly wrt concurrency, so I fixed one.

Fixes from spatie fork:

- don't allow concurrent updates to event stream for same aggregate root UUID
- Fix concurrent reading - (locking reads (fixes pkey "gaps"))
- Fix concurrent writing - (make aggregateVersion per event rather than per persist)

Other changes:

- Removed short fn () syntax (php 7.3)
- Removed member variable types (php 7.3)
- AggregateRoot uuid is protected instead of private
- static make() like retrieve but w/o db lookup

Locking and Transactions
========================

[](#locking-and-transactions)

Mysql's `SELECT ... LOCK IN SHARE MODE` behaves 2 different ways depending on if it is done inside a transaction or outside (with autocommit=1).

Using a locking read will try to obtain a a gap lock or next-key lock because we are scanning a non-unique index of 'aggregate\_uuid' (but I believe this also happens even with a compound unique key of 'aggregate\_uuid' and 'aggregate\_version'). Trying to obtain the lock with autocommit=1 and outside of a `BEGIN` or `START TRANSACTION` statement will have the effect of waiting for other inserts which obtained a next-key lock to complete and flush the output. This means that selecting ranges of pkeys will not result in "gaps".

Using a locking read inside a transaction will try to obtain the same locks on any rows scanned plus obtain a lock on the next item to be inserted into any index scanned. So, using a locking read inside a transaction will block all inserts into `stored_events` table because the lock is on the next highest value of 'aggregate\_uuid', effectively blocking all inserts.

We are not using a locking read inside a transaction when finding the highest aggregate\_version right before inserting new events, but this idea was attempted so some function comments might be referring to this old method.

All this assumes the ISOLATION LEVEL READ COMMITTED (which is the mysql default).

For all `retrieve()` calls whose purpose is to reconstitute an Aggregate, we use locking reads to ensure we see a consistent view of any in-flight write transactions.

For any pre-insert reads which try to ensure the fencing parameter 'aggregate\_version' is up-to-date with the in-memory aggregate, we do not use locking reads and rely on the unique index of 'aggregate\_uuid' + 'aggregate\_version' to prevent stale writes.o

Any call to `persist()` could throw a `CouldNotPersistAggregate` exception.

Static Make
-----------

[](#static-make)

When you subclass AggregateRoot, you always must do a `retrieve($uuid)` call to set the UUID. It's not possible to set the UUID and skip any event loading.

```
//spatie way
$order = OrderAggregate::retrieve($uuid);

//my way
$order = OrderAggregate::make($uuid);

```

Original README follows
-----------------------

[](#original-readme-follows)

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](https://docs.spatie.be/laravel-event-sourcing/v1/getting-familiar-with-event-sourcing/introduction).

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.

- [Larabank built traditionally without event sourcing](https://github.com/spatie/larabank-traditional)
- [Larabank built with projectors](https://github.com/spatie/larabank-event-projector)
- [Larabank built with aggregates and projectors](https://github.com/spatie/larabank-event-projector-aggregates)

Support us
----------

[](#support-us)

We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us).

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](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards).

Documentation
-------------

[](#documentation)

You can find installation instructions and detailed instructions on how to use this package at [the dedicated documentation site](https://docs.spatie.be/laravel-event-sourcing/v1/introduction/).

Upgrading from laravel-event-projector
--------------------------------------

[](#upgrading-from-laravel-event-projector)

This package supercedes [laravel-event-projector](https://github.com/spatie/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](UPGRADING.md).

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

Security
--------

[](#security)

If you discover any security related issues, please email  instead of using the issue tracker.

Postcardware
------------

[](#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, Samberstraat 69D, 2060 Antwerp, Belgium.

We publish all received postcards [on our company website](https://spatie.be/en/opensource/postcards).

Credits
-------

[](#credits)

- [Freek Van der Herten](https://github.com/freekmurze)
- [All Contributors](../../contributors)

The aggregate root functionality is heavily inspired by [Frank De Jonge](https://twitter.com/frankdejonge)'s excellent [EventSauce](https://eventsauce.io/) package. A big thank you to [Dries Vints](https://github.com/driesvints) for giving lots of valuable feedback while we were developing the package.

Footnotes
---------

[](#footnotes)

1 Quote taken from [Event Sourcing made Simple](https://kickstarter.engineering/event-sourcing-made-simple-4a2625113224)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

34

—

LowBetter than 77% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity13

Limited adoption so far

Community20

Small or concentrated contributor base

Maturity72

Established project with proven stability

 Bus Factor1

Top contributor holds 79.6% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~59 days

Recently: every ~240 days

Total

20

Last Release

1307d ago

Major Versions

0.0.1 → 1.0.02019-09-20

1.0.4 → 2.0.02019-12-02

1.1.0 → 2.1.02020-02-07

2.1.0 → 3.0.02020-02-07

PHP version history (4 changes)0.0.1PHP ^7.3

2.0.0PHP ^7.4

3.1.0PHP ^7.2

3.2.1PHP ^7.2|^8.0

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/38968403?v=4)[markk2](/maintainers/markk2)[@markk2](https://github.com/markk2)

---

Top Contributors

[![freekmurze](https://avatars.githubusercontent.com/u/483853?v=4)](https://github.com/freekmurze "freekmurze (551 commits)")[![markkimsal](https://avatars.githubusercontent.com/u/54099?v=4)](https://github.com/markkimsal "markkimsal (33 commits)")[![sebastiandedeyne](https://avatars.githubusercontent.com/u/1561079?v=4)](https://github.com/sebastiandedeyne "sebastiandedeyne (18 commits)")[![adrianspacely](https://avatars.githubusercontent.com/u/3690710?v=4)](https://github.com/adrianspacely "adrianspacely (17 commits)")[![telkins](https://avatars.githubusercontent.com/u/53731?v=4)](https://github.com/telkins "telkins (8 commits)")[![brendt](https://avatars.githubusercontent.com/u/6905297?v=4)](https://github.com/brendt "brendt (8 commits)")[![colinc](https://avatars.githubusercontent.com/u/16424?v=4)](https://github.com/colinc "colinc (6 commits)")[![rodrigopedra](https://avatars.githubusercontent.com/u/5470108?v=4)](https://github.com/rodrigopedra "rodrigopedra (5 commits)")[![gdebrauwer](https://avatars.githubusercontent.com/u/22586858?v=4)](https://github.com/gdebrauwer "gdebrauwer (5 commits)")[![dilab](https://avatars.githubusercontent.com/u/218813?v=4)](https://github.com/dilab "dilab (4 commits)")[![pascalbaljet](https://avatars.githubusercontent.com/u/8403149?v=4)](https://github.com/pascalbaljet "pascalbaljet (3 commits)")[![jamesfairhurst](https://avatars.githubusercontent.com/u/230768?v=4)](https://github.com/jamesfairhurst "jamesfairhurst (3 commits)")[![unreasonablymundane](https://avatars.githubusercontent.com/u/25407733?v=4)](https://github.com/unreasonablymundane "unreasonablymundane (3 commits)")[![36864](https://avatars.githubusercontent.com/u/109086466?v=4)](https://github.com/36864 "36864 (3 commits)")[![vtalbot](https://avatars.githubusercontent.com/u/1474848?v=4)](https://github.com/vtalbot "vtalbot (2 commits)")[![Azeirah](https://avatars.githubusercontent.com/u/4040870?v=4)](https://github.com/Azeirah "Azeirah (2 commits)")[![danielwaghorn](https://avatars.githubusercontent.com/u/9108635?v=4)](https://github.com/danielwaghorn "danielwaghorn (2 commits)")[![hailwood](https://avatars.githubusercontent.com/u/709773?v=4)](https://github.com/hailwood "hailwood (2 commits)")[![mfullbrook](https://avatars.githubusercontent.com/u/548608?v=4)](https://github.com/mfullbrook "mfullbrook (2 commits)")[![michael-schaefer-eu](https://avatars.githubusercontent.com/u/9930093?v=4)](https://github.com/michael-schaefer-eu "michael-schaefer-eu (2 commits)")

---

Tags

eventspatieaggregatessourcingprojectorsreactorslaravel-event-sourcing

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/markkimsal-laravel-event-sourcing/health.svg)

```
[![Health](https://phpackages.com/badges/markkimsal-laravel-event-sourcing/health.svg)](https://phpackages.com/packages/markkimsal-laravel-event-sourcing)
```

###  Alternatives

[spatie/laravel-event-sourcing

The easiest way to get started with event sourcing in Laravel

9003.7M26](/packages/spatie-laravel-event-sourcing)[spatie/laravel-backup

A Laravel package to backup your application

6.0k21.8M191](/packages/spatie-laravel-backup)[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

245.2k](/packages/aedart-athenaeum)[barryvdh/laravel-ide-helper

Laravel IDE Helper, generates correct PHPDocs for all Facade classes, to improve auto-completion.

14.9k123.0M687](/packages/barryvdh-laravel-ide-helper)[spatie/laravel-enum

Laravel Enum support

3655.4M31](/packages/spatie-laravel-enum)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9682.1M97](/packages/roots-acorn)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
