Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit cc400f8

Browse filesBrowse files
committed
bug #34569 [Workflow] Apply the same logic of precedence between the apply() and the buildTransitionBlockerList() method (lyrixx)
This PR was merged into the 4.3 branch. Discussion ---------- [Workflow] Apply the same logic of precedence between the apply() and the buildTransitionBlockerList() method | Q | A | ------------- | --- | Branch? | 4.3 | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | Fix #34489 | License | MIT | Doc PR | Commits ------- 2ff3496 [Workflow] Apply the same logic of precedence between the apply() and the buildTransitionBlockerList() method
2 parents 2beeea9 + 2ff3496 commit cc400f8
Copy full SHA for cc400f8

File tree

2 files changed

+62
-22
lines changed
Filter options

2 files changed

+62
-22
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Workflow/Tests/StateMachineTest.php
+32-6Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use PHPUnit\Framework\TestCase;
66
use Symfony\Component\EventDispatcher\EventDispatcher;
77
use Symfony\Component\Workflow\Event\GuardEvent;
8+
use Symfony\Component\Workflow\Exception\NotEnabledTransitionException;
89
use Symfony\Component\Workflow\StateMachine;
910
use Symfony\Component\Workflow\TransitionBlocker;
1011

@@ -84,27 +85,52 @@ public function testBuildTransitionBlockerListReturnsExpectedReasonOnBranchMerge
8485
$subject = new Subject();
8586

8687
// There may be multiple transitions with the same name. Make sure that transitions
87-
// that are not enabled by the marking are evaluated.
88+
// that are enabled by the marking are evaluated.
8889
// see https://github.com/symfony/symfony/issues/28432
8990

90-
// Test if when you are in place "a"trying transition "t1" then returned
91+
// Test if when you are in place "a" and trying to apply "t1" then it returns
9192
// blocker list contains guard blocker instead blockedByMarking
9293
$subject->setMarking('a');
9394
$transitionBlockerList = $net->buildTransitionBlockerList($subject, 't1');
9495
$this->assertCount(1, $transitionBlockerList);
9596
$blockers = iterator_to_array($transitionBlockerList);
96-
9797
$this->assertSame('Transition blocker of place a', $blockers[0]->getMessage());
9898
$this->assertSame('blocker', $blockers[0]->getCode());
9999

100-
// Test if when you are in place "d" trying transition "t1" then
101-
// returned blocker list contains guard blocker instead blockedByMarking
100+
// Test if when you are in place "d" and trying to apply "t1" then
101+
// it returns blocker list contains guard blocker instead blockedByMarking
102102
$subject->setMarking('d');
103103
$transitionBlockerList = $net->buildTransitionBlockerList($subject, 't1');
104104
$this->assertCount(1, $transitionBlockerList);
105105
$blockers = iterator_to_array($transitionBlockerList);
106-
107106
$this->assertSame('Transition blocker of place d', $blockers[0]->getMessage());
108107
$this->assertSame('blocker', $blockers[0]->getCode());
109108
}
109+
110+
public function testApplyReturnsExpectedReasonOnBranchMerge()
111+
{
112+
$definition = $this->createComplexStateMachineDefinition();
113+
114+
$dispatcher = new EventDispatcher();
115+
$net = new StateMachine($definition, null, $dispatcher);
116+
117+
$dispatcher->addListener('workflow.guard', function (GuardEvent $event) {
118+
$event->addTransitionBlocker(new TransitionBlocker(sprintf('Transition blocker of place %s', $event->getTransition()->getFroms()[0]), 'blocker'));
119+
});
120+
121+
$subject = new Subject();
122+
123+
// There may be multiple transitions with the same name. Make sure that all transitions
124+
// that are enabled by the marking are evaluated.
125+
// see https://github.com/symfony/symfony/issues/34489
126+
127+
try {
128+
$net->apply($subject, 't1');
129+
$this->fail();
130+
} catch (NotEnabledTransitionException $e) {
131+
$blockers = iterator_to_array($e->getTransitionBlockerList());
132+
$this->assertSame('Transition blocker of place a', $blockers[0]->getMessage());
133+
$this->assertSame('blocker', $blockers[0]->getCode());
134+
}
135+
}
110136
}

‎src/Symfony/Component/Workflow/Workflow.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Workflow/Workflow.php
+30-16Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -159,25 +159,47 @@ public function apply($subject, $transitionName/*, array $context = []*/)
159159

160160
$marking = $this->getMarking($subject);
161161

162-
$transitionBlockerList = null;
163-
$applied = false;
164-
$approvedTransitionQueue = [];
162+
$transitionExist = false;
163+
$approvedTransitions = [];
164+
$bestTransitionBlockerList = null;
165165

166166
foreach ($this->definition->getTransitions() as $transition) {
167167
if ($transition->getName() !== $transitionName) {
168168
continue;
169169
}
170170

171-
$transitionBlockerList = $this->buildTransitionBlockerListForTransition($subject, $marking, $transition);
172-
if (!$transitionBlockerList->isEmpty()) {
171+
$transitionExist = true;
172+
173+
$tmpTransitionBlockerList = $this->buildTransitionBlockerListForTransition($subject, $marking, $transition);
174+
175+
if ($tmpTransitionBlockerList->isEmpty()) {
176+
$approvedTransitions[] = $transition;
177+
continue;
178+
}
179+
180+
if (!$bestTransitionBlockerList) {
181+
$bestTransitionBlockerList = $tmpTransitionBlockerList;
173182
continue;
174183
}
175-
$approvedTransitionQueue[] = $transition;
184+
185+
// We prefer to return transitions blocker by something else than
186+
// marking. Because it means the marking was OK. Transitions are
187+
// deterministic: it's not possible to have many transitions enabled
188+
// at the same time that match the same marking with the same name
189+
if (!$tmpTransitionBlockerList->has(TransitionBlocker::BLOCKED_BY_MARKING)) {
190+
$bestTransitionBlockerList = $tmpTransitionBlockerList;
191+
}
192+
}
193+
194+
if (!$transitionExist) {
195+
throw new UndefinedTransitionException($subject, $transitionName, $this);
176196
}
177197

178-
foreach ($approvedTransitionQueue as $transition) {
179-
$applied = true;
198+
if (!$approvedTransitions) {
199+
throw new NotEnabledTransitionException($subject, $transitionName, $this, $bestTransitionBlockerList);
200+
}
180201

202+
foreach ($approvedTransitions as $transition) {
181203
$this->leave($subject, $transition, $marking);
182204

183205
$context = $this->transition($subject, $transition, $marking, $context);
@@ -193,14 +215,6 @@ public function apply($subject, $transitionName/*, array $context = []*/)
193215
$this->announce($subject, $transition, $marking);
194216
}
195217

196-
if (!$transitionBlockerList) {
197-
throw new UndefinedTransitionException($subject, $transitionName, $this);
198-
}
199-
200-
if (!$applied) {
201-
throw new NotEnabledTransitionException($subject, $transitionName, $this, $transitionBlockerList);
202-
}
203-
204218
return $marking;
205219
}
206220

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.