Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 28cd88e

Browse files
committed
bug #29141 [Workflow] Fixed bug of buildTransitionBlockerList when many transition are enabled (Tetragramat, lyrixx)
This PR was merged into the 4.1 branch. Discussion ---------- [Workflow] Fixed bug of buildTransitionBlockerList when many transition are enabled | Q | A | ------------- | --- | Branch? | 4.1 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #28429 #28432 #28493 | License | MIT | Doc PR | <!-- Write a short README entry for your feature/bugfix here (replace this comment block.) This will help people understand your PR and can be used as a start of the Doc PR. Additionally: - Bug fixes must be submitted against the lowest branch where they apply (lowest branches are regularly merged to upper ones so they get the fixes too). - Features and deprecations must be submitted against the master branch. --> Commits ------- 732f343 [Workflow] Made code simpler db69ccc method buildTransitionBlockerList returns TransitionBlockerList of expected transition
2 parents ab9b40d + 732f343 commit 28cd88e

File tree

4 files changed

+115
-1
lines changed

4 files changed

+115
-1
lines changed

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

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
namespace Symfony\Component\Workflow\Tests;
44

55
use PHPUnit\Framework\TestCase;
6+
use Symfony\Component\EventDispatcher\EventDispatcher;
7+
use Symfony\Component\Workflow\Event\GuardEvent;
68
use Symfony\Component\Workflow\StateMachine;
9+
use Symfony\Component\Workflow\TransitionBlocker;
710

811
class StateMachineTest extends TestCase
912
{
@@ -38,4 +41,70 @@ public function testCanWithMultipleTransition()
3841
$this->assertTrue($net->can($subject, 't2'));
3942
$this->assertTrue($net->can($subject, 't3'));
4043
}
44+
45+
public function testBuildTransitionBlockerList()
46+
{
47+
$definition = $this->createComplexStateMachineDefinition();
48+
49+
$net = new StateMachine($definition);
50+
$subject = new \stdClass();
51+
52+
$subject->marking = 'a';
53+
$this->assertTrue($net->buildTransitionBlockerList($subject, 't1')->isEmpty());
54+
$subject->marking = 'd';
55+
$this->assertTrue($net->buildTransitionBlockerList($subject, 't1')->isEmpty());
56+
57+
$subject->marking = 'b';
58+
$this->assertFalse($net->buildTransitionBlockerList($subject, 't1')->isEmpty());
59+
}
60+
61+
public function testBuildTransitionBlockerListWithMultipleTransitions()
62+
{
63+
$definition = $this->createComplexStateMachineDefinition();
64+
65+
$net = new StateMachine($definition);
66+
$subject = new \stdClass();
67+
68+
$subject->marking = 'b';
69+
$this->assertTrue($net->buildTransitionBlockerList($subject, 't2')->isEmpty());
70+
$this->assertTrue($net->buildTransitionBlockerList($subject, 't3')->isEmpty());
71+
}
72+
73+
public function testBuildTransitionBlockerListReturnsExpectedReasonOnBranchMerge()
74+
{
75+
$definition = $this->createComplexStateMachineDefinition();
76+
77+
$dispatcher = new EventDispatcher();
78+
$net = new StateMachine($definition, null, $dispatcher);
79+
80+
$dispatcher->addListener('workflow.guard', function (GuardEvent $event) {
81+
$event->addTransitionBlocker(new TransitionBlocker(\sprintf('Transition blocker of place %s', $event->getTransition()->getFroms()[0]), 'blocker'));
82+
});
83+
84+
$subject = new \stdClass();
85+
86+
// There may be multiple transitions with the same name. Make sure that transitions
87+
// that are not enabled by the marking are evaluated.
88+
// see https://github.com/symfony/symfony/issues/28432
89+
90+
// Test if when you are in place "a"trying transition "t1" then returned
91+
// blocker list contains guard blocker instead blockedByMarking
92+
$subject->marking = 'a';
93+
$transitionBlockerList = $net->buildTransitionBlockerList($subject, 't1');
94+
$this->assertCount(1, $transitionBlockerList);
95+
$blockers = iterator_to_array($transitionBlockerList);
96+
97+
$this->assertSame('Transition blocker of place a', $blockers[0]->getMessage());
98+
$this->assertSame('blocker', $blockers[0]->getCode());
99+
100+
// Test if when you are in place "d" trying transition "t1" then
101+
// returned blocker list contains guard blocker instead blockedByMarking
102+
$subject->marking = 'd';
103+
$transitionBlockerList = $net->buildTransitionBlockerList($subject, 't1');
104+
$this->assertCount(1, $transitionBlockerList);
105+
$blockers = iterator_to_array($transitionBlockerList);
106+
107+
$this->assertSame('Transition blocker of place d', $blockers[0]->getMessage());
108+
$this->assertSame('blocker', $blockers[0]->getCode());
109+
}
41110
}

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,32 @@ public function testBuildTransitionBlockerListReturnsUndefinedTransition()
195195
$workflow->buildTransitionBlockerList($subject, '404 Not Found');
196196
}
197197

198+
public function testBuildTransitionBlockerList()
199+
{
200+
$definition = $this->createComplexWorkflowDefinition();
201+
$subject = new \stdClass();
202+
$subject->marking = null;
203+
$workflow = new Workflow($definition, new MultipleStateMarkingStore());
204+
205+
$this->assertTrue($workflow->buildTransitionBlockerList($subject, 't1')->isEmpty());
206+
$this->assertFalse($workflow->buildTransitionBlockerList($subject, 't2')->isEmpty());
207+
208+
$subject->marking = array('b' => 1);
209+
210+
$this->assertFalse($workflow->buildTransitionBlockerList($subject, 't1')->isEmpty());
211+
$this->assertFalse($workflow->buildTransitionBlockerList($subject, 't2')->isEmpty());
212+
213+
$subject->marking = array('b' => 1, 'c' => 1);
214+
215+
$this->assertFalse($workflow->buildTransitionBlockerList($subject, 't1')->isEmpty());
216+
$this->assertTrue($workflow->buildTransitionBlockerList($subject, 't2')->isEmpty());
217+
218+
$subject->marking = array('f' => 1);
219+
220+
$this->assertFalse($workflow->buildTransitionBlockerList($subject, 't5')->isEmpty());
221+
$this->assertTrue($workflow->buildTransitionBlockerList($subject, 't6')->isEmpty());
222+
}
223+
198224
public function testBuildTransitionBlockerListReturnsReasonsProvidedByMarking()
199225
{
200226
$definition = $this->createComplexWorkflowDefinition();

src/Symfony/Component/Workflow/TransitionBlockerList.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,17 @@ public function add(TransitionBlocker $blocker): void
3737
$this->blockers[] = $blocker;
3838
}
3939

40+
public function has(string $code): bool
41+
{
42+
foreach ($this->blockers as $blocker) {
43+
if ($code === $blocker->getCode()) {
44+
return true;
45+
}
46+
}
47+
48+
return false;
49+
}
50+
4051
public function clear(): void
4152
{
4253
$this->blockers = array();

src/Symfony/Component/Workflow/Workflow.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,15 @@ public function buildTransitionBlockerList($subject, string $transitionName): Tr
119119
$transitionBlockerList = $this->buildTransitionBlockerListForTransition($subject, $marking, $transition);
120120

121121
if ($transitionBlockerList->isEmpty()) {
122-
continue;
122+
return $transitionBlockerList;
123+
}
124+
125+
// We prefer to return transitions blocker by something else than
126+
// marking. Because it means the marking was OK. Transitions are
127+
// deterministic: it's not possible to have many transitions enabled
128+
// at the same time that match the same marking with the same name
129+
if (!$transitionBlockerList->has(TransitionBlocker::BLOCKED_BY_MARKING)) {
130+
return $transitionBlockerList;
123131
}
124132
}
125133

0 commit comments

Comments
 (0)