Symfony2表单实体字段与多对多关系

3
我有一个Doctrine用户实体,它与角色实体具有多对多的关系。我还有一个表单,该表单基于用户实体字段显示用户详细信息。我在控制器中使用表单构建器以正常方式设置表单,并传递从数据库加载的实体实例。这一切都很好。
现在,我想在此表单中添加一个选择菜单,其中包含分配给用户的角色,并从数据库中可用的角色进行填充。我在我的UserType表单中创建了一个名为roles的字段,类型为“collection”,并传入了一个RoleType表单实例。在我的RoleType表单中,我添加了一个类型为“entity”的字段,并定义了我的角色类等。这都符合文档的要求。这一切都很好,它会加载带有Roles的选择菜单,但它不会选择保存在用户实体中的正确角色。
当我跟踪“roles”的表单值(或在我的角色实体字段上设置数据转换器)时,我得到的值是一个字符串,其中包含用户关联的角色名称。我没有得到Role实例或Collection / Array。而且,如果我将角色实体字段设置为“multiple = true”,则会从Doctrine数据转换器中获得“Expected a Doctrine \ Common \ Collections \ Collection object.”的错误。再次说明,这是因为它期望收到集合,但却得到了一个字符串。
这可能与我的用户实体的水合方式有关吗?我正在使用“$ repository-findOneBy(array('id'=> $ id))”;
这是我正在做的简化版本:
用户类
class User implements AdvancedUserInterface, \Serializable
{   
    /**
     * @ORM\ManyToMany(targetEntity="Role", inversedBy="users")
     */
    public $roles;

    public function __construct()
    {
        $this->roles = new ArrayCollection();
    }

    public function getRoles()
    {
        return $this->roles->toArray();
    }
}

角色类

class  Role implements RoleInterface
{
    /**
     * @ORM\ManyToMany(targetEntity="User", inversedBy="roles")
     */
    public $users;

    public function __construct()
    {
        $this->users = new ArrayCollection();
    }

    public function getUsers()
    {
        return $this->users;
    }
}

用户表单类型

class UserType extends AbstractType
{
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'NameSpace\MyBundle\Entity\User',
        ));
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('id', 'hidden')
            ->add('roles', 'collection', array('type' => new RoleType()))
            ->add('save', 'submit');
     }

     public function getName()
     {
         return 'user';
     }
}

角色表单类型
class RoleType extends AbstractType
{
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'NameSpace\MyBundle\Entity\Role',
        ));
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('name', 'entity', array(
            'class' => 'NameSpace\MyBundle\Entity\Role', 
            'property' => 'name'
            [multiple  => true]
        ));
    }

    public function getName()
    {
       return 'role';
    }
}

你的双向多对多关系必须有一个 mappedBy,而不是两个 inversedBy - juanmf
1个回答

4
您的表单没有向用户实体提供集合以获取角色信息:
public function getRoles()
{
    //this returns an array
    return $this->roles->toArray();
}

Form类使用实体中的getter和setter,因此实际上返回一个数组,因为这是Symfony2安全系统所需的。您需要做的是还要实现一个getRolesCollection字段,并在表单中使用它:

public function getRolesCollection()
{
    //this returns a collection
    return $this->roles;
}

//and (updated from comment below)
->add('roles_collection', 'entity', array('type' => new RoleType()))

oro平台类似于这样做:https://github.com/orocrm/platform/blob/master/src/Oro/Bundle/UserBundle/Form/Type/UserType.php 这篇博客文章也可能会有所帮助:http://blog.jmoz.co.uk/symfony2-fosuserbundle-role-entities/。它是一个添加FOSUserBundle数据库角色的人。

太好了,谢谢你的帮助。那是问题的一部分。另一部分是我需要在UserType表单中将“roles_collection”字段类型从“collection”更改为“entity”。这消除了“RoleType”表单类的需要。这在你发布的第一个链接中有所说明。 - Jon
没错,通过添加getRolesCollection()addRoleCollection($role)removeRoleCollection($role)作为[get|add|remove]Role()代理,效果很好,谢谢! - juanmf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接