Search by

small / workflow-bundle

small

Symfony integration and dependency injection for Small Workflow

Package info

git.small-project.dev/lib/small-workflow-bundle

Type:symfony-bundle

pkg:composer/small/workflow-bundle

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

0.1.0 2026-11-02 20:57 UTC

This package is auto-updated.

Last update: 2026-11-07 18:22:40 UTC


README

Small Workflow Bundle

Symfony dependency-injection integration for small/workflow.

Install

composer require small/workflow-bundle (development currently depends on untagged small/workflow:dev-main). Enable Small\WorkflowBundle\SmallWorkflowBundle::class in config/bundles.php.

Configure

config/packages/small_workflow.yaml:

small_workflow:
  workflows:
    affaire:
      file: '%kernel.project_dir%/config/workflows/affaire.yaml'
      handlers:
        submit: App\Workflow\SubmitHandler
      services:
        'App\Workflow\CanSubmit': App\Workflow\CanSubmit
        'App\Workflow\DraftState': App\Workflow\DraftState
      lock: App\Workflow\AffaireLock
      persister: App\Workflow\AffairePersister
      events: App\Workflow\EventDispatcher

Register the referenced application services in the Symfony container. State/guard instances are optional; without registration the core engine can instantiate no-argument classes itself.

Inject

public function __construct(private WorkflowRegistry $workflows) {}

$instance = $this->workflows->for('affaire', new WorkflowContext([
    'affaire' => $affaire,
    'user' => $user,
]));
$vote = $instance->vote();
$vote->getStates();
$vote->getActions();
$vote->getTransitions();
$instance->execute(AffaireAction::Submit);

WorkflowEngineFactory can also be injected to create a fresh engine (create('affaire')) or a bound instance (for('affaire', $context)). WorkflowRegistry offers a simplified named-workflow lookup. Engines do not retain business-entity state. Voting remains advisory; execution rechecks under the application-provided lock.

No persistence mechanism, default lock, database schema or Doctrine integration is installed by this bundle. The application implements persistence and transaction boundaries.

PHP attribute autoconfiguration

Services registered with Symfony autoconfiguration may declare:

#[\Small\WorkflowBundle\Attribute\AsWorkflowService('affaire', 'state')]
final class DraftState extends \Small\Workflow\WorkflowState { /* ... */ }

#[\Small\WorkflowBundle\Attribute\AsWorkflowService('affaire', 'guard')]
final class CanSubmit implements \Small\Workflow\WorkflowGuard { /* ... */ }

#[\Small\WorkflowBundle\Attribute\AsWorkflowService('affaire', 'handler', 'submit')]
final class SubmitHandler implements \Small\Workflow\WorkflowActionHandler { /* ... */ }

Supported service types are state, guard, handler, lock, persister, events. The handler key corresponds to the action declared in the workflow YAML file. The existing services / handlers configuration remains supported. Services referenced by attributes must be autoconfigured in the Symfony container.

The compiler pass validates the workflow files, referenced state classes, guard and handler definitions, and resolves the services before the application starts. Missing dependencies and invalid workflows fail container compilation.

Debug command

bin/console workflow:debug
bin/console workflow:debug affaire

Lists declared workflows, states, transitions and their actions without loading business entities.

Symfony lifecycle events

When the Symfony event_dispatcher service exists, workflows without an explicitly configured events: service automatically emit Symfony events named small_workflow.started, small_workflow.completed, and small_workflow.failed. Listeners receive the core Small\\Workflow\\WorkflowEvent object and may inspect getWorkflow(), getTransition(), getAction(), getBefore(), getAfter(), and getPhase().

use Small\\Workflow\\WorkflowEvent;
use Symfony\\Component\\EventDispatcher\\Attribute\\AsEventListener;

final class WorkflowListener
{
    #[AsEventListener(event: 'small_workflow.completed')]
    public function onCompleted(WorkflowEvent $event): void
    {
        if ($event->getWorkflow() !== 'affaire') {
            return;
        }

        // Application follow-up.
    }
}

An explicit events: dispatcher overrides the Symfony integration. Without Symfony's dispatcher service, no default events are published. Listener calls are synchronous, and completed does not guarantee a surrounding database transaction has committed. For durable external effects, use a transactional outbox.