[FrameworkBundle] fixed guard event names for transitions
This commit is contained in:
parent
fb88bfc79a
commit
83dc473dd6
@ -602,15 +602,44 @@ class FrameworkExtension extends Extension
|
||||
@trigger_error(sprintf('The "type" option of the "framework.workflows.%s" configuration entry must be defined since Symfony 3.3. The default value will be "state_machine" in Symfony 4.0.', $name), E_USER_DEPRECATED);
|
||||
}
|
||||
$type = $workflow['type'];
|
||||
$workflowId = sprintf('%s.%s', $type, $name);
|
||||
|
||||
// Create transitions
|
||||
$transitions = array();
|
||||
$guardsConfiguration = array();
|
||||
// Global transition counter per workflow
|
||||
$transitionCounter = 0;
|
||||
foreach ($workflow['transitions'] as $transition) {
|
||||
if ('workflow' === $type) {
|
||||
$transitions[] = new Definition(Workflow\Transition::class, array($transition['name'], $transition['from'], $transition['to']));
|
||||
$transitionDefinition = new Definition(Workflow\Transition::class, array($transition['name'], $transition['from'], $transition['to']));
|
||||
$transitionDefinition->setPublic(false);
|
||||
$transitionId = sprintf('%s.transition.%s', $workflowId, $transitionCounter++);
|
||||
$container->setDefinition($transitionId, $transitionDefinition);
|
||||
$transitions[] = new Reference($transitionId);
|
||||
if (isset($transition['guard'])) {
|
||||
$configuration = new Definition(Workflow\EventListener\GuardExpression::class);
|
||||
$configuration->addArgument(new Reference($transitionId));
|
||||
$configuration->addArgument($transition['guard']);
|
||||
$configuration->setPublic(false);
|
||||
$eventName = sprintf('workflow.%s.guard.%s', $name, $transition['name']);
|
||||
$guardsConfiguration[$eventName][] = $configuration;
|
||||
}
|
||||
} elseif ('state_machine' === $type) {
|
||||
foreach ($transition['from'] as $from) {
|
||||
foreach ($transition['to'] as $to) {
|
||||
$transitions[] = new Definition(Workflow\Transition::class, array($transition['name'], $from, $to));
|
||||
$transitionDefinition = new Definition(Workflow\Transition::class, array($transition['name'], $from, $to));
|
||||
$transitionDefinition->setPublic(false);
|
||||
$transitionId = sprintf('%s.transition.%s', $workflowId, $transitionCounter++);
|
||||
$container->setDefinition($transitionId, $transitionDefinition);
|
||||
$transitions[] = new Reference($transitionId);
|
||||
if (isset($transition['guard'])) {
|
||||
$configuration = new Definition(Workflow\EventListener\GuardExpression::class);
|
||||
$configuration->addArgument(new Reference($transitionId));
|
||||
$configuration->addArgument($transition['guard']);
|
||||
$configuration->setPublic(false);
|
||||
$eventName = sprintf('workflow.%s.guard.%s', $name, $transition['name']);
|
||||
$guardsConfiguration[$eventName][] = $configuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -641,7 +670,6 @@ class FrameworkExtension extends Extension
|
||||
}
|
||||
|
||||
// Create Workflow
|
||||
$workflowId = sprintf('%s.%s', $type, $name);
|
||||
$workflowDefinition = new ChildDefinition(sprintf('%s.abstract', $type));
|
||||
$workflowDefinition->replaceArgument(0, new Reference(sprintf('%s.definition', $workflowId)));
|
||||
if (isset($markingStoreDefinition)) {
|
||||
@ -677,16 +705,7 @@ class FrameworkExtension extends Extension
|
||||
}
|
||||
|
||||
// Add Guard Listener
|
||||
$guard = new Definition(Workflow\EventListener\GuardListener::class);
|
||||
$guard->setPrivate(true);
|
||||
$configuration = array();
|
||||
foreach ($workflow['transitions'] as $config) {
|
||||
$transitionName = $config['name'];
|
||||
|
||||
if (!isset($config['guard'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($guardsConfiguration) {
|
||||
if (!class_exists(ExpressionLanguage::class)) {
|
||||
throw new LogicException('Cannot guard workflows as the ExpressionLanguage component is not installed. Try running "composer require symfony/expression-language".');
|
||||
}
|
||||
@ -695,13 +714,11 @@ class FrameworkExtension extends Extension
|
||||
throw new LogicException('Cannot guard workflows as the Security component is not installed. Try running "composer require symfony/security".');
|
||||
}
|
||||
|
||||
$eventName = sprintf('workflow.%s.guard.%s', $name, $transitionName);
|
||||
$guard->addTag('kernel.event_listener', array('event' => $eventName, 'method' => 'onTransition'));
|
||||
$configuration[$eventName] = $config['guard'];
|
||||
}
|
||||
if ($configuration) {
|
||||
$guard = new Definition(Workflow\EventListener\GuardListener::class);
|
||||
$guard->setPrivate(true);
|
||||
|
||||
$guard->setArguments(array(
|
||||
$configuration,
|
||||
$guardsConfiguration,
|
||||
new Reference('workflow.security.expression_language'),
|
||||
new Reference('security.token_storage'),
|
||||
new Reference('security.authorization_checker'),
|
||||
@ -709,6 +726,9 @@ class FrameworkExtension extends Extension
|
||||
new Reference('security.role_hierarchy'),
|
||||
new Reference('validator', ContainerInterface::NULL_ON_INVALID_REFERENCE),
|
||||
));
|
||||
foreach ($guardsConfiguration as $eventName => $config) {
|
||||
$guard->addTag('kernel.event_listener', array('event' => $eventName, 'method' => 'onTransition'));
|
||||
}
|
||||
|
||||
$container->setDefinition(sprintf('%s.listener.guard', $workflowId), $guard);
|
||||
$container->setParameter('workflow.has_guard_listeners', true);
|
||||
|
@ -13,12 +13,12 @@
|
||||
<framework:argument>a</framework:argument>
|
||||
</framework:marking-store>
|
||||
<framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support>
|
||||
<framework:place name="draft" />
|
||||
<framework:place name="wait_for_journalist" />
|
||||
<framework:place name="approved_by_journalist" />
|
||||
<framework:place name="wait_for_spellchecker" />
|
||||
<framework:place name="approved_by_spellchecker" />
|
||||
<framework:place name="published" />
|
||||
<framework:place>draft</framework:place>
|
||||
<framework:place>wait_for_journalist</framework:place>
|
||||
<framework:place>approved_by_journalist</framework:place>
|
||||
<framework:place>wait_for_spellchecker</framework:place>
|
||||
<framework:place>approved_by_spellchecker</framework:place>
|
||||
<framework:place>published</framework:place>
|
||||
<framework:transition name="request_review">
|
||||
<framework:from>draft</framework:from>
|
||||
<framework:to>wait_for_journalist</framework:to>
|
||||
|
@ -19,19 +19,22 @@ class GuardExpression
|
||||
|
||||
private $expression;
|
||||
|
||||
public function getTransition(): Transition
|
||||
{
|
||||
return $this->transition;
|
||||
}
|
||||
|
||||
public function getExpression(): string
|
||||
{
|
||||
return $this->expression;
|
||||
}
|
||||
|
||||
public function __construct(Transition $transition, string $expression)
|
||||
/**
|
||||
* @param string $expression
|
||||
*/
|
||||
public function __construct(Transition $transition, $expression)
|
||||
{
|
||||
$this->transition = $transition;
|
||||
$this->expression = $expression;
|
||||
}
|
||||
|
||||
public function getTransition()
|
||||
{
|
||||
return $this->transition;
|
||||
}
|
||||
|
||||
public function getExpression()
|
||||
{
|
||||
return $this->expression;
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
|
||||
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 <lyrixx@lyrixx.info>
|
||||
@ -63,16 +62,15 @@ class GuardListener
|
||||
}
|
||||
}
|
||||
|
||||
private function validateGuardExpression(GuardEvent $event, string $expression)
|
||||
private function validateGuardExpression(GuardEvent $event, $expression)
|
||||
{
|
||||
if (!$this->expressionLanguage->evaluate($expression, $this->getVariables($event))) {
|
||||
$blocker = TransitionBlocker::createBlockedByExpressionGuardListener($expression);
|
||||
$event->addTransitionBlocker($blocker);
|
||||
$event->setBlocked(true);
|
||||
}
|
||||
}
|
||||
|
||||
// code should be sync with Symfony\Component\Security\Core\Authorization\Voter\ExpressionVoter
|
||||
private function getVariables(GuardEvent $event): array
|
||||
private function getVariables(GuardEvent $event)
|
||||
{
|
||||
$token = $this->tokenStorage->getToken();
|
||||
|
||||
|
@ -21,16 +21,16 @@ class GuardListenerTest extends TestCase
|
||||
private $authenticationChecker;
|
||||
private $validator;
|
||||
private $listener;
|
||||
private $transition;
|
||||
private $configuration;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$configuration = array(
|
||||
$this->configuration = array(
|
||||
'test_is_granted' => 'is_granted("something")',
|
||||
'test_is_valid' => 'is_valid(subject)',
|
||||
'test_expression' => array(
|
||||
new GuardExpression($this->getTransition(true), '!is_valid(subject)'),
|
||||
new GuardExpression($this->getTransition(true), 'is_valid(subject)'),
|
||||
new GuardExpression(new Transition('name', 'from', 'to'), '!is_valid(subject)'),
|
||||
new GuardExpression(new Transition('name', 'from', 'to'), 'is_valid(subject)'),
|
||||
),
|
||||
);
|
||||
$expressionLanguage = new ExpressionLanguage();
|
||||
@ -41,7 +41,7 @@ class GuardListenerTest extends TestCase
|
||||
$this->authenticationChecker = $this->getMockBuilder(AuthorizationCheckerInterface::class)->getMock();
|
||||
$trustResolver = $this->getMockBuilder(AuthenticationTrustResolverInterface::class)->getMock();
|
||||
$this->validator = $this->getMockBuilder(ValidatorInterface::class)->getMock();
|
||||
$this->listener = new GuardListener($configuration, $expressionLanguage, $tokenStorage, $this->authenticationChecker, $trustResolver, null, $this->validator);
|
||||
$this->listener = new GuardListener($this->configuration, $expressionLanguage, $tokenStorage, $this->authenticationChecker, $trustResolver, null, $this->validator);
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
@ -104,8 +104,8 @@ class GuardListenerTest extends TestCase
|
||||
|
||||
public function testWithGuardExpressionWithNotSupportedTransition()
|
||||
{
|
||||
$event = $this->createEvent(true);
|
||||
$this->configureValidator(false, false);
|
||||
$event = $this->createEvent();
|
||||
$this->configureValidator(false);
|
||||
$this->listener->onTransition($event, 'test_expression');
|
||||
|
||||
$this->assertFalse($event->isBlocked());
|
||||
@ -113,7 +113,7 @@ class GuardListenerTest extends TestCase
|
||||
|
||||
public function testWithGuardExpressionWithSupportedTransition()
|
||||
{
|
||||
$event = $this->createEvent();
|
||||
$event = $this->createEvent($this->configuration['test_expression'][1]->getTransition());
|
||||
$this->configureValidator(true, true);
|
||||
$this->listener->onTransition($event, 'test_expression');
|
||||
|
||||
@ -122,18 +122,18 @@ class GuardListenerTest extends TestCase
|
||||
|
||||
public function testGuardExpressionBlocks()
|
||||
{
|
||||
$event = $this->createEvent();
|
||||
$event = $this->createEvent($this->configuration['test_expression'][1]->getTransition());
|
||||
$this->configureValidator(true, false);
|
||||
$this->listener->onTransition($event, 'test_expression');
|
||||
|
||||
$this->assertTrue($event->isBlocked());
|
||||
}
|
||||
|
||||
private function createEvent($newTransition = false)
|
||||
private function createEvent(Transition $transition = null)
|
||||
{
|
||||
$subject = new \stdClass();
|
||||
$subject->marking = new Marking();
|
||||
$transition = $this->getTransition($newTransition);
|
||||
$transition = $transition ?: new Transition('name', 'from', 'to');
|
||||
|
||||
return new GuardEvent($subject, $subject->marking, $transition);
|
||||
}
|
||||
@ -173,13 +173,4 @@ class GuardListenerTest extends TestCase
|
||||
->willReturn($valid ? array() : array('a violation'))
|
||||
;
|
||||
}
|
||||
|
||||
private function getTransition($new = false)
|
||||
{
|
||||
if ($new || !$this->transition) {
|
||||
$this->transition = new Transition('name', 'from', 'to');
|
||||
}
|
||||
|
||||
return $this->transition;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user