Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Event Store Dbal Laravel Package

micro-module/event-store-dbal

A Doctrine DBAL-backed event store for micro-module applications. Persist and replay domain events in a relational database through a simple API suited to event sourcing and CQRS workflows.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. This is a low-level persistence adapter, not an application framework. It supplies a Doctrine DBAL-backed implementation of an event store (append streams, read streams, likely snapshot support), which slots into a hexagonal/DDD architecture where the domain depends on an event-store interface and infrastructure supplies the storage. That is a reasonable shape for a Laravel codebase that already separates domain from framework. It is not a Laravel package in the idiomatic sense: expect no service provider, no publishable config, no Eloquent models, no artisan commands, no queue integration. A TPM should treat this as a library to be wired manually, not a drop-in feature.

Integration feasibility. Composer-installable and MIT-licensed, so legal/procurement friction is nil. The real work is four pieces the package almost certainly does not do for you: (1) publishing the event-store schema as a Laravel migration, (2) choosing and implementing event serialization (payload + metadata + event type discriminator), (3) mapping your aggregate/stream identity convention onto its API, and (4) handling optimistic-concurrency exceptions in the application layer. Each is modest individually; together they represent a meaningful spike, not an afternoon integration.

Technical risk. High, and concentrated in three places:

  • Compatibility. The last release is May 2022, i.e. PHP 7.4/8.0-era with Doctrine DBAL 2.x-or-3.x constraints. DBAL 3 removed Statement::execute(), fetchAll(), and friends in favour of executeStatement()/fetchAllAssociative(). Laravel 10/11 ship DBAL ^3. If this package pins DBAL ^2, it is uninstallable on a current Laravel baseline without patching. Verify the composer constraint first — this is the single highest-probability blocker.
  • Abandonment. Zero stars, zero dependents, no release in ~3 years, single-maintainer organisation with sibling packages ("micro-module/*") that are presumably equally quiet. There is no evidence of production use anywhere. Zero dependents is not a signal of quality — it is a signal of no validation.
  • Ecosystem coupling. If the package implements an interface owned by a sibling micro-module package, you inherit that dependency's health too, and a fork means forking the interface as well.

Key questions to answer before committing:

  1. What exact interface/contract does it implement, and is that contract owned by this repo or a sibling?
  2. What is the concurrency model — version column with a unique constraint, SELECT … FOR UPDATE, or nothing?
  3. Which DBAL major version is required, and does the constraint resolve on our Laravel/PHP baseline?
  4. Is event serialization pluggable, and is there any event upcasting support for schema evolution?
  5. Does it ship a schema/migration, and does it support snapshots and stream deletion?
  6. Are there subscription/polling primitives for projections, or is that entirely out of scope?
  7. Who maintains it, and is there any commit activity since the 2022 release?

Integration Approach

Stack fit. Works with any Laravel version whose doctrine/dbal constraint it satisfies, and can share the application's existing connection or use a dedicated one. The DBAL dependency is not exotic — Laravel itself pulls DBAL for column-modification support — but Laravel's constraint is a dev/optional one, so the package's own constraint governs and may force a downgrade you cannot accept.

Recommended migration path — wrap, don't couple. Define your own EventStore port in the application layer and make this package one adapter behind it, even if it is currently the only implementation. Given the maintenance signals, the strategic value of this package is as a reference implementation you can lift the SQL and semantics from, not as a long-term dependency. Two viable paths:

  • Fork-and-own: copy into the monorepo (or a packages/ path repository), keep the MIT headers, apply the DBAL 3 fixes if needed. Realistic and cheap given the codebase is small.
  • Reimplement-thin: the event store's hot path is an append with a unique (stream_id, version) constraint plus a ranged read. Many teams write this in a few hundred lines tailored to their access patterns, avoiding a dependency entirely.

Either path is defensible. composer require from Packagist as a permanent dependency is the option I would advise against.

Compatibility work to sequence before committing:

  1. Read the composer.json constraints and the DBAL API surface actually used; confirm DBAL major compatibility with the target Laravel baseline.
  2. Confirm PHP version floor and any deprecations on the target runtime.
  3. Check whether the interface it implements is stable and versioned, or an internal contract likely to move.

Sequencing (a 2–3 week discovery, then a gate):

  1. Day 1–2: dependency-resolution spike on the real baseline. If it will not install, stop and pick a different path — this is a cheap kill signal.
  2. Week 1: wire the adapter behind your own interface, add the migration, implement serialization with an explicit event-type registry.
  3. Week 2: concurrency test — two writers racing one aggregate stream, assert the losing writer gets a clean domain-level conflict, not a raw DBAL exception.
  4. Week 2–3: minimum viable projection mechanism (this will almost certainly be yours to build), replay/rebuild test on a non-trivial event volume.
  5. Gate: decide fork-and-own vs. build-thin vs. adopt a maintained alternative. Do not pass the gate without the concurrency and replay tests green.

If the team wants event sourcing as a feature with projections, reactors, and Laravel ergonomics, evaluate a maintained, Laravel-native option in parallel — this package will not supply the upper layers, and assembling them from an unmaintained base is the worst of both worlds.

Operational Impact

Maintenance and support. Assume you own it from day one. There is no upstream support, no issue triage, no security response process, and no community to ask. Zero dependents means every bug you find is your bug. Budget forked-code maintenance explicitly in the team's capacity — probably low absolute effort for a small adapter, but non-zero and permanent. Add it to the dependency-risk register with a named owner and a review date.

Scaling characteristics. An append-only table with a unique (stream_id, version) index and a read index on (stream_id, version) scales to tens of millions of rows on Postgres/MySQL without drama, provided you never do unbounded scans. Watch four things:

  • Table growth — no partitioning or archival out of the box; plan a retention/compaction strategy for short-lived streams.
  • Snapshot policy — long-lived aggregates will rehydrate hundreds of events per command unless you snapshot; that is a policy decision with a cost curve, not a package feature.
  • Projection throughput — without subscription primitives you will poll, and polling is a linear load multiplier on the primary. Consider a read-replica or a committed-position table from the start.
  • Connection pressure — an event store on the same connection pool as the request path can starve under write bursts.

Failure modes to design against:

  • Concurrency conflict surfaced as a raw DBAL exception. Must be translated into a domain-level ConcurrencyException; otherwise domain code depends on infrastructure. This is the most common defect when adopting a bare adapter.
  • Partial writes. If append and read-model update are not in one transaction (or an outbox), you get silently divergent projections with no recovery path.
  • Serialization drift. Renaming or moving an event class breaks replay of historical events. Without upcasting support, you need an explicit type-string → class registry and a migration story for payload shape changes. This is the failure mode that hurts most and surfaces latest.
  • Projection poison messages. A single unparseable event can stall a polling projector forever. Needs a dead-letter/skip-with-alert path.
  • Non-idempotent subscribers. At-least-once delivery means duplicate handling is the application's problem; assume nothing here.

Ramp-up. The binding constraint is not the package, it is event sourcing literacy. Engineers new to the model tend to build CRUD-shaped aggregates, over-snapshot, and treat projections as authoritative. Budget for a design review of the first two aggregates and a short internal primer on streams, versions, replay, and eventual consistency. Team familiarity with Doctrine DBAL specifically is likely near zero in a Laravel shop — that is a smaller but real ramp.

Bottom line for the TPM: feasible as an internal, wrapped component with a clear fork/licence story and a defined owner; not advisable as an adopted third-party dependency on a current Laravel baseline. Gate the decision on dependency resolution and the concurrency test, and pre-commit to owning it, because no one else will.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin