More than a handful of times have people asked me how to use the workflow component when doing domain driven design. Im no expert but I think this should be documented and this is how I imagine one solve the problem.
In DDD the models should know everything about themselves. Ie the BlogPost entity should have the information about what the places and transitions are.
namespace App\Entity;
class BlogPost {
// getters and setters
public static function getWorkflowDefinition()
{
$definitionBuilder = new DefinitionBuilder();
$definition = $definitionBuilder->addPlaces(['draft', 'published', 'trashed'])
->addTransition(new Transition('publish', 'draft', 'published'))
->addTransition(new Transition('trash', 'published', 'trashed'))
->build();
return $definition;
}
}
Then we create a generic factory like:
namespace App\Workflow;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Workflow\MarkingStore\MultipleStateMarkingStore;
use Symfony\Component\Workflow\Validator\WorkflowValidator;
use Symfony\Component\Workflow\Workflow;
class WorkflowFactory
{
private $eventDispatcher;
public function __construct(EventDispatcherInterface $eventDispatcher)
{
$this->eventDispatcher = $eventDispatcher;
}
public function create(callable $fetcher, $name)
{
$definition = $fetcher();
(new WorkflowValidator())->validate($definition, $name);
$marking = new MultipleStateMarkingStore('state');
return new Workflow($definition, $marking, $this->eventDispatcher, $name);
}
}
Now we can register workflow as services like:
App\Workflow\WorkflowFactory:
arguments: ['@event_dispatcher']
workflow.blog_post:
class: Symfony\Component\Workflow\Workflow
factory: ['@App\Workflow\WorkflowFactory', 'create']
arguments: [['App\Entity\BlogPost', 'getWorkflowDefinition'], 'blog_post']
# Other workflows can use the same factory
workflow.acme:
class: Symfony\Component\Workflow\Workflow
factory: ['@App\Workflow\WorkflowFactory', 'create']
arguments: [['App\Entity\Acme', 'getWorkflowDefinition'], 'acme']
This sounds like a cool cookbook entry 馃憤
@OskarStark I'm afraid we can't add something like this to docs. First, because it talks about a particular architecture (DDD) that we never show or explain in the docs. Second, because none of the doc maintainers know DDD, so this doc would never be maintained or fixed.
I'm really sorry, but I must close this without merging because of the given reasons. Thanks for understanding!
Thank you for the feedback Javier.
I think the correct action now is to write a blog post about this. I'll try to do it before the end of the month.
馃憤
I just published the article: http://developer.happyr.com/symfony-state-machines-and-domain-driven-design
Most helpful comment
I just published the article: http://developer.happyr.com/symfony-state-machines-and-domain-driven-design