Sf2 / 3为不同角色(用户)替换不同形式

时间:2016-08-23 02:25:05

标签: symfony symfony-forms

我有一个需要复杂访问控制的应用程序。 Voters是我在控制器级别做出决策所需要的。 但是,我需要以不同的方式为不同的用户构建表单。 示例:有Admin(ROLE_ADMIN)和User(ROLE_USER)。有一个帖子包含字段:

  • 已发布
  • 主持
  • 作者
  • body
  • 时间戳

管理员必须能够编辑任何帖子的所有字段。 用户 - 仅特定字段:已发布,正文。 (顺便说一句,只有这是这篇文章的作者,但这是由选民决定的。)

我找到的可能解决方案是dynamic form modification。但是如果我们需要更多复杂性,例如帖子属于Blog,则博客属于作者。邮政可以由直接作者和博客作者编辑。 博客的作者也可以编辑postedAt字段,但不能由帖子的直接作者完成。

我需要在PRE_BIND监听器中写一些登录信息。

也许这种情况有某种常见的做法,或者有人可以展示自己的例子。

2 个答案:

答案 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语句过多而变得混乱。在这种情况下,我建议完全写出不同的表单类型(可能会为重复的事情扩展基本表单类型)。