aboutcoders/workflow-bundle
Symfony bundle to define and manage workflows with optional GUI. Provides routing and ORM configuration, Twig helpers to render workflow configuration and history, and an AJAX endpoint to fetch execution history. Integrates with KnpMenuBundle and JobBundle.
Installation
composer require aboutcoders/workflow-bundle:dev-master
Ensure Abc\Bundle\WorkflowBundle\AbcWorkflowBundle is registered in AppKernel.php.
Routing
Add to app/config/routing.yml:
abc_workflow_tasks:
resource: "@AbcWorkflowBundle/Resources/config/routing.yml"
prefix: /
Optionally, include the GUI routes:
abc_workflow_workflows:
resource: "@AbcWorkflowBundle/Resources/config/routing_optional.yml"
prefix: /
Configuration
Define workflows in YAML (e.g., app/config/config.yml):
abc_workflow:
db_driver: orm
workflows:
my_workflow:
supports: App\Entity\MyEntity
places: [draft, published, archived]
transitions:
- { from: draft, to: published }
- { from: published, to: archived }
First Use Case Inject the workflow service in a controller:
use Abc\Bundle\WorkflowBundle\Workflow\WorkflowService;
public function __construct(WorkflowService $workflowService) {
$this->workflowService = $workflowService;
}
public function publishAction(MyEntity $entity) {
$this->workflowService->apply($entity, 'publish');
return new Response('Published!');
}
Annotate Entities
Use the @Workflow annotation to define workflow support:
use Abc\Bundle\WorkflowBundle\Annotation\Workflow;
/**
* @Workflow("my_workflow")
*/
class MyEntity {}
Service Integration
Use the WorkflowService to manage transitions:
// Apply a transition
$workflowService->apply($entity, 'publish');
// Check current place
$currentPlace = $workflowService->getCurrentPlace($entity);
// Check allowed transitions
$allowedTransitions = $workflowService->getAllowedTransitions($entity);
Event Listeners
Listen to workflow events (e.g., WorkflowTransitionEvent):
use Abc\Bundle\WorkflowBundle\Event\WorkflowTransitionEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class WorkflowSubscriber implements EventSubscriberInterface {
public static function getSubscribedEvents() {
return [
'workflow.transition' => 'onTransition',
];
}
public function onTransition(WorkflowTransitionEvent $event) {
// Handle transition logic (e.g., send notifications)
}
}
Display Workflow Configuration Use the Twig extension in templates:
{{ workflow_configuration(entity) }}
Show Workflow History
{{ workflow_history(entity) }}
AJAX History Fetching
Use the execution_history route to fetch history dynamically:
{{ path('execution_history', { 'entity': entity.id }) }}
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class BulkPublishCommand extends Command {
protected function execute(InputInterface $input, OutputInterface $output) {
$entities = $entityManager->getRepository(MyEntity::class)->findAll();
foreach ($entities as $entity) {
$this->workflowService->apply($entity, 'publish');
}
$output->writeln('Published all entities!');
}
}
Missing Dependencies
KnpMenuBundle and AbcJobBundle are installed and configured as per their docs. The workflow GUI relies on these.Incorrect Workflow Configuration
places or transitions will cause runtime errors.transitions:
- { from: draft, to: publish } # Missing 'ed' in 'published'
Entity Not Annotated
@Workflow, the bundle will ignore it. Double-check annotations or service configuration.Database Driver Mismatch
db_driver is set to orm but your entities aren’t Doctrine-aware, transitions won’t persist. Ensure AbcWorkflowBundle is loaded after DoctrineBundle in AppKernel.php.Circular Dependencies in Transitions
draft → published → draft). The bundle doesn’t enforce this, but it can cause infinite loops in logic.Enable Debug Mode Symfony’s debug toolbar will show workflow-related events under the "Events" tab.
Log Workflow Transitions Add a subscriber to log transitions:
public function onTransition(WorkflowTransitionEvent $event) {
$this->logger->info(
sprintf('Transitioned %s from %s to %s',
get_class($event->getEntity()),
$event->getTransition()->getFrom(),
$event->getTransition()->to
)
);
}
Check Workflow Service Methods Use these methods to inspect state:
$workflowService->getCurrentPlace($entity); // Current state
$workflowService->getAllowedTransitions($entity); // Valid next steps
$workflowService->getHistory($entity); // Full history
Custom Transition Guards
Override transition logic by implementing Abc\Bundle\WorkflowBundle\Guard\GuardInterface:
class CustomGuard implements GuardInterface {
public function checkTransition($entity, Transition $transition) {
// Custom logic (e.g., check user permissions)
return true;
}
}
Register it in services.yml:
abc_workflow.guard.custom:
class: App\Guard\CustomGuard
tags:
- { name: abc_workflow.guard, priority: 10 }
Custom Workflow Storage
Extend the bundle’s storage layer by implementing Abc\Bundle\WorkflowBundle\Storage\WorkflowStorageInterface for non-Doctrine ORMs.
Twig Extensions
Override or extend the Twig functions (e.g., workflow_configuration) by creating a custom Twig extension:
class CustomWorkflowExtension extends \Twig_Extension {
public function getFunctions() {
return [
new \Twig_SimpleFunction('custom_workflow_config', [$this, 'renderCustomConfig']),
];
}
}
Event Dispatching Extend the bundle’s event system by listening to:
workflow.transition (after transition)workflow.place_entered (when entering a place)workflow.place_exited (when leaving a place)Avoid Heavy Logic in Guards Transition guards should be lightweight. Offload complex logic to services called from guards.
Batch Processing
For bulk operations, use Doctrine’s EntityManager::clear() to reduce memory usage:
$em = $this->getDoctrine()->getManager();
foreach ($entities as $entity) {
$workflowService->apply($entity, 'publish');
if ($i % 20 === 0) { // Batch every 20 entities
$em->clear();
}
$i++;
}
Caching Workflow Metadata If workflows rarely change, cache the configuration in a service to avoid re-parsing YAML on every request.
How can I help you explore Laravel packages today?