letots/workflow-extension-bundle

Configurations to allow defining Symfony Workflows as PHP classes easily and little helpers functions to work with them.

Maintainers

Package info

github.com/letots/workflow-extension-bundle

pkg:composer/letots/workflow-extension-bundle

Statistics

Installs: 60

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 1

0.1.3 2026-05-30 13:20 UTC

This package is auto-updated.

Last update: 2026-05-30 13:21:09 UTC


README

Define Symfony Workflows as PHP classes using attributes, with helpers to work with them.

Workflow class

#[AsWorkflow(name: 'order', type: AsWorkflow::TYPE_STATE_MACHINE)]
class OrderWorkflow extends AbstractWorkflow
{
    public const PLACE_NEW = 'new';

    #[Place(initial: true)]
    public const PLACE_DRAFT = 'draft';

    #[Transition(from: self::PLACE_DRAFT, to: self::PLACE_NEW)]
    public const TRANSITION_PUBLISH = 'publish';
}

Inject the workflow by name:

public function __construct(
    private WorkflowInterface $order,
) {}

Or use the alias workflow.order.

Transitions

  • #[Transition] must be placed on a class constant. The constant value is the transition name.
  • In TYPE_STATE_MACHINE, each constant declares a single arc: one from place and one to place.
  • To reach the same destination from several places, declare several constants with the same transition name (same constant value), each with its own from place.
#[Transition(from: self::PLACE_DRAFT, to: self::PLACE_NEW)]
public const TRANSITION_PUBLISH = 'publish';

#[Transition(from: self::PLACE_REVIEW, to: self::PLACE_NEW)]
public const TRANSITION_PUBLISH_FROM_REVIEW = 'publish';

In TYPE_WORKFLOW, from and to may be arrays for multi-place transitions.

Metadata

Metadata can be attached to the workflow, places, and transitions. Retrieve it via $workflow->getMetadataStore() (same API as Symfony YAML workflows).

#[AsWorkflow(name: 'order', metadata: ['title' => 'Order workflow'])]
class OrderWorkflow extends AbstractWorkflow
{
    #[Place(initial: true, metadata: ['title' => 'Draft'])]
    public const PLACE_DRAFT = 'draft';

    #[Transition(from: self::PLACE_DRAFT, to: self::PLACE_NEW, metadata: ['title' => 'Publish'])]
    public const TRANSITION_PUBLISH = 'publish';
}

Audit trail

Enable workflow activity logging (requires the logger service, channel workflow):

#[AsWorkflow(name: 'order', auditTrail: true)]
class OrderWorkflow extends AbstractWorkflow
{
}

Guards

Guards are standard Symfony workflow guard listeners. The bundle injects the application event_dispatcher into each workflow service so guard events are dispatched.

#[AsEventListener(event: 'workflow.order.guard')]
public function onGuard(GuardEvent $event): void
{
    if ($event->getTransitionName() === 'publish' && !$this->authorizationChecker->isGranted('ROLE_ADMIN')) {
        $event->setBlocked(true, 'Not allowed.');
    }
}

Replace order with the workflow name from #[AsWorkflow(name: '...')].

Registry

When using supportStrategy with a class name string, the bundle registers an InstanceOfSupportStrategy automatically:

#[AsWorkflow(name: 'order', supportStrategy: Order::class)]
class OrderWorkflow extends AbstractWorkflow
{
}