我有一个需要复杂访问控制的应用程序。 Voters是我在控制器级别做出决策所需要的。 但是,我需要以不同的方式为不同的用户构建表单。 示例:有Admin(ROLE_ADMIN)和User(ROLE_USER)。有一个帖子包含字段:
管理员必须能够编辑任何帖子的所有字段。 用户 - 仅特定字段:已发布,正文。 (顺便说一句,只有这是这篇文章的作者,但这是由选民决定的。)
我找到的可能解决方案是dynamic form modification。但是如果我们需要更多复杂性,例如帖子属于Blog,则博客属于作者。邮政可以由直接作者和博客作者编辑。 博客的作者也可以编辑postedAt字段,但不能由帖子的直接作者完成。
我需要在PRE_BIND监听器中写一些登录信息。
也许这种情况有某种常见的做法,或者有人可以展示自己的例子。
答案 0 :(得分:3)
您可以创建form type extension
想象一下只有在ROLE_ADMIN
被授予时才要显示字段的表单类型。为此,您只需向该字段添加一个新属性(在此示例中为“author”)
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('published', 'text')
->add('moderated', 'text')
->add('author', 'text', [
'is_granted' => 'ROLE_ADMIN',
])
;
}
要解释此参数,您必须通过注入SecurityContext
Symfony来创建表单类型扩展,以确保登录用户的权限。
<?php
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\SecurityContextInterface;
class SecurityTypeExtension extends AbstractTypeExtension
{
/**
* The security context
* @var SecurityContextInterface
*/
private $securityContext;
/**
* Object constructor
*/
public function __construct(SecurityContextInterface $securityContext)
{
$this->securityContext = $securityContext;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$grant = $options['is_granted'];
if (null === $grant || $this->securityContext->isGranted($grant)) {
return;
}
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$form = $event->getForm();
if ($form->isRoot()) {
return;
}
$form->getParent()->remove($form->getName());
});
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefined(array('is_granted' => null));
}
/**
* {@inheritdoc}
*/
public function getExtendedType()
{
return 'form';
}
}
最后,您只需将扩展名保存为服务:
services:
yourbundle.security_type_extension:
class: YourProject\Bundle\ForumBundle\Form\Extension\SecurityTypeExtension
arguments:
- @security.context
tags:
- { name: form.type_extension, alias: form }
答案 1 :(得分:1)
动态表单修改似乎没必要。用户登录后,角色不应更改。
您可以在表单类型中注入security.authorization_checker
服务,并在buildForm
方法中使用该服务有条件地向表单添加字段。根据表单的不同,这可能会因为if语句过多而变得混乱。在这种情况下,我建议完全写出不同的表单类型(可能会为重复的事情扩展基本表单类型)。