teknoo/states-bundle
Teknoo States Bundle is a Symfony bundle for defining and managing object states and transitions. It provides configurable state machines, transition rules, and workflow integration for PHP applications that need clear lifecycle handling.
Architecture fit. This is the wrong artifact for a Laravel codebase, and that is the first thing a TPM must internalise before spending engineering time. teknoo/states-bundle is a Symfony bundle — it ships a Bundle subclass wired for Symfony's HttpKernel, a DI compiler pass, and a configuration tree. Laravel has no equivalent of a bundle: no bundle.php, no container extension, no kernel hook. What is portable is the underlying state-machine library (now teknoo/states 3.1+), which is framework-agnostic PHP implementing the State pattern with attribute-driven configuration. So the realistic evaluation unit is the generator/library, not this bundle, and the bundle half simply cannot be reused in our stack without reimplementation.
Integration feasibility. Low as packaged. There is no Laravel service provider, no publishable config, no facade, and no evidence anyone has ever wired this into a Laravel app (0 dependents, 2 stars). Dependency resolution is also a practical blocker: the bundle's constraints are pinned to Symfony generations, and a modern Laravel composer.json will either fail resolution outright or drag the full Symfony framework stack into the tree alongside Illuminate — duplicated HTTP kernel concepts, duplicated container abstractions, and a large surface to justify in review. Even the surviving library route requires us to hand-build discovery and hydration that Symfony provided for free.
Technical risk. High, and mostly non-technical in character:
teknoo/states 3.1+. We would be adopting a superseded API on a branch that receives no fixes.Key questions for the spike.
teknoo/states 3.1+ actively released, or is it also dormant? A deprecated pointer to a dead successor is not a migration, it is a hop.Stack fit. Poor at the package level, moderate at the pattern level. Laravel already has idiomatic options for the same problem: PHP 8.1 backed enums with transition methods, Illuminate\Pipeline, or an actively maintained package such as Spatie's model-states. Those follow framework conventions, get community patches, and need no explanation to a new hire.
Migration path. Do not install this bundle. Two viable routes:
composer require teknoo/states, then write a small Laravel service provider to replace the Symfony compiler pass for state-class discovery. Everything Symfony-specific is reimplemented by us.Compatibility gates. Before any code: confirm PHP constraint satisfaction against our runtime, run composer why-not against candidate constraints, and verify emitted code passes static analysis and lint unmodified. Persist the state name (a string column), never the state object — hydrate on retrieval via an Eloquent cast or a small hydrator service, and verify the initialisation method name against the current tests, since it has moved between 2.x and 3.x.
Sequencing. (1) Timeboxed 2–3 day spike on a throwaway branch, generating one real state machine from an existing domain (order or subscription lifecycle). (2) Diff the generated output against a hand-written enum equivalent. (3) Decide Route A or B. (4) If Route A, vendor-pin and add Composer audit watch; if Route B, document the pattern and move on. Treat this as a decision gate, not a delivery item — do not sequence it behind other work.
Maintenance. The dominant cost. An archived dependency means we inherit the maintenance obligation the moment we ship it: patching PHP-version compatibility ourselves, manually watching the upstream successor, and re-validating on every framework upgrade. The decision that most reduces blast radius is where the generator runs. If generated classes are committed to the repo and the generator is dev-only, the runtime dependency vanishes and only the build step is at risk. That single distinction should drive the decision more than any feature comparison.
Support. None. No maintainer response, no issue triage, no release notes. Internal knowledge transfer becomes critical: whoever runs the spike must document the generated shape and the regeneration command, or the next engineer will read the output as hand-written code and edit it in place.
Scaling. Computationally a non-issue — generated state classes are static, allocation-light, and dispatch like any normal object; they scale as well as hand-written code, arguably better than deep conditional chains. The scaling concern is organisational: one codegen workflow serving many state machines is a win; one unmaintained codegen workflow serving many state machines is a single point of failure across the domain model.
Failure modes.
Ramp-up. Superficially fast — the API surface is small and the State pattern is well documented. The real ramp is conceptual: the team needs shared literacy on when a state machine is warranted versus when it is over-engineering a three-branch conditional. Budget half a day of design discussion per candidate domain, not half a day of onboarding.
Recommendation. Do not adopt teknoo/states-bundle in a Laravel codebase. Run a short spike to harvest the pattern and confirm whether the successor library is alive; absent evidence of active maintenance, implement the pattern with native PHP enums or an actively maintained Laravel-native alternative. The opportunity score reflects an unoccupied niche, and the near-zero composite score correctly identifies why it is unoccupied.
How can I help you explore Laravel packages today?