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

Workflow Bundle Laravel Package

lexik/workflow-bundle

LexikWorkflowBundle integrates Symfony Workflow into Symfony applications with DI configuration, workflow visualization, and Doctrine entity state tracking.

View on GitHub
Deep Wiki
Context7

Getting Started

lexik/workflow-bundle is a Symfony2-era bundle (not a Laravel package) that wires a config-defined state machine — workflows, steps, and transitions — to a Doctrine entity, with a WorkflowManager service as the single runtime entry point. It is MIT, archived, ~126 stars, and effectively has no downstream dependents.

Decision first, code second. As a Laravel developer you have three realistic paths:

  1. You maintain a legacy Symfony 2.x app — install it there and use it as intended.
  2. You're evaluating it for a Laravel app — do not install it. Symfony2 bundles do not boot outside the Symfony 2 kernel, and the package is archived. Read the config DSL and WorkflowManager API, then reimplement with symfony/workflow (standalone, Composer-installable in Laravel) or spatie/laravel-model-states.
  3. You want the ideas, not the code — mine Flow/, the YAML examples in the tests, and the Doctrine listener for the pattern.

Minimal setup on the Symfony side:

composer require lexik/workflow-bundle
  • Register Lexik\Bundle\WorkflowBundle\LexikWorkflowBundle in AppKernel.
  • Add a lexik_workflow: block with your workflow name, its steps, and the transitions between them.
  • Make the entity stateful — add the bundle's state field/trait and the Doctrine mapping so the current step name persists.
  • Inject lexik_workflow.workflow_manager (or the workflow-specific service) into your controller.

Look first at: WorkflowManager (the whole public API surface is small — start, read current step, apply transition), the Flow/ namespace for the step/process model, Resources/config/ for the service wiring and config tree, and the bundle's tests for canonical YAML examples.

First use case: an order checkout wizard — cart → address → payment → review → done — with a guard on payment that refuses to advance until the charge succeeds. That exercises config, manager, entity state, and one guard in a single afternoon.

Implementation Patterns

Treat the YAML as your domain contract. Define each workflow once, name steps after business states rather than routes (awaiting_payment, not payment_page), and resist letting controllers invent step names. In the Laravel port this becomes a PHP enum plus a transition map — same shape, type-safe.

One entry point for mutation. Never set the entity's state field directly. All movement goes through the manager:

$manager->applyTransition($entity, 'pay');
return $this->redirect($manager->getNextStepUrl($entity)); // or map step -> route yourself

This is the pattern worth stealing even if you don't steal the code: a single choke point makes audit logging, authorization, and event dispatch trivial.

Guards belong in services. Step conditions reference container services/callables. Keep the decision logic in a service with injected dependencies (payment gateway, inventory, user), and let the YAML only name it. Business rules in YAML are unreadable, untestable, and invisible to static analysis.

Side effects via listeners, not inside transitions. Send the confirmation email, reserve stock, and write the audit row from a listener on the step-reached event, not from the controller after applyTransition. Make every listener idempotent — retries and double-clicks happen, and nothing in the bundle stops a transition from firing twice.

Storage choice is architectural, not cosmetic. Session-backed storage is fine for a marketing funnel wizard; it breaks the moment you need an API, multiple tabs, a queue consumer, or a support dashboard ("where are all orders stuck?"). For anything you'll report on, persist the state on the entity and query it with plain Eloquent/Doctrine.

Test the graph, not the controller. Assert the transition table directly: for each (step, transition) pair, confirm the allowed outcome and that the illegal ones throw. Then a single feature test that walks the happy path end-to-end. This catches dead-end steps and unreachable states, which are the real failure mode of config-driven state machines.

Porting checklist for Laravel: entity column → state string column with an enum cast; YAML → transition map in PHP; guards → can policies or guard callables; listeners → domain events; redirect-after-transition → named-route lookup keyed by state.

Gotchas and Tips

  • Archived is the headline gotcha. No PHP 8 support, no Symfony 5/6 support, no security fixes, no maintainer. It is a reference implementation now, not a dependency. Budget for a rewrite if you're on it.
  • Renaming a step is a data migration. Step names are persisted as strings. Renaming payment to awaiting_payment is not a config edit — it's an UPDATE over every affected row plus a coordinated deploy. Choose names you can live with.
  • Transitions aren't transactional. If a listener throws after the state moved, you get a half-applied workflow. Wrap applyTransition + flush in an explicit DB transaction, and make each side effect safe to re-run.
  • Guard failure is silent by default. Decide whether denied transitions throw or return false, log both, and surface a flash message — otherwise users click a button and nothing happens, and you get a bug report with no trace.
  • Config is compiled into the container. YAML changes require a cache clear, and stale var/cache is the #1 cause of "my new step doesn't exist." In dev, confirm the compiled container actually contains your workflow before debugging anything else.
  • Beware session storage in tests. It hides state bugs that only appear with persistence; write the tests against the Doctrine-backed path even if you ship the session one.
  • Debugging toolkit: dump the manager's current step, assert the workflow contains the step you expect, and keep a CLI command or test that renders the full graph — unreachable steps and steps with no outgoing transition are the common defects.
  • Extension points exist (custom storage, custom step types, event subscribers), but every one of them means writing code against abandoned interfaces. Prefer copying the concept into a supported package over extending this one.
  • Check the bundle's own tests before the README. In projects of this vintage, the test fixtures are the most accurate documentation of the config schema.
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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource