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

Krakboem Laravel Package

rva-vzw/krakboem

A Laravel/PHP package for the card game Krakboem that provides core game rules, state management, and event-driven player actions. It helps developers build digital tables, scoring, and turn-based gameplay in Laravel applications with extensible, configurable components.

View on GitHub
Deep Wiki
Context7

Getting Started

Krakboem is a set of CQRS/event-sourcing interfaces plus a small kernel — not a batteries-included framework. Budget an hour to read the source before writing application code.

  1. composer require rva-vzw/krakboem. The core has no framework dependency; the Symfony integration lives in a separate krakboem-bundle.
  2. Read these first, in this order: CommandBus, EventBus, Event / Command marker interfaces, AggregateRoot, EventStore, EventSourcedRepository. They define the whole vocabulary; everything else is wiring.
  3. Skim the package's own test suite — it doubles as the only reliable example set for a library at this maturity level.
  4. Pick one genuinely small aggregate for your first slice: a TodoList, Cart, or Invoice. Anything with more than ~5 events will obscure the learning curve.
  5. On Laravel, do not install the Symfony bundle. Bind the interfaces manually in a service provider (CommandBus, EventBus, EventStore, EventSourcedRepository) and inject the concrete implementations you choose.
  6. First use case to prove the loop end-to-end: dispatch a CreateThing command → handler instantiates the aggregate → aggregate records a ThingCreated event → repository persists to the event store → a projection listens and writes a read-model row. Once that circle closes, everything else is repetition.

Implementation Patterns

Aggregate as the unit of consistency. Handlers should be thin: load the aggregate via the repository, call a domain method, save. All business rules live on the aggregate; commands are validated by the aggregate raising events, not by the handler. Resist putting if logic in handlers.

Command → event → projection pipeline. A command handler mutates one aggregate and returns nothing. The event bus fans out to projections and sagas. Keep projections dumb and idempotent — they receive events, they don't call back into aggregates.

Repository load-by-replay. EventSourcedRepository::get($id) fetches a stream and calls apply() on each event. Design apply() methods to be pure state transitions with no side effects (no email sending, no HTTP calls). Side effects belong in projectors or sagas.

Optimistic concurrency. Persist with the expected aggregate version and let the event store throw on mismatch. Wrap command dispatch in a retry for transient conflicts on hot aggregates; never swallow the exception silently.

Sagas / process managers for cross-aggregate workflows. When one aggregate's event must trigger a command on another, put that glue in a saga with an explicit state store. Don't let projections dispatch commands — replaying a projection would re-fire business actions.

Testing with an in-memory event store. Inject an in-memory EventStore implementation into the repository and write given/when/then tests: seed events, dispatch a command, assert the new events on the stream. This is the single highest-leverage habit with this package.

Laravel integration. Use a service provider to bind interfaces; bind a CommandBus that runs synchronously for write paths. Route projectors to queued jobs only after you've verified synchronous behaviour — ordering bugs in async projections are painful to diagnose.

Middleware as the extension seam. Logging, transactions, validation, and metrics all belong in CommandBus/EventBus middleware rather than handlers. Wrap the event store save and the event bus dispatch in the same transaction where your storage backend supports it.

Gotchas and Tips

  • Thin docs, zero stars. Treat the source and tests as the documentation. Pin the version in composer.json and expect to read diffs on upgrade; the public API is small but not yet battle-hardened by a large user base.
  • The Symfony bundle is not the core. Don't assume Laravel parity. Everything the bundle auto-wires (serializers, event store backends, buses) you must bind yourself. Expect half a day of plumbing before your first aggregate runs.
  • Treat events as immutable and versioned. Once an event is in the store, it is permanent. Add an eventVersion and plan for upcasters before you have production data, not after. Never rename event properties without a migration path.
  • Serialization is your problem. Use a stable, explicit format (JSON with a discriminator field is fine). Do not use PHP serialize() — refactors break stored events.
  • Idempotency everywhere. Projections and sagas will be replayed. Every handler must tolerate receiving the same event twice; a processed_events table or a natural-key upsert is usually cheapest.
  • Snapshots are an optimisation, not a requirement. Skip them until a stream exceeds a few hundred events. Adding them prematurely introduces a second source of truth to debug.
  • The event log is your debugger. When something is wrong, read the stream for the aggregate first — the answer is almost always there. Build a small artisan command or route early to dump a stream; it pays for itself within a week.
  • Don't expose aggregate objects from handlers. Return void (or a command result DTO). Leaking the aggregate into controllers couples your HTTP layer to event-sourcing internals and makes replay-based reasoning fragile.
  • Concurrency exceptions must be visible. Log every optimistic-lock failure with the aggregate id and expected version. Silent retries hide a domain modelling problem — usually two commands targeting one aggregate that should have been modelled as one.
  • Extension points to know: custom CommandBus middleware, custom EventBus implementations (sync vs. async), and pluggable EventStore backends. If you need something the package doesn't offer, implement the interface rather than forking — the interfaces are the stable part.
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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console