8000 [Workflow] Fixed bug of buildTransitionBlockerList when many transition are enabled by lyrixx · Pull Request #29141 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[Workflow] Fixed bug of buildTransitionBlockerList when many transition are enabled #29141

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions src/Symfony/Component/Workflow/Tests/StateMachineTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
namespace Symfony\Component\Workflow\Tests;

use PHPUnit\Framework\TestCase;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Workflow\Event\GuardEvent;
use Symfony\Component\Workflow\StateMachine;
use Symfony\Component\Workflow\TransitionBlocker;

class StateMachineTest extends TestCase
{
Expand Down Expand Up @@ -38,4 +41,70 @@ public function testCanWithMultipleTransition()
$this->assertTrue($net->can($subject, 't2'));
$this->assertTrue($net->can($subject, 't3'));
}

public function testBuildTransitionBlockerList()
{
$definition = $this->createComplexStateMachineDefinition();

$net = new StateMachine($definition);
$subject = new \stdClass();

$subject->marking = 'a';
$this->assertTrue($net->buildTransitionBlockerList($subject, 't1')->isEmpty());
$subject->marking = 'd';
$this->assertTrue($net->buildTransitionBlockerList($subject, 't1')->isEmpty());

$subject->marking = 'b';
$this->assertFalse($net->buildTransitionBlockerList($subject, 't1')->isEmpty());
}

public function testBuildTransitionBlockerListWithMultipleTransitions()
{
$definition = $this->createComplexStateMachineDefinition();

$net = new StateMachine($definition);
$subject = new \stdClass();

$subject->marking = 'b';
$this->assertTrue($net->buildTransitionBlockerList($subject, 't2')->isEmpty());
$this->assertTrue($net->buildTransitionBlockerList($subject, 't3')->isEmpty());
}

public function testBuildTransitionBlockerListReturnsExpectedReasonOnBranchMerge()
{
$definition = $this->createComplexStateMachineDefinition();

$dispatcher = new EventDispatcher();
$net = new StateMachine($definition, null, $dispatcher);

$dispatcher->addListener('workflow.guard', function (GuardEvent $event) {
$event->addTransitionBlocker(new TransitionBlocker(\sprintf('Transition blocker of place %s', $event->getTransition()->getFroms()[0]), 'blocker'));
});

$subject = new \stdClass();

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

// Test if when you are in place "a"trying transition "t1" then returned
// blocker list contains guard blocker instead blockedByMarking
$subject->marking = 'a';
$transitionBlockerList = $net->buildTransitionBlockerList($subject, 't1');
$this->assertCount(1, $transitionBlockerList);
$blockers = iterator_to_array($transitionBlockerList);

$this->assertSame('Transition blocker of place a', $blockers[0]->getMessage());
$this->assertSame('blocker', $blockers[0]->getCode());

// Test if when you are in place "d" trying transition "t1" then
// returned blocker list contains guard blocker instead blockedByMarking
$subject->marking = 'd';
$transitionBlockerList = $net->buildTransitionBlockerList($subject, 't1');
$this->assertCount(1, $transitionBlockerList);
$blockers = iterator_to_array($transitionBlockerList);

$this->assertSame('Transition blocker of place d', $blockers[0]->getMessage());
$this->assertSame('blocker', $blockers[0]->getCode());
}
}
26 changes: 26 additions & 0 deletions src/Symfony/Component/Workflow/Tests/WorkflowTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,32 @@ public function testBuildTransitionBlockerListReturnsUndefinedTransition()
$workflow->buildTransitionBlockerList($subject, '404 Not Found');
}

public function testBuildTransitionBlockerList()
{
$definition = $this->createComplexWorkflowDefinition();
$subject = new \stdClass();
$subject->marking = null;
$workflow = new Workflow($definition, new MultipleStateMarkingStore());

$this->assertTrue($workflow->buildTransitionBlockerList($subject, 't1')->isEmpty());
$this->assertFalse($workflow->buildTransitionBlockerList($subject, 't2')->isEmpty());

$subject->marking = array('b' => 1);

$this->assertFalse($workflow->buildTransitionBlockerList($subject, 't1')->isEmpty());
$this->assertFalse($workflow->buildTransitionBlockerList($subject, 't2')->isEmpty());

$subject->marking = array('b' => 1, 'c' => 1);

$this->assertFalse($workflow->buildTransitionBlockerList($subject, 't1')->isEmpty());
$this->assertTrue($workflow->buildTransitionBlockerList($subject, 't2')->isEmpty());

$subject->marking = array('f' => 1);

$this->assertFalse($workflow->buildTransitionBlockerList($subject, 't5')->isEmpty());
$this->assertTrue($workflow->buildTransitionBlockerList($subject, 't6')->isEmpty());
}

public function testBuildTransitionBlockerListReturnsReasonsProvidedByMarking()
{
$definition = $this->createComplexWorkflowDefinition();
Expand Down
11 changes: 11 additions & 0 deletions src/Symfony/Component/Workflow/TransitionBlockerList.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@ public function add(TransitionBlocker $blocker): void
$this->blockers[] = $blocker;
}

public function has(string $code): bool
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we mark this method as internal?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be usefull to any one, isn't?
We could mark it internal, but I don't really see benefit of doing it.
It will update the code if you want.

{
foreach ($this->blockers as $blocker) {
if ($code === $blocker->getCode()) {
return true;
}
}

return false;
}

public function clear(): void
{
$this->blockers = array();
Expand Down
10 changes: 9 additions & 1 deletion src/Symfony/Component/Workflow/Workflow.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,15 @@ public function buildTransitionBlockerList($subject, string $transitionName): Tr
$transitionBlockerList = $this->buildTransitionBlockerListForTransition($subject, $marking, $transition);

if ($transitionBlockerList->isEmpty()) {
continue;
return $transitionBlockerList;
}

// We prefer to return transitions blocker by something else than
// marking. Because it means the marking was OK. Transitions are
// deterministic: it's not possible to have many transitions enabled
// at the same time that match the same marking with the same name
if (!$transitionBlockerList->has(TransitionBlocker::BLOCKED_BY_MARKING)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could update the condition above: if ($transitionBlockerList->isEmpty() || !$transitionBlockerList->has(TransitionBlocker::BLOCKED_BY_MARKING)) {

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But then the comment will be harder to understand because it applies to only one part of the if statement

I prefer to keep it as it. Are you OK with that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, no blocker for me

return $transitionBlockerList;
}
}

Expand Down
0