【问题标题】:Symfony2 collection of Entities - how to add/remove association with existing entities?Symfony2 实体集合 - 如何添加/删除与现有实体的关联?
【发布时间】:2012-06-18 19:40:25
【问题描述】:

1。快速概览

1.1 目标

我想要实现的是创建/编辑用户工具。可编辑的字段是:

  • 用户名(类型:文本)
  • plainPassword(类型:密码)
  • 电子邮件(类型:电子邮件)
  • 组(类型:集合)
  • avoRoles(类型:集合)

注意:最后一个属性没有命名为$roles,因为我的 User 类是扩展 FOSUserBundle 的 User 类并且覆盖角色带来了更多的问题。为了避免它们,我只是决定将我的角色集合存储在 $avoRoles 下。

1.2 用户界面

My template 由 2 个部分组成:

  1. 用户表单
  2. 表格显示 $userRepository->findAllRolesExceptOwnedByUser($user);

注意:findAllRolesExceptOwnedByUser() 是一个自定义存储库函数,返回所有角色的子集(那些尚未分配给 $user 的角色)。

1.3 所需功能

1.3.1 添加角色:

WHEN 用户单击 Roles 表中的“+”(添加)按钮 THEN jquery 从 Roles 表中删除该行 AND jquery 将新列表项添加到用户表单(avoRoles 列表)

1.3.2 移除角色:

WHEN 用户单击用户表单(avoRoles 列表)中的“x”(删除)按钮 THEN jquery 从用户表单中删除该列表项(avoRoles 列表) AND jquery 向 Roles 表添加新行

1.3.3 保存更改:

用户点击“Zapisz”(保存)按钮 THEN 用户表单提交所有字段(用户名、密码、电子邮件、avoRoles、组) AND 将 avoRoles 保存为角色实体的 ArrayCollection(ManyToMany 关系) AND 将组保存为角色实体的 ArrayCollection(ManyToMany 关系)

注意:只有现有的角色和组可以分配给用户。如果由于任何原因未找到它们,则不应验证表单。


2。代码

在本节中,我将介绍/或简要描述此操作背后的代码。如果描述不够,您需要查看代码,请告诉我,我会粘贴它。我并不是一开始就将其全部粘贴,以避免向您发送不必要的代码。

2.1 用户类

我的用户类扩展了 FOSUserBundle 用户类。

namespace Avocode\UserBundle\Entity;

use FOS\UserBundle\Entity\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use Avocode\CommonBundle\Collections\ArrayCollection;
use Symfony\Component\Validator\ExecutionContext;

/**
 * @ORM\Entity(repositoryClass="Avocode\UserBundle\Repository\UserRepository")
 * @ORM\Table(name="avo_user")
 */
class User extends BaseUser
{
    const ROLE_DEFAULT = 'ROLE_USER';
    const ROLE_SUPER_ADMIN = 'ROLE_SUPER_ADMIN';

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\generatedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\ManyToMany(targetEntity="Group")
     * @ORM\JoinTable(name="avo_user_avo_group",
     *      joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="group_id", referencedColumnName="id")}
     * )
     */
    protected $groups;

    /**
     * @ORM\ManyToMany(targetEntity="Role")
     * @ORM\JoinTable(name="avo_user_avo_role",
     *      joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="role_id", referencedColumnName="id")}
     * )
     */
    protected $avoRoles;

    /**
     * @ORM\Column(type="datetime", name="created_at")
     */
    protected $createdAt;

    /**
     * User class constructor
     */
    public function __construct()
    {
        parent::__construct();

        $this->groups = new ArrayCollection();        
        $this->avoRoles = new ArrayCollection();
        $this->createdAt = new \DateTime();
    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set user roles
     * 
     * @return User
     */
    public function setAvoRoles($avoRoles)
    {
        $this->getAvoRoles()->clear();

        foreach($avoRoles as $role) {
            $this->addAvoRole($role);
        }

        return $this;
    }

    /**
     * Add avoRole
     *
     * @param Role $avoRole
     * @return User
     */
    public function addAvoRole(Role $avoRole)
    {
        if(!$this->getAvoRoles()->contains($avoRole)) {
          $this->getAvoRoles()->add($avoRole);
        }

        return $this;
    }

    /**
     * Get avoRoles
     *
     * @return ArrayCollection
     */
    public function getAvoRoles()
    {
        return $this->avoRoles;
    }

    /**
     * Set user groups
     * 
     * @return User
     */
    public function setGroups($groups)
    {
        $this->getGroups()->clear();

        foreach($groups as $group) {
            $this->addGroup($group);
        }

        return $this;
    }

    /**
     * Get groups granted to the user.
     *
     * @return Collection
     */
    public function getGroups()
    {
        return $this->groups ?: $this->groups = new ArrayCollection();
    }

    /**
     * Get user creation date
     *
     * @return DateTime
     */
    public function getCreatedAt()
    {
        return $this->createdAt;
    }
}

2.2 角色类

我的角色类扩展了 Symfony 安全组件核心角色类。

namespace Avocode\UserBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Avocode\CommonBundle\Collections\ArrayCollection;
use Symfony\Component\Security\Core\Role\Role as BaseRole;

/**
 * @ORM\Entity(repositoryClass="Avocode\UserBundle\Repository\RoleRepository")
 * @ORM\Table(name="avo_role")
 */
class Role extends BaseRole
{    
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\generatedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\Column(type="string", unique="TRUE", length=255)
     */
    protected $name;

    /**
     * @ORM\Column(type="string", length=255)
     */
    protected $module;

    /**
     * @ORM\Column(type="text")
     */
    protected $description;

    /**
     * Role class constructor
     */
    public function __construct()
    {
    }

    /**
     * Returns role name.
     * 
     * @return string
     */    
    public function __toString()
    {
        return (string) $this->getName();
    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     * @return Role
     */
    public function setName($name)
    {      
        $name = strtoupper($name);
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string 
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set module
     *
     * @param string $module
     * @return Role
     */
    public function setModule($module)
    {
        $this->module = $module;

        return $this;
    }

    /**
     * Get module
     *
     * @return string 
     */
    public function getModule()
    {
        return $this->module;
    }

    /**
     * Set description
     *
     * @param text $description
     * @return Role
     */
    public function setDescription($description)
    {
        $this->description = $description;

        return $this;
    }

    /**
     * Get description
     *
     * @return text 
     */
    public function getDescription()
    {
        return $this->description;
    }
}

2.3 组类

由于我对组和角色有同样的问题,所以我在这里跳过它们。如果我让角色发挥作用,我知道我可以对组做同样的事情。

2.4 控制器

namespace Avocode\UserBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Security\Core\SecurityContext;
use JMS\SecurityExtraBundle\Annotation\Secure;
use Avocode\UserBundle\Entity\User;
use Avocode\UserBundle\Form\Type\UserType;

class UserManagementController extends Controller
{
    /**
     * User create
     * @Secure(roles="ROLE_USER_ADMIN")
     */
    public function createAction(Request $request)
    {      
        $em = $this->getDoctrine()->getEntityManager();

        $user = new User();
        $form = $this->createForm(new UserType(array('password' => true)), $user);

        $roles = $em->getRepository('AvocodeUserBundle:User')
                    ->findAllRolesExceptOwned($user);
        $groups = $em->getRepository('AvocodeUserBundle:User')
                    ->findAllGroupsExceptOwned($user);

        if($request->getMethod() == 'POST' && $request->request->has('save')) {
            $form->bindRequest($request);

            if($form->isValid()) {
                /* Persist, flush and redirect */
                $em->persist($user);
                $em->flush();
                $this->setFlash('avocode_user_success', 'user.flash.user_created');
                $url = $this->container->get('router')->generate('avocode_user_show', array('id' => $user->getId()));

                return new RedirectResponse($url);
            }
        }

        return $this->render('AvocodeUserBundle:UserManagement:create.html.twig', array(
          'form' => $form->createView(),
          'user' => $user,
          'roles' => $roles,
          'groups' => $groups,
        ));
    }
}

2.5 自定义仓库

没有必要发布这个,因为它们工作得很好 - 它们返回所有角色/组的子集(那些未分配给用户的)。

2.6 用户类型

用户类型:

namespace Avocode\UserBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;

class UserType extends AbstractType
{    
    private $options; 

    public function __construct(array $options = null) 
    { 
        $this->options = $options; 
    }

    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder->add('username', 'text');

        // password field should be rendered only for CREATE action
        // the same form type will be used for EDIT action
        // thats why its optional

        if($this->options['password'])
        {
          $builder->add('plainpassword', 'repeated', array(
                        'type' => 'text',
                        'options' => array(
                          'attr' => array(
                            'autocomplete' => 'off'
                          ),
                        ),
                        'first_name' => 'input',
                        'second_name' => 'confirm', 
                        'invalid_message' => 'repeated.invalid.password',
                     ));
        }

        $builder->add('email', 'email', array(
                        'trim' => true,
                     ))

        // collection_list is a custom field type
        // extending collection field type
        //
        // the only change is diffrent form name
        // (and a custom collection_list_widget)
        // 
        // in short: it's a collection field with custom form_theme
        // 
                ->add('groups', 'collection_list', array(
                        'type' => new GroupNameType(),
                        'allow_add' => true,
                        'allow_delete' => true,
                        'by_reference' => true,
                        'error_bubbling' => false,
                        'prototype' => true,
                     ))
                ->add('avoRoles', 'collection_list', array(
                        'type' => new RoleNameType(),
                        'allow_add' => true,
                        'allow_delete' => true,
                        'by_reference' => true,
                        'error_bubbling' => false,
                        'prototype' => true,
                     ));
    }

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

    public function getDefaultOptions(array $options){

        $options = array(
          'data_class' => 'Avocode\UserBundle\Entity\User',
        );

        // adding password validation if password field was rendered

        if($this->options['password'])
          $options['validation_groups'][] = 'password';

        return $options;
    }
}

2.7 角色名称类型

这个表单应该呈现:

  • 隐藏的角色 ID
  • 角色名称(只读)
  • 隐藏模块(只读)
  • 隐藏描述(只读)
  • 移除 (x) 按钮

模块和描述被呈现为隐藏字段,因为当管理员从用户中删除一个角色时,该角色应该由 jQuery 添加到角色表 - 并且该表具有模块和描述列。

namespace Avocode\UserBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;

class RoleNameType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder            
            ->add('', 'button', array(
              'required' => false,
            ))  // custom field type rendering the "x" button

            ->add('id', 'hidden')

            ->add('name', 'label', array(
              'required' => false,
            )) // custom field type rendering <span> item instead of <input> item

            ->add('module', 'hidden', array('read_only' => true))
            ->add('description', 'hidden', array('read_only' => true))
        ;        
    }

    public function getName()
    {
        // no_label is a custom widget that renders field_row without the label

        return 'no_label';
    }

    public function getDefaultOptions(array $options){
        return array('data_class' => 'Avocode\UserBundle\Entity\Role');
    }
}

3。当前/已知问题

3.1 案例1:如上引用的配置

以上配置返回错误:

Property "id" is not public in class "Avocode\UserBundle\Entity\Role". Maybe you should create the method "setId()"?

但不应该要求设置 ID。

  1. 首先因为我不想创建新角色。我只想在现有角色和用户实体之间创建关系。
  2. 即使我确实想创建一个新角色,它的 ID 也应该是自动生成的:

    /**

    • @ORM\Id
    • @ORM\Column(type="integer")
    • @ORM\generatedValue(strategy="AUTO") */ 受保护的 $id;

3.2 案例2:在角色实体中为ID属性添加setter

我认为这是错误的,但我这样做只是为了确定。将此代码添加到角色实体后:

public function setId($id)
{
    $this->id = $id;
    return $this;
}

如果我创建新用户并添加角色,然后保存...会发生什么:

  1. 新用户已创建
  2. 新用户具有分配了所需 ID 的角色(耶!)
  3. 但该角色的名称被空字符串覆盖(真糟糕!)

显然,这不是我想要的。我不想编辑/覆盖角色。我只是想在他们和用户之间添加一个关系。

3.3 案例 3:Jeppe 建议的解决方法

当我第一次遇到这个问题时,我最终找到了一个解决方法,这与 Jeppe 建议的相同。今天(由于其他原因)我不得不重新制作我的表单/视图并且解决方法停止工作。

Case3 UserManagementController 有什么变化 -> createAction:

  // in createAction
  // instead of $user = new User
  $user = $this->updateUser($request, new User());

  //and below updateUser function


    /**
     * Creates mew iser and sets its properties
     * based on request
     * 
     * @return User Returns configured user
     */
    protected function updateUser($request, $user)
    {
        if($request->getMethod() == 'POST')
        {
          $avo_user = $request->request->get('avo_user');

          /**
           * Setting and adding/removeing groups for user
           */
          $owned_groups = (array_key_exists('groups', $avo_user)) ? $avo_user['groups'] : array();
          foreach($owned_groups as $key => $group) {
            $owned_groups[$key] = $group['id'];
          }

          if(count($owned_groups) > 0)
          {
            $em = $this->getDoctrine()->getEntityManager();
            $groups = $em->getRepository('AvocodeUserBundle:Group')->findById($owned_groups);
            $user->setGroups($groups);
          }

          /**
           * Setting and adding/removeing roles for user
           */
          $owned_roles = (array_key_exists('avoRoles', $avo_user)) ? $avo_user['avoRoles'] : array();
          foreach($owned_roles as $key => $role) {
            $owned_roles[$key] = $role['id'];
          }

          if(count($owned_roles) > 0)
          {
            $em = $this->getDoctrine()->getEntityManager();
            $roles = $em->getRepository('AvocodeUserBundle:Role')->findById($owned_roles);
            $user->setAvoRoles($roles);
          }

          /**
           * Setting other properties
           */
          $user->setUsername($avo_user['username']);
          $user->setEmail($avo_user['email']);

          if($request->request->has('generate_password'))
            $user->setPlainPassword($user->generateRandomPassword());  
        }

        return $user;
    }

不幸的是,这并没有改变任何东西。结果是 CASE1(没有 ID 设置器)或 CASE2(有 ID 设置器)。

3.4 案例4:用户友好的建议

添加 cascade={"persist", "remove"} 到映射。

/**
 * @ORM\ManyToMany(targetEntity="Group", cascade={"persist", "remove"})
 * @ORM\JoinTable(name="avo_user_avo_group",
 *      joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="group_id", referencedColumnName="id")}
 * )
 */
protected $groups;

/**
 * @ORM\ManyToMany(targetEntity="Role", cascade={"persist", "remove"})
 * @ORM\JoinTable(name="avo_user_avo_role",
 *      joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="role_id", referencedColumnName="id")}
 * )
 */
protected $avoRoles;

并在 FormType 中将 by_reference 更改为 false

// ...

                ->add('avoRoles', 'collection_list', array(
                        'type' => new RoleNameType(),
                        'allow_add' => true,
                        'allow_delete' => true,
                        'by_reference' => false,
                        'error_bubbling' => false,
                        'prototype' => true,
                     ));

// ...

保留 3.3 中建议的解决方法代码确实改变了一些东西:

  1. 用户和角色之间的关联未创建
  2. .. 但是角色实体的名称被空字符串覆盖(如 3.2)

所以..它确实改变了一些东西,但方向错误。

4。版本

4.1 Symfony2 v2.0.15

4.2 Doctrine2 v2.1.7

4.3 FOSUserBundle 版本:6fb81861d84d460f1d070ceb8ec180aac841f7fa

5。总结

我尝试了许多不同的方法(以上只是最新的方法),经过数小时的研究代码、谷歌搜索和寻找答案后,我无法得到这个工作。

任何帮助将不胜感激。如果您需要了解任何内容,我会发布您需要的任何代码部分。

【问题讨论】:

  • +1 是我很长时间以来看到的最广泛和写得最完善的问题之一。
  • 问题可能出在Form类型上。能否请您澄清RoleNameType 中的评论:“自定义字段类型呈现项而不是项”。
  • 哦,我忘了用 < 写 " item" 和 " item"和> - 所以这些元素(作为不被接受的 html 元素)在我的问题中被忽略了
  • 我不喜欢冗长的问题,因为我必须先找到并搜索“问题”/“问题”,然后才能开始提供帮助 -.-
  • 这段代码有效吗? $roles = $em->getRepository('AvocodeUserBundle:Role')->findById($owned_roles);我从教义+ ZF来之前从未见过它

标签: php forms collections symfony entity


【解决方案1】:

一年过去了,这个问题变得相当流行。此后 Symfony 发生了变化,我的技能和知识也有所提高,我目前解决此问题的方法也有所提高。

我为 symfony2 创建了一组表单扩展(参见 github 上的 FormExtensionsBundle 项目),它们包括一个用于处理 One/Many ToMany 关系的表单类型。

在编写这些代码时,将自定义代码添加到您的控制器以处理集合是不可接受的 - 表单扩展应该易于使用、开箱即用并让我们开发人员的生活更轻松,而不是更难。另外..记住..干!

所以我不得不将添加/删除关联代码移到其他地方 - 正确的地方自然是 EventListener :)

查看EventListener/CollectionUploadListener.php 文件,了解我们现在如何处理此问题。

附言。复制这里的代码是不必要的,最重要的是这样的东西实际上应该在 EventListener 中处理。

【讨论】:

    【解决方案2】:

    我得出了相同的结论,即 Form 组件有问题,并且看不到修复它的简单方法。但是,我提出了一个完全通用的稍微不那么繁琐的解决方案。它没有任何实体/属性的硬编码知识,因此将修复它遇到的任何集合:

    更简单、通用的解决方法

    这不需要您对实体进行任何更改。

    use Doctrine\Common\Collections\Collection;
    use Symfony\Component\Form\Form;
    
    # In your controller. Or possibly defined within a service if used in many controllers
    
    /**
     * Ensure that any removed items collections actually get removed
     *
     * @param \Symfony\Component\Form\Form $form
     */
    protected function cleanupCollections(Form $form)
    {
        $children = $form->getChildren();
    
        foreach ($children as $childForm) {
            $data = $childForm->getData();
            if ($data instanceof Collection) {
    
                // Get the child form objects and compare the data of each child against the object's current collection
                $proxies = $childForm->getChildren();
                foreach ($proxies as $proxy) {
                    $entity = $proxy->getData();
                    if (!$data->contains($entity)) {
    
                        // Entity has been removed from the collection
                        // DELETE THE ENTITY HERE
    
                        // e.g. doctrine:
                        // $em = $this->getDoctrine()->getEntityManager();
                        // $em->remove($entity);
    
                    }
                }
            }
        }
    }
    

    在持久化之前调用新的cleanupCollections()方法

    # in your controller action...
    
    if($request->getMethod() == 'POST') {
        $form->bindRequest($request);
        if($form->isValid()) {
    
            // 'Clean' all collections within the form before persisting
            $this->cleanupCollections($form);
    
            $em->persist($user);
            $em->flush();
    
            // further actions. return response...
        }
    }
    

    【讨论】:

    • 感谢分享。现在我正在开发我的应用程序的不同部分,但当我审查/修改我的应用程序代码时,我肯定会考虑你的解决方案。
    【解决方案3】:

    1。变通解决方案

    Jeppe Marianger-Lam 建议的解决方案是目前我所知道的唯一可行的解​​决方案。

    1.1 为什么它在我的案例中停止工作?

    我将我的 RoleNameType(出于其他原因)更改为:

    • ID(隐藏)
    • 名称(自定义类型 - 标签)
    • 模块和描述(隐藏,只读)

    问题是我的自定义类型标签将 NAME 属性呈现为

    角色名称

    由于它不是“只读”的,因此 FORM 组件预计会在 POST 中获取 NAME。

    而是只发布了 ID,因此 FORM 组件假定 NAME 为 NULL。

    这导致 CASE 2 (3.2) -> 创建关联,但用空字符串覆盖 ROLE NAME。

    2。那么,这个解决方法到底是什么?

    2.1 控制器

    这个解决方法非常简单。

    在您的控制器中,在验证表单之前,您必须获取已发布的实体标识符并获取匹配的实体,然后将它们设置为您的对象。

    // example action
    public function createAction(Request $request)
    {      
        $em = $this->getDoctrine()->getEntityManager();
    
        // the workaround code is in updateUser function
        $user = $this->updateUser($request, new User());
    
        $form = $this->createForm(new UserType(), $user);
    
        if($request->getMethod() == 'POST') {
            $form->bindRequest($request);
    
            if($form->isValid()) {
                /* Persist, flush and redirect */
                $em->persist($user);
                $em->flush();
                $this->setFlash('avocode_user_success', 'user.flash.user_created');
                $url = $this->container->get('router')->generate('avocode_user_show', array('id' => $user->getId()));
    
                return new RedirectResponse($url);
            }
        }
    
        return $this->render('AvocodeUserBundle:UserManagement:create.html.twig', array(
          'form' => $form->createView(),
          'user' => $user,
        ));
    }
    

    在 updateUser 函数中的解决方法代码下方:

    protected function updateUser($request, $user)
    {
        if($request->getMethod() == 'POST')
        {
          // getting POSTed values
          $avo_user = $request->request->get('avo_user');
    
          // if no roles are posted, then $owned_roles should be an empty array (to avoid errors)
          $owned_roles = (array_key_exists('avoRoles', $avo_user)) ? $avo_user['avoRoles'] : array();
    
          // foreach posted ROLE, get it's ID
          foreach($owned_roles as $key => $role) {
            $owned_roles[$key] = $role['id'];
          }
    
          // FIND all roles with matching ID's
          if(count($owned_roles) > 0)
          {
            $em = $this->getDoctrine()->getEntityManager();
            $roles = $em->getRepository('AvocodeUserBundle:Role')->findById($owned_roles);
    
            // and create association
            $user->setAvoRoles($roles);
          }
    
        return $user;
    }
    

    为此,您的 SETTER(在本例中为 User.php 实体)必须是:

    public function setAvoRoles($avoRoles)
    {
        // first - clearing all associations
        // this way if entity was not found in POST
        // then association will be removed
    
        $this->getAvoRoles()->clear();
    
        // adding association only for POSTed entities
        foreach($avoRoles as $role) {
            $this->addAvoRole($role);
        }
    
        return $this;
    }
    

    3。最后的想法

    不过,我认为这种解决方法正在做的工作

    $form->bindRequest($request);
    

    应该这样做!要么是我做错了,要么是 symfony 的 Collection 表单类型不完整。

    There are some major changes in Form component 出现在 symfony 2.1 中,希望这会得到修复。

    PS。如果是我做错了什么……

    ...请张贴应该做的方式!我很高兴看到一个快速、简单且“干净”的解决方案。

    PS2。特别感谢:

    Jeppe Marianger-Lam 和用户友好(来自 IRC 上的#symfony2)。你一直很有帮助。干杯!

    【讨论】:

    • 感谢您发布如此详尽的问题并跟进您的解决方案,即使这是一种解决方法。你有没有设法找到一个“干净”的解决方案来解决这个问题?
    • 不,但我很快会再看看这个问题,因为新的 symfony 版本中可能会发生一些变化:)
    【解决方案4】:

    这是我以前做过的——我不知道这是否是“正确”的做法,但它确实有效。

    当您从提交的表单中获得结果时(即,就在if($form-&gt;isValid()) 之前或之后),只需询问角色列表,然后将它们全部从实体中删除(将列表保存为变量)。使用此列表,只需遍历所有内容,向存储库询问与 ID 匹配的角色实体,然后将这些添加到您的用户实体中 persistflush 之前。

    我刚刚搜索了 Symfony2 文档,因为我想起了一些关于 prototype 的表单集合,结果出现了:http://symfony.com/doc/current/cookbook/form/form_collections.html - 它提供了如何正确处理表单中的 javascript 添加和删除集合类型的示例。也许先试试这个方法,如果你不能让它工作,然后再试试我上面提到的方法:)

    【讨论】:

    • 关于 javascript:我确实阅读了这本食谱,并且我的 javascript 代码完全按预期工作(并且角色已正确发布到控制器)。问题纯粹是在 PHP 代码中的某个地方。我的表单类型或实体类一定有问题。
    • 你的解决方案是我2个月前第一次遇到这个问题时所做的。现在由于其他原因,我不得不重新制作我的表单/视图并且解决方法停止工作。我将发布案例 3,其中包含我遇到的错误。
    • 感谢帮助,由于我在回答中描述的原因,解决方法不起作用
    【解决方案5】:

    您需要更多实体:
    USER
    id_user(类型:整数)
    用户名(类型:文本)
    plainPassword(类型:密码)
    电子邮件(类型:电子邮件)



    id_group(类型:整数)
    描述(类型:文本)


    AVOROLES
    id_avorole(类型:整数)
    描述(类型:文本)


    *USER_GROUP*
    id_user_group(类型:整数)
    id_user (type:integer)(这是用户实体上的 id)
    id_group (type:integer)(这是组实体上的 id)


    *USER_AVOROLES*
    id_user_avorole(类型:整数)
    id_user (type:integer)(这是用户实体上的 id)
    id_avorole (type:integer)(这是 avorole 实体上的 id)


    你可以有这样的例子:
    用户:
    编号:3
    用户名:约翰
    普通密码:johnpw
    电子邮件:john@email.com


    组:
    id_group: 5
    描述:第 5 组


    用户组:
    id_user_group: 1
    id_user: 3
    id_group: 5
    *这个用户可以有很多组,所以在另一行 *

    【讨论】:

      猜你喜欢
      • 2012-02-13
      • 1970-01-01
      • 2013-09-19
      • 1970-01-01
      • 1970-01-01
      • 2018-06-17
      • 2011-12-03
      • 1970-01-01
      • 2021-11-20
      相关资源
      最近更新 更多