From bfe07dda837252ea7168593f015f6fb6715b3231 Mon Sep 17 00:00:00 2001 From: Carlos Pereira De Amorim Date: Fri, 10 Jul 2020 00:08:44 +0200 Subject: [PATCH] Added Context to Workflow Event There's also a default context for the initial marking event. --- .../Twig/Extension/WorkflowExtension.php | 1 + src/Symfony/Component/Workflow/CHANGELOG.md | 2 + .../Component/Workflow/Event/Event.php | 10 +++- .../Workflow/Event/TransitionEvent.php | 7 --- .../Component/Workflow/Tests/WorkflowTest.php | 54 +++++++++++++++++++ src/Symfony/Component/Workflow/Workflow.php | 49 ++++++++++------- 6 files changed, 95 insertions(+), 28 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Extension/WorkflowExtension.php b/src/Symfony/Bridge/Twig/Extension/WorkflowExtension.php index 1864a1a17f..ea7cd17a8f 100644 --- a/src/Symfony/Bridge/Twig/Extension/WorkflowExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/WorkflowExtension.php @@ -21,6 +21,7 @@ use Twig\TwigFunction; * WorkflowExtension. * * @author Grégoire Pineau + * @author Carlos Pereira De Amorim */ final class WorkflowExtension extends AbstractExtension { diff --git a/src/Symfony/Component/Workflow/CHANGELOG.md b/src/Symfony/Component/Workflow/CHANGELOG.md index 99e1331019..0030f96b83 100644 --- a/src/Symfony/Component/Workflow/CHANGELOG.md +++ b/src/Symfony/Component/Workflow/CHANGELOG.md @@ -5,6 +5,8 @@ CHANGELOG ----- * Added `Workflow::getEnabledTransition()` to easily retrieve a specific transition object + * Added context to the event dispatched + * Added default context to the Initial Marking 5.1.0 ----- diff --git a/src/Symfony/Component/Workflow/Event/Event.php b/src/Symfony/Component/Workflow/Event/Event.php index cda6e170be..e1f448a8b5 100644 --- a/src/Symfony/Component/Workflow/Event/Event.php +++ b/src/Symfony/Component/Workflow/Event/Event.php @@ -19,20 +19,23 @@ use Symfony\Contracts\EventDispatcher\Event as BaseEvent; /** * @author Fabien Potencier * @author Grégoire Pineau + * @author Carlos Pereira De Amorim */ class Event extends BaseEvent { + protected $context; private $subject; private $marking; private $transition; private $workflow; - public function __construct(object $subject, Marking $marking, Transition $transition = null, WorkflowInterface $workflow = null) + public function __construct(object $subject, Marking $marking, Transition $transition = null, WorkflowInterface $workflow = null, array $context = []) { $this->subject = $subject; $this->marking = $marking; $this->transition = $transition; $this->workflow = $workflow; + $this->context = $context; } public function getMarking() @@ -64,4 +67,9 @@ class Event extends BaseEvent { return $this->workflow->getMetadataStore()->getMetadata($key, $subject); } + + public function getContext(): array + { + return $this->context; + } } diff --git a/src/Symfony/Component/Workflow/Event/TransitionEvent.php b/src/Symfony/Component/Workflow/Event/TransitionEvent.php index a38c49030c..4710f90038 100644 --- a/src/Symfony/Component/Workflow/Event/TransitionEvent.php +++ b/src/Symfony/Component/Workflow/Event/TransitionEvent.php @@ -13,15 +13,8 @@ namespace Symfony\Component\Workflow\Event; final class TransitionEvent extends Event { - private $context; - public function setContext(array $context): void { $this->context = $context; } - - public function getContext(): array - { - return $this->context; - } } diff --git a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php index 82543a903e..85543f9286 100644 --- a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php +++ b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php @@ -392,6 +392,7 @@ class WorkflowTest extends TestCase $eventNameExpected = [ 'workflow.entered', 'workflow.workflow_name.entered', + 'workflow.workflow_name.entered.a', 'workflow.guard', 'workflow.workflow_name.guard', 'workflow.workflow_name.guard.t1', @@ -463,6 +464,7 @@ class WorkflowTest extends TestCase $eventNameExpected = [ 'workflow.entered', 'workflow.workflow_name.entered', + 'workflow.workflow_name.entered.a', 'workflow.guard', 'workflow.workflow_name.guard', 'workflow.workflow_name.guard.a-b', @@ -533,6 +535,58 @@ class WorkflowTest extends TestCase $workflow->apply($subject, 't1'); } + public function testEventContext() + { + $definition = $this->createComplexWorkflowDefinition(); + $subject = new Subject(); + $dispatcher = new EventDispatcher(); + $name = 'workflow_name'; + $context = ['context']; + $workflow = new Workflow($definition, new MethodMarkingStore(), $dispatcher, $name); + + $assertWorkflowContext = function (Event $event) use ($context) { + $this->assertEquals($context, $event->getContext()); + }; + + $eventNames = [ + 'workflow.leave', + 'workflow.transition', + 'workflow.enter', + 'workflow.entered', + 'workflow.announce', + ]; + + foreach ($eventNames as $eventName) { + $dispatcher->addListener($eventName, $assertWorkflowContext); + } + + $workflow->apply($subject, 't1', $context); + } + + public function testEventDefaultInitialContext() + { + $definition = $this->createComplexWorkflowDefinition(); + $subject = new Subject(); + $dispatcher = new EventDispatcher(); + $name = 'workflow_name'; + $context = Workflow::DEFAULT_INITIAL_CONTEXT; + $workflow = new Workflow($definition, new MethodMarkingStore(), $dispatcher, $name); + + $assertWorkflowContext = function (Event $event) use ($context) { + $this->assertEquals($context, $event->getContext()); + }; + + $eventNames = [ + 'workflow.workflow_name.entered.a', + ]; + + foreach ($eventNames as $eventName) { + $dispatcher->addListener($eventName, $assertWorkflowContext); + } + + $workflow->apply($subject, 't1'); + } + public function testMarkingStateOnApplyWithEventDispatcher() { $definition = new Definition(range('a', 'f'), [new Transition('t', range('a', 'c'), range('d', 'f'))]); diff --git a/src/Symfony/Component/Workflow/Workflow.php b/src/Symfony/Component/Workflow/Workflow.php index 8895334e55..75e7fe0102 100644 --- a/src/Symfony/Component/Workflow/Workflow.php +++ b/src/Symfony/Component/Workflow/Workflow.php @@ -30,10 +30,12 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; * @author Fabien Potencier * @author Grégoire Pineau * @author Tobias Nyholm + * @author Carlos Pereira De Amorim */ class Workflow implements WorkflowInterface { public const DISABLE_ANNOUNCE_EVENT = 'workflow_disable_announce_event'; + public const DEFAULT_INITIAL_CONTEXT = ['initial' => true]; private $definition; private $markingStore; @@ -51,7 +53,7 @@ class Workflow implements WorkflowInterface /** * {@inheritdoc} */ - public function getMarking(object $subject) + public function getMarking(object $subject, array $context = []) { $marking = $this->markingStore->getMarking($subject); @@ -71,7 +73,11 @@ class Workflow implements WorkflowInterface // update the subject with the new marking $this->markingStore->setMarking($subject, $marking); - $this->entered($subject, null, $marking); + if (!$context) { + $context = self::DEFAULT_INITIAL_CONTEXT; + } + + $this->entered($subject, null, $marking, $context); } // check that the subject has a known place @@ -154,7 +160,7 @@ class Workflow implements WorkflowInterface */ public function apply(object $subject, string $transitionName, array $context = []) { - $marking = $this->getMarking($subject); + $marking = $this->getMarking($subject, $context); $transitionExist = false; $approvedTransitions = []; @@ -197,20 +203,20 @@ class Workflow implements WorkflowInterface } foreach ($approvedTransitions as $transition) { - $this->leave($subject, $transition, $marking); + $this->leave($subject, $transition, $marking, $context); $context = $this->transition($subject, $transition, $marking, $context); - $this->enter($subject, $transition, $marking); + $this->enter($subject, $transition, $marking, $context); $this->markingStore->setMarking($subject, $marking, $context); - $this->entered($subject, $transition, $marking); + $this->entered($subject, $transition, $marking, $context); - $this->completed($subject, $transition, $marking); + $this->completed($subject, $transition, $marking, $context); if (!($context[self::DISABLE_ANNOUNCE_EVENT] ?? false)) { - $this->announce($subject, $transition, $marking); + $this->announce($subject, $transition, $marking, $context); } } @@ -324,12 +330,12 @@ class Workflow implements WorkflowInterface return $event; } - private function leave(object $subject, Transition $transition, Marking $marking): void + private function leave(object $subject, Transition $transition, Marking $marking, array $context = []): void { $places = $transition->getFroms(); if (null !== $this->dispatcher) { - $event = new LeaveEvent($subject, $marking, $transition, $this); + $event = new LeaveEvent($subject, $marking, $transition, $this, $context); $this->dispatcher->dispatch($event, WorkflowEvents::LEAVE); $this->dispatcher->dispatch($event, sprintf('workflow.%s.leave', $this->name)); @@ -350,8 +356,7 @@ class Workflow implements WorkflowInterface return $context; } - $event = new TransitionEvent($subject, $marking, $transition, $this); - $event->setContext($context); + $event = new TransitionEvent($subject, $marking, $transition, $this, $context); $this->dispatcher->dispatch($event, WorkflowEvents::TRANSITION); $this->dispatcher->dispatch($event, sprintf('workflow.%s.transition', $this->name)); @@ -360,12 +365,12 @@ class Workflow implements WorkflowInterface return $event->getContext(); } - private function enter(object $subject, Transition $transition, Marking $marking): void + private function enter(object $subject, Transition $transition, Marking $marking, array $context): void { $places = $transition->getTos(); if (null !== $this->dispatcher) { - $event = new EnterEvent($subject, $marking, $transition, $this); + $event = new EnterEvent($subject, $marking, $transition, $this, $context); $this->dispatcher->dispatch($event, WorkflowEvents::ENTER); $this->dispatcher->dispatch($event, sprintf('workflow.%s.enter', $this->name)); @@ -380,13 +385,13 @@ class Workflow implements WorkflowInterface } } - private function entered(object $subject, ?Transition $transition, Marking $marking): void + private function entered(object $subject, ?Transition $transition, Marking $marking, array $context): void { if (null === $this->dispatcher) { return; } - $event = new EnteredEvent($subject, $marking, $transition, $this); + $event = new EnteredEvent($subject, $marking, $transition, $this, $context); $this->dispatcher->dispatch($event, WorkflowEvents::ENTERED); $this->dispatcher->dispatch($event, sprintf('workflow.%s.entered', $this->name)); @@ -395,29 +400,33 @@ class Workflow implements WorkflowInterface foreach ($transition->getTos() as $place) { $this->dispatcher->dispatch($event, sprintf('workflow.%s.entered.%s', $this->name, $place)); } + } elseif (!empty($this->definition->getInitialPlaces())) { + foreach ($this->definition->getInitialPlaces() as $place) { + $this->dispatcher->dispatch($event, sprintf('workflow.%s.entered.%s', $this->name, $place)); + } } } - private function completed(object $subject, Transition $transition, Marking $marking): void + private function completed(object $subject, Transition $transition, Marking $marking, array $context): void { if (null === $this->dispatcher) { return; } - $event = new CompletedEvent($subject, $marking, $transition, $this); + $event = new CompletedEvent($subject, $marking, $transition, $this, $context); $this->dispatcher->dispatch($event, WorkflowEvents::COMPLETED); $this->dispatcher->dispatch($event, sprintf('workflow.%s.completed', $this->name)); $this->dispatcher->dispatch($event, sprintf('workflow.%s.completed.%s', $this->name, $transition->getName())); } - private function announce(object $subject, Transition $initialTransition, Marking $marking): void + private function announce(object $subject, Transition $initialTransition, Marking $marking, array $context): void { if (null === $this->dispatcher) { return; } - $event = new AnnounceEvent($subject, $marking, $initialTransition, $this); + $event = new AnnounceEvent($subject, $marking, $initialTransition, $this, $context); $this->dispatcher->dispatch($event, WorkflowEvents::ANNOUNCE); $this->dispatcher->dispatch($event, sprintf('workflow.%s.announce', $this->name));