10000 [Workflow] Cleaned the transition blocker implementations · symfony/symfony@2b8faff · GitHub
[go: up one dir, main page]

Skip to content

Commit 2b8faff

Browse files
committed
[Workflow] Cleaned the transition blocker implementations
1 parent 4d10e10 commit 2b8faff

File tree

9 files changed

+246
-336
lines changed

9 files changed

+246
-336
lines changed

src/Symfony/Component/Workflow/Event/GuardEvent.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,18 @@ public function __construct($subject, Marking $marking, Transition $transition,
3636

3737
public function isBlocked(): bool
3838
{
39-
return 0 !== count($this->transitionBlockerList);
39+
return !$this->transitionBlockerList->isEmpty();
4040
}
4141

4242
public function setBlocked(bool $blocked): void
4343
{
4444
if (!$blocked) {
45-
$this->transitionBlockerList = new TransitionBlockerList();
45+
$this->transitionBlockerList->reset();
4646

4747
return;
4848
}
4949

50-
$this->transitionBlockerList->add(TransitionBlocker::createUnknownReason($this->getTransition()->getName()));
50+
$this->transitionBlockerList->add(TransitionBlocker::createUnknown());
5151
}
5252

5353
public function getTransitionBlockerList(): TransitionBlockerList

src/Symfony/Component/Workflow/EventListener/GuardListener.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Symfony\Component\Validator\Validator\ValidatorInterface;
1919
use Symfony\Component\Workflow\Event\GuardEvent;
2020
use Symfony\Component\Workflow\Exception\InvalidTokenConfigurationException;
21+
use Symfony\Component\Workflow\TransitionBlocker;
2122

2223
/**
2324
* @author Grégoire Pineau <lyrixx@lyrixx.info>
@@ -49,8 +50,11 @@ public function onTransition(GuardEvent $event, $eventName)
4950
return;
5051
}
5152

52-
if (!$this->expressionLanguage->evaluate($this->configuration[$eventName], $this B41A ->getVariables($event))) {
53-
$event->setBlocked(true);
53+
$expression = $this->configuration[$eventName];
54+
55+
if (!$this->expressionLanguage->evaluate($expression, $this->getVariables($event))) {
56+
$blocker = TransitionBlocker::createBlockedByExpressionGuardListener($expression);
57+
$event->addTransitionBlocker($blocker);
5458
}
5559
}
5660

src/Symfony/Component/Workflow/Exception/BlockedTransitionException.php renamed to src/Symfony/Component/Workflow/Exception/NotEnabledTransitionException.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,17 @@
1414
use Symfony\Component\Workflow\TransitionBlockerList;
1515

1616
/**
17-
* Thrown by the workflow when a transition is not enabled.
17+
* Thrown by Workflow when a not enabled transition is applied on a subject.
18+
*
19+
* @author Grégoire Pineau <lyrixx@lyrixx.info>
1820
*/
19-
class BlockedTransitionException extends LogicException
21+
class NotEnabledTransitionException extends LogicException
2022
{
2123
private $transitionBlockerList;
2224

23-
public function __construct(string $message, TransitionBlockerList $transitionBlockerList)
25+
public function __construct(string $transitionName, string $workflowName, TransitionBlockerList $transitionBlockerList)
2426
{
25-
parent::__construct($message);
27+
parent::__construct(sprintf('Transition "%s" is not enabled for workflow "%s".', $transitionName, $workflowName));
2628

2729
$this->transitionBlockerList = $transitionBlockerList;
2830
}

src/Symfony/Component/Workflow/Exception/UndefinedTransitionException.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,13 @@
1313

1414
/**
1515
* Thrown by Workflow when an undefined transition is applied on a subject.
16+
*
17+
* @author Grégoire Pineau <lyrixx@lyrixx.info>
1618
*/
1719
class UndefinedTransitionException extends LogicException
1820
{
21+
public function __construct(string $transitionName, string $workflowName)
22+
{
23+
parent::__construct(sprintf('Transition "%s" is not defined for workflow "%s".', $transitionName, $workflowName));
24+
}
1925
}

src/Symfony/Component/Workflow/Tests/WorkflowTest.php

Lines changed: 93 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use Symfony\Component\Workflow\Definition;
88
use Symfony\Component\Workflow\Event\Event;
99
use Symfony\Component\Workflow\Event\GuardEvent;
10-
use Symfony\Component\Workflow\Exception\BlockedTransitionException;
10+
use Symfony\Component\Workflow\Exception\NotEnabledTransitionException;
1111
use Symfony\Component\Workflow\Marking;
1212
use Symfony\Component\Workflow\MarkingStore\MarkingStoreInterface;
1313
use Symfony\Component\Workflow\MarkingStore\MultipleStateMarkingStore;
@@ -164,35 +164,114 @@ public function testCanDoesNotTriggerGuardEventsForNotEnabledTransitions()
164164
$this->assertSame(array('workflow_name.guard.t3'), $dispatchedEvents);
165165
}
166166

167+
public function testCanWithSameNameTransition()
168+
{
169+
$definition = $this->createWorkflowWithSameNameTransition();
170+
$workflow = new Workflow($definition, new MultipleStateMarkingStore());
171+
172+
$subject = new \stdClass();
173+
$subject->marking = null;
174+
$this->assertTrue($workflow->can($subject, 'a_to_bc'));
175+
$this->assertFalse($workflow->can($subject, 'b_to_c'));
176+
$this->assertFalse($workflow->can($subject, 'to_a'));
177+
178+
$subject->marking = array('b' => 1);
179+
$this->assertFalse($workflow->can($subject, 'a_to_bc'));
180+
$this->assertTrue($workflow->can($subject, 'b_to_c'));
181+
$this->assertTrue($workflow->can($subject, 'to_a'));
182+
}
183+
167184
/**
168-
* @expectedException \Symfony\Component\Workflow\Exception\LogicException
169-
* @expectedExceptionMessage Unable to apply transition "t2" for workflow "unnamed".
185+
* @expectedException \Symfony\Component\Workflow\Exception\UndefinedTransitionException
186+
* @expectedExceptionMessage Transition "404 Not Found" is not defined for workflow "unnamed".
170187
*/
171-
public function testApplyWithImpossibleTransition()
188+
public function testBuildTransitionBlockerListReturnsUndefinedTransition()
189+
{
190+
$definition = $this->createSimpleWorkflowDefinition();
191+
$subject = new \stdClass();
192+
$subject->marking = null;
193+
$workflow = new Workflow($definition);
194+
195+
$workflow->buildTransitionBlockerList($subject, '404 Not Found');
196+
}
197+
198+
public function testBuildTransitionBlockerListReturnsReasonsProvidedByMarking()
172199
{
173200
$definition = $this->createComplexWorkflowDefinition();
174201
$subject = new \stdClass();
175202
$subject->marking = null;
176203
$workflow = new Workflow($definition, new MultipleStateMarkingStore());
177204

178-
$workflow->apply($subject, 't2');
205+
$transitionBlockerList = $workflow->buildTransitionBlockerList($subject, 't2');
206+
$this->assertCount(1, $transitionBlockerList);
207+
$blockers = iterator_to_array($transitionBlockerList);
208+
$this->assertSame('The marking does not enable the transition.', $blockers[0]->getMessage());
209+
$this->assertSame('19beefc8-6b1e-4716-9d07-a39bd6d16e34', $blockers[0]->getCode());
179210
}
180211

181-
public function testCanWithSameNameTransition()
212+
public function testBuildTransitionBlockerListReturnsReasonsProvidedInGuards()
182213
{
183-
$definition = $this->createWorkflowWithSameNameTransition();
214+
$definition = $this->createSimpleWorkflowDefinition();
215+
$subject = new \stdClass();
216+
$subject->marking = null;
217+
$dispatcher = new EventDispatcher();
218+
$workflow = new Workflow($definition, new MultipleStateMarkingStore(), $dispatcher);
219+
220+
$dispatcher->addListener('workflow.guard', function (GuardEvent $event) {
221+
$event->addTransitionBlocker(new TransitionBlocker('Transition blocker 1', 'blocker_1'));
222+
$event->addTransitionBlocker(new TransitionBlocker('Transition blocker 2', 'blocker_2'));
223+
});
224+
$dispatcher->addListener('workflow.guard', function (GuardEvent $event) {
225+
$event->addTransitionBlocker(new TransitionBlocker('Transition blocker 3', 'blocker_3'));
226+
});
227+
$dispatcher->addListener('workflow.guard', function (GuardEvent $event) {
228+
$event->setBlocked(true);
229+
});
230+
231+
$transitionBlockerList = $workflow->buildTransitionBlockerList($subject, 't1');
232+
$this->assertCount(4, $transitionBlockerList);
233+
$blockers = iterator_to_array($transitionBlockerList);
234+
$this->assertSame('Transition blocker 1', $blockers[0]->getMessage());
235+
$this->assertSame('blocker_1', $blockers[0]->getCode());
236+
$this->assertSame('Transition blocker 2', $blockers[1]->getMessage());
237+
$this->assertSame('blocker_2', $blockers[1]->getCode());
238+
$this->assertSame('Transition blocker 3', $blockers[2]->getMessage());
239+
$this->assertSame('blocker_3', $blockers[2]->getCode());
240+
$this->assertSame('Unknown reason.', $blockers[3]->getMessage());
241+
$this->assertSame('e8b5bbb9-5913-4b98-bfa6-65dbd228a82a', $blockers[3]->getCode());
242+
}
243+
244+
/**
245+
* @expectedException \Symfony\Component\Workflow\Exception\UndefinedTransitionException
246+
* @expectedExceptionMessage Transition "404 Not Found" is not defined for workflow "unnamed".
247+
*/
248+
public function testApplyWithNotExisingTransition()
< F438 /td>
249+
{
250+
$definition = $this->createComplexWorkflowDefinition();
251+
$subject = new \stdClass();
252+
$subject->marking = null;
184253
$workflow = new Workflow($definition, new MultipleStateMarkingStore());
185254

255+
$workflow->apply($subject, '404 Not Found');
256+
}
257+
258+
public function testApplyWithNotEnabledTransition()
259+
{
260+
$definition = $this->createComplexWorkflowDefinition();
186261
$subject = new \stdClass();
187262
$subject->marking = null;
188-
$this->assertTrue($workflow->can($subject, 'a_to_bc'));
189-
$this->assertFalse($workflow->can($subject, 'b_to_c'));
190-
$this->assertFalse($workflow->can($subject, 'to_a'));
263+
$workflow = new Workflow($definition, new MultipleStateMarkingStore());
191264

192-
$subject->marking = array('b' => 1);
193-
$this->assertFalse($workflow->can($subject, 'a_to_bc'));
194-
$this->assertTrue($workflow->can($subject, 'b_to_c'));
195-
$this->assertTrue($workflow->can($subject, 'to_a'));
265+
try {
266+
$workflow->apply($subject, 't2');
267+
268+
$this->fail('Should throw an exception');
269+
} catch (NotEnabledTransitionException $e) {
270+
$this->assertSame('Transition "t2" is not enabled for workflow "unnamed".', $e->getMessage());
271+
$this->assertCount(1, $e->getTransitionBlockerList());
272+
$list = iterator_to_array($e->getTransitionBlockerList());
273+
$this->assertSame('The marking does not enable the transition.', $list[0]->getMessage());
274+
}
196275
}
197276

198277
public function testApply()
@@ -413,116 +492,6 @@ public function testGetEnabledTransitionsWithSameNameTransition()
413492
$this->assertSame('to_a', $transitions[1]->getName());
414493
$this->assertSame('to_a', $transitions[2]->getName());
415494
}
416-
417-
public function testWhyCannotReturnsReasonsProvidedInGuards()
418-
{
419-
$definition = $this->createSimpleWorkflowDefinition();
420-
$subject = new \stdClass();
421-
$subject->marking = null;
422-
$dispatcher = new EventDispatcher();
423-
$workflow = new Workflow($definition, new MultipleStateMarkingStore(), $dispatcher);
424-
425-
$guardsAddingTransitionBlockers = array(
426-
function (GuardEvent $event) {
427-
$event->addTransitionBlocker(new TransitionBlocker('Transition blocker 1', 'blocker_1'));
428-
$event->addTransitionBlocker(new TransitionBlocker('Transition blocker 2', 'blocker_2'));
429-
},
430-
function (GuardEvent $event) {
431-
$event->addTransitionBlocker(new TransitionBlocker('Transition blocker 3', 'blocker_3'));
432-
},
433-
);
434-
435-
foreach ($guardsAddingTransitionBlockers as $guard) {
436-
$dispatcher->addListener('workflow.guard', $guard);
437-
}
438-
439-
$transitionBlockerList = $workflow->buildTransitionBlockerList($subject, 't1');
440-
441-
$this->assertCount(3, $transitionBlockerList);
442-
443-
$assertTransitionBlockerPresentByCodeFn = function (string $code) use ($transitionBlockerList) {
444-
$this->assertNotNull(
445-
$transitionBlockerList->findByCode($code),
446-
sprintf('Workflow did not produce transition blocker with code "%s"', $code)
447-
);
448-
};
449-
450-
$assertTransitionBlockerPresentByCodeFn('blocker_1');
451-
$assertTransitionBlockerPresentByCodeFn('blocker_2');
452-
$assertTransitionBlockerPresentByCodeFn('blocker_3');
453-
}
454-
455-
public function testWhyCannotReturnsTransitionNotDefinedReason()
456-
{
457-
$definition = $this->createSimpleWorkflowDefinition();
458-
$subject = new \stdClass();
459-
$subject->marking = null;
460-
$workflow = new Workflow($definition);
461-
462-
$transitionBlockerList = $workflow->buildTransitionBlockerList($subject, 'undefined_transition_name');
463-
464-
$this->assertCount(1, $transitionBlockerList);
465-
$this->assertEquals(
466-
TransitionBlocker::REASON_TRANSITION_NOT_DEFINED,
467-
$transitionBlockerList->get(0)->getCode()
468-
);
469-
}
470-
471-
public function testWhyCannotReturnsTransitionNotApplicableReason()
472-
{
473-
$definition = $this->createSimpleWorkflowDefinition();
474-
$subject = new \stdClass();
475-
$subject->marking = null;
476-
$workflow = new Workflow($definition);
477-
478-
$transitionBlockerList = $workflow->buildTransitionBlockerList($subject, 't2');
479-
480-
$this->assertCount(1, $transitionBlockerList);
481-
$this->assertEquals(
482-
TransitionBlocker::REASON_TRANSITION_NOT_APPLICABLE,
483-
$transitionBlockerList->get(0)->getCode()
484-
);
485-
}
486-
487-
public function testApplyConveysTheTransitionBlockers()
488-
{
489-
$definition = $this->createSimpleWorkflowDefinition();
490-
$subject = new \stdClass();
491-
$subject->marking = null;
492-
$dispatcher = new EventDispatcher();
493-
$workflow = new Workflow($definition, new MultipleStateMarkingStore(), $dispatcher);
494-
495-
$dispatcher->addListener('workflow.guard', function (GuardEvent $event) {
496-
$event->addTransitionBlocker(new TransitionBlocker('Transition blocker 3', 'blocker_1'));
497-
});
498-
499-
try {
500-
$workflow->apply($subject, 't1');
501-
} catch (BlockedTransitionException $exception) {
502-
$this->assertNotNull(
503-
$exception->getTransitionBlockerList()->findByCode('blocker_1'),
504-
'Workflow failed to convey it could not transition subject because of expected blocker'
505-
);
506-
507-
return;
508-
}
509-
510-
$this->fail('Workflow failed to prevent a transition from happening');
511-
}
512-
513-
/**
514-
* @expectedException \Symfony\Component\Workflow\Exception\UndefinedTransitionException
515-
* @expectedExceptionMessage Transition "undefined_transition" is not defined in workflow "unnamed".
516-
*/
517-
public function testApplyWithUndefinedTransition()
518-
{
519-
$definition = $this->createSimpleWorkflowDefinition();
520-
$subject = new \stdClass();
521-
$subject->marking = null;
522-
$workflow = new Workflow($definition);
523-
524-
$workflow->apply($subject, 'undefined_transition');
525-
}
526495
}
527496

528497
class EventDispatcherMock implements \Symfony\Component\EventDispatcher\EventDispatcherInterface

0 commit comments

Comments
 (0)
0