iotron/laravel-state-machine
A Laravel package for building state machines around Eloquent models. Define states and allowed transitions, guard status changes, and keep workflow logic organized, explicit, and easy to test. Helps replace scattered status checks with a clear, maintainable transition map.
Architecture fit. The package implements the state machine pattern directly on Eloquent models — transitions, guards/hooks, enum-backed states, and transition history. That maps cleanly onto the lifecycle-heavy domain objects most Laravel applications already have (orders, subscriptions, approvals, onboarding). It is a single-purpose library with a narrow surface area, which keeps architectural coupling low: the state machine lives inside the model layer rather than introducing a new service tier or event bus. The v1.0.1 release does not change this shape; it hardens the transition path and widens framework support.
Integration feasibility. Composer-installable with a clearly stated support matrix (Laravel 11/12/13, PHP 8.2–8.4, MySQL/PostgreSQL/SQLite). The package self-describes as a drop-in replacement for asantibanez/laravel-eloquent-state-machines, which materially lowers adoption cost for teams already using that package — the swap is a dependency change plus a namespace/API parity check rather than a re-architecture. New adopters get a conventional, well-understood pattern. The main integration work is publishing and owning the transition-history schema and deciding where transaction boundaries live in application code.
Technical risk. The headline risk in 1.0.1 is that the transaction change is behavioral, not merely additive. StateMachine now inspects DB::transactionLevel() and reuses an ambient transaction instead of opening a nested one. That is the right default for most applications, but it changes rollback semantics: a transition that previously failed in isolation and rolled back to a savepoint will now roll back the caller's entire transaction. Any workflow relying on partial-commit or per-transition isolation must be re-validated. Secondary risks: a fork-based lineage means parity drift with upstream, and the Laravel 13 lane drops PHP 8.2, so the support matrix is not uniform across framework versions.
Key questions.
asantibanez package, and how are divergences tracked?Stack fit. Native to Laravel: Eloquent models, DB facade transaction handling, enum support, and the framework's testing conventions. No non-standard runtime dependencies are implied beyond Laravel itself and Carbon. It slots into an existing Laravel codebase without new infrastructure, and the supported database set covers typical local (SQLite) and production (MySQL/PostgreSQL) configurations.
Migration path. Two distinct paths:
asantibanez package — swap the composer requirement, verify namespace and method parity against the in-house model definitions, and run the full existing state machine test suite before merging. Treat this as a dependency substitution with a parity gate, not a refactor.For both, the decisive step is auditing existing DB::transaction() call sites around transitions to confirm the new reuse behavior matches intent.
Compatibility. Pin the matrix explicitly in CI: Laravel 11/12 on PHP 8.2–8.4, Laravel 13 on PHP 8.3–8.4 (mirroring the upstream workflow's PHP 8.2 exclusion). Confirm that the application's own Laravel constraint and PHP floor align before bumping; a Laravel 13 upgrade and this package bump should travel together rather than sequentially. Verify behavior on the target production database, since savepoint handling is the specific thing that changed.
Sequencing.
TransactionBoundaryTest — assert both the ambient-transaction and no-transaction paths.Maintenance. The codebase is small and the change surface per release is narrow, so ongoing maintenance is light. The real cost is lineage tracking: as a drop-in replacement for an actively used upstream package, the team inherits responsibility for monitoring upstream changes, Laravel release cycles, and any divergence in behavior. Assign a named owner for dependency bumps and budget a review per Laravel minor release.
Support. Support posture is the weakest-known dimension. Release notes indicate an active CI matrix and a meaningful test suite (TransactionBoundaryTest, expanded enum and history coverage), which is a positive signal for quality. But there is no stated commercial support, SLA, or security disclosure process. For business-critical workflows, plan on internal capability to read and patch the package rather than relying on upstream responsiveness.
Scaling. Two scaling axes matter. First, transition history: every transition writes a row, so high-volume models need an indexed history table and a retention/pruning policy defined up front — this is application-owned work. Second, concurrency: transitions on the same aggregate must be serialized (row locks or queued commands) to avoid interleaved state changes; the package's transaction handling makes this cleaner but does not by itself prevent races. The transaction-level check adds one cheap introspection call per transition — negligible.
Failure modes.
Ramp-up. Low. State machines are a familiar pattern and the package's API is idiomatic Laravel, so a mid-level developer can ship a first model in under a day. The learning investment belongs in the transaction semantics and history/retention design rather than the library API. Budget a short internal write-up documenting the transaction-boundary rule, since that is the one place where intuition from the previous version (or from hand-rolled transition code) will be wrong.
How can I help you explore Laravel packages today?