caner/state-machine
A lightweight Laravel state machine for Eloquent models. Define states, transitions and guards, apply them safely with validation, events and history, and keep workflow logic out of controllers and models. Ideal for approvals, orders and multi-step processes.
if ($order->status === 'paid') checks across controllers, jobs, and listeners.refunded"), and customer-facing status timelines all key off a canonical state graph.save()" bugs at call sites), and improves docs with a worked example project. Together these lower the cost of a spike and raise the odds the package behaves as advertised — but they are evaluation enablers, not a maturity signal.Consider it when:
DB::transaction() wrappers around every call site.save() bookkeeping — 1.1.0 handles the state write on a successful transition, which removes a common class of "state changed in memory but not in the database" defects.Look elsewhere (or build in-house) when:
spatie/laravel-model-states, which is the de facto Laravel answer and has materially broader adoption; the PM question is whether this package's transaction-safety angle justifies the adoption risk gap.transitionTo() method is cheaper to own.For executives (one paragraph): We're evaluating a small open-source Laravel component that formalizes how records move between states — order placed → paid → shipped → refunded, for example — and guarantees each move is atomic with the database writes around it. It costs nothing in license (MIT) and could reduce defect classes where records end up in impossible states, which directly affects revenue reporting and customer trust. The latest release, 1.1.0, addresses the two things that made it hard to even trial: it now supports Laravel 9, saves the new state automatically so engineers can't half-apply a transition, and ships documentation with a working example. The maturity caveat stands — small user base, single maintainer, and a slow release rhythm. Recommendation is unchanged but better informed: run a short engineering spike on one non-critical workflow, then decide adopt / vendor-and-own / decline. Worst case we vendor a few hundred lines of code and own it; best case it saves us building transition logic from scratch.
For engineering (the ask): Re-run the spike with 1.1.0 and validate the new behavior specifically: confirm compatibility with our exact Laravel and PHP versions (only Laravel 9 is claimed), and verify how "automatic state update" persists — does it fire inside the same transaction as our side effects, does it respect saveQuietly/events, does it behave under nested transactions and queued jobs, and does it interact correctly with model observers and audit hooks. Still evaluate against spatie/laravel-model-states and an in-house enum-plus-guards approach. Also confirm guard/authorization extensibility and test coverage. Report back with adopt / vendor-and-own / decline, with the transition rules owned in configuration rather than controller code either way.
How can I help you explore Laravel packages today?