问题
TL;DR: how can you add custom constraints (i.e. security voters) to transitions?
My application needs some workflow management system, so I'd like to try Symfony's new Workflow Component. Let's take a Pull Request workflow as an example.
In this example, only states and their transitions are describes. But what if I want to add other constraints to this workflow? I can image some constraints:
- Only admins can accept Pull Request
- Users can only reopen their own Pull Request
- Users can not reopen PR's older than 1 year
While you can use Events in this case, I don't think that's the best way to handle it, because an event is fired after $workflow->apply(). I want to know beforehand if a user is allowed to change the state, so I can hide or disable the button. (not like this).
The LexikWorkflowBundle solved this problem partially, by adding roles to the steps (transitions). Switching to this bundle might be a good idea, but I'd like to figure out how I can solve this problem without.
What is the best way to add custom entity constraints ('PR older than 1 year can't be reopened') and security constraints ('only admins can accept PR's', maybe by using Symfony's Security Voters) to transitions?
Update: To clarify: I want to add permission control to my workflow, but that doesn't necessarily mean I want to tightly couple it to the Workflow Component. I'd like to stick to good practices, so the given solution should respect the single responsibility principle.
回答1:
The best way I found was implementing the AuthorizationChecker in the Workflow's GuardListener.
The demo application gives a good example:
namespace Acme\DemoBundle\Entity\Listener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
use Symfony\Component\Workflow\Event\GuardEvent;
class GuardListener implements EventSubscriberInterface
{
public function __construct(AuthorizationCheckerInterface $checker)
{
$this->checker = $checker;
}
public function onTransition(GuardEvent $event)
{
// For all action, user should be logger
if (!$this->checker->isGranted('IS_AUTHENTICATED_FULLY')) {
$event->setBlocked(true);
}
}
public function onTransitionJournalist(GuardEvent $event)
{
if (!$this->checker->isGranted('ROLE_JOURNALIST')) {
$event->setBlocked(true);
}
}
public function onTransitionSpellChecker(GuardEvent $event)
{
if (!$this->checker->isGranted('ROLE_SPELLCHECKER')) {
$event->setBlocked(true);
}
}
public static function getSubscribedEvents()
{
return [
'workflow.article.guard' => 'onTransition',
'workflow.article.guard.journalist_approval' => 'onTransitionJournalist',
'workflow.article.guard.spellchecker_approval' => 'onTransitionSpellChecker',
];
}
来源:https://stackoverflow.com/questions/41566420/symfony-workflow-component-and-security-voters