-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Workflow] Add transition blockers #26076
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,21 +11,52 @@ | |
|
||
namespace Symfony\Component\Workflow\Event; | ||
|
||
use Symfony\Component\Workflow\Marking; | ||
use Symfony\Component\Workflow\Transition; | ||
use Symfony\Component\Workflow\TransitionBlocker; | ||
use Symfony\Component\Workflow\TransitionBlockerList; | ||
|
||
/** | ||
* @author Fabien Potencier <[email protected]> | ||
* @author Grégoire Pineau <[email protected]> | ||
*/ | ||
class GuardEvent extends Event | ||
{ | ||
private $blocked = false; | ||
private $transitionBlockerList; | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function __construct($subject, Marking $marking, Transition $transition, $workflowName = 'unnamed') | ||
{ | ||
parent::__construct($subject, $marking, $transition, $workflowName); | ||
|
||
$this->transitionBlockerList = new TransitionBlockerList(); | ||
} | ||
|
||
public function isBlocked(): bool | ||
{ | ||
return !$this->transitionBlockerList->isEmpty(); | ||
} | ||
|
||
public function setBlocked(bool $blocked): void | ||
lyrixx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
if (!$blocked) { | ||
$this->transitionBlockerList->reset(); | ||
|
||
return; | ||
} | ||
|
||
$this->transitionBlockerList->add(TransitionBlocker::createUnknown()); | ||
lyrixx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
public function isBlocked() | ||
public function getTransitionBlockerList(): TransitionBlockerList | ||
{ | ||
return $this->blocked; | ||
return $this->transitionBlockerList; | ||
} | ||
|
||
public function setBlocked($blocked) | ||
public function addTransitionBlocker(TransitionBlocker $transitionBlocker): void | ||
{ | ||
$this->blocked = (bool) $blocked; | ||
$this->transitionBlockerList->add($transitionBlocker); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ | |
use Symfony\Component\Validator\Validator\ValidatorInterface; | ||
use Symfony\Component\Workflow\Event\GuardEvent; | ||
use Symfony\Component\Workflow\Exception\InvalidTokenConfigurationException; | ||
use Symfony\Component\Workflow\TransitionBlocker; | ||
|
||
/** | ||
* @author Grégoire Pineau <[email protected]> | ||
|
@@ -49,8 +50,11 @@ public function onTransition(GuardEvent $event, $eventName) | |
return; | ||
} | ||
|
||
if (!$this->expressionLanguage->evaluate($this->configuration[$eventName], $this->getVariables($event))) { | ||
$event->setBlocked(true); | ||
$expression = $this->configuration[$eventName]; | ||
|
||
if (!$this->expressionLanguage->evaluate($expression, $this->getVariables($event))) { | ||
$blocker = TransitionBlocker::createBlockedByExpressionGuardListener($expression); | ||
$event->addTransitionBlocker($blocker); | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\Workflow\Exception; | ||
|
||
use Symfony\Component\Workflow\TransitionBlockerList; | ||
|
||
/** | ||
* Thrown by Workflow when a not enabled transition is applied on a subject. | ||
* | ||
* @author Grégoire Pineau <[email protected]> | ||
*/ | ||
class NotEnabledTransitionException extends LogicException | ||
{ | ||
private $transitionBlockerList; | ||
|
||
public function __construct(string $transitionName, string $workflowName, TransitionBlockerList $transitionBlockerList) | ||
{ | ||
parent::__construct(sprintf('Transition "%s" is not enabled for workflow "%s".', $transitionName, $workflowName)); | ||
|
||
$this->transitionBlockerList = $transitionBlockerList; | ||
} | ||
|
||
public function getTransitionBlockerList(): TransitionBlockerList | ||
{ | ||
return $this->transitionBlockerList; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\Workflow\Exception; | ||
|
||
/** | ||
* Thrown by Workflow when an undefined transition is applied on a subject. | ||
* | ||
* @author Grégoire Pineau <[email protected]> | ||
*/ | ||
class UndefinedTransitionException extends LogicException | ||
{ | ||
public function __construct(string $transitionName, string $workflowName) | ||
{ | ||
parent::__construct(sprintf('Transition "%s" is not defined for workflow "%s".', $transitionName, $workflowName)); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <[email protected]> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\Workflow; | ||
|
||
/** | ||
* A reason why a transition cannot be performed for a subject. | ||
*/ | ||
final class TransitionBlocker | ||
{ | ||
const BLOCKED_BY_MARKING = '19beefc8-6b1e-4716-9d07-a39bd6d16e34'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What are these? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It was in the initial PR. It's used to identify a blocker by a "machine". It's the same approach as in the Validator component. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would make them |
||
const BLOCKED_BY_EXPRESSION_GUARD_LISTENER = '326a1e9c-0c12-11e8-ba89-0ed5f89f718b'; | ||
const UNKNOWN = 'e8b5bbb9-5913-4b98-bfa6-65dbd228a82a'; | ||
|
||
private $message; | ||
private $code; | ||
private $parameters; | ||
|
||
/** | ||
* @param string $code Code is a machine-readable string, usually an UUID | ||
* @param array $parameters This is useful if you would like to pass around the condition values, that | ||
* blocked the transition. E.g. for a condition "distance must be larger than | ||
* 5 miles", you might want to pass around the value of 5. | ||
*/ | ||
public function __construct(string $message, string $code, array $parameters = array()) | ||
{ | ||
$this->message = $message; | ||
$this->code = $code; | ||
$this->parameters = $parameters; | ||
} | ||
|
||
/** | ||
* Create a blocker that says the transition cannot be made because it is | ||
* not enabled. | ||
* | ||
* It means the subject is in wrong place (i.e. status): | ||
* * If the workflow is a state machine: the subject is not in the previous place of the transition. | ||
* * If the workflow is a workflow: the subject is not in all previous places of the transition. | ||
*/ | ||
public static function createBlockedByMarking(Marking $marking): self | ||
{ | ||
return new static('The marking does not enable the transition.', self::BLOCKED_BY_MARKING, array( | ||
'marking' => $marking, | ||
)); | ||
} | ||
|
||
/** | ||
* Creates a blocker that says the transition cannot be made because it has | ||
* been blocked by the expression guard listener. | ||
*/ | ||
public static function createBlockedByExpressionGuardListener(string $expression): self | ||
{ | ||
return new static('The expression blocks the transition.', self::BLOCKED_BY_EXPRESSION_GUARD_LISTENER, array( | ||
'expression' => $expression, | ||
)); | ||
} | ||
|
||
/** | ||
* Creates a blocker that says the transition cannot be made because of an | ||
* unknown reason. | ||
* | ||
* This blocker code is chiefly for preserving backwards compatibility. | ||
*/ | ||
public static function createUnknown(): self | ||
{ | ||
return new static('Unknown reason.', self::UNKNOWN); | ||
} | ||
|
||
public function getMessage(): string | ||
{ | ||
return $this->message; | ||
} | ||
|
||
public function getCode(): string | ||
{ | ||
return $this->code; | ||
} | ||
|
||
public function getParameters(): array | ||
{ | ||
return $this->parameters; | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.