Symfony2实体集合-如何添加/删除与现有实体的关联?


69

1.快速概述

1.1目标

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

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

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

1.2用户界面

我的模板包括2个部分:

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

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

1.3所需功能

1.3.1添加角色:

    WHEN用户点击“+”(添加)按钮,在角色表  
    THEN jQuery的删除了从角色表行  
      jQuery的添加新的列表项用户表单(avoRoles名单)

1.3.2删除角色:

    WHEN用户点击“X”(删除)按钮,用户形式(avoRoles列表)  
     THEN jQuery的删除了从用户的形式(avoRoles列表)列表项  
      jQuery的增加了新的行角色表

1.3.3保存更改:

    WHEN用户点击“Zapisz”(保存)按钮,  
    那么用户表单提交的所有字段(用户名,密码,电子邮件,avoRoles,团体)  
      保存avoRoles为角色的实体(多对多关系)的ArrayCollection  
      保存群体的角色实体的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 RoleNameType

这种形式应该呈现:

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

模块和描述显示为隐藏字段,因为当Admin从用户删除角色时,该角色应由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 \ generateValue(strategy =“ AUTO”)* /受保护的$ id;

3.2情况2:在角色实体中为ID属性添加了设置器

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

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版本2.0.15

4.2教义2 v2.1.7

4.3 FOSUserBundle版本:6fb81861d84d460f1d070ceb8ec180aac841f7fa

5.总结

我已经尝试了许多不同的方法(以上只是最新的方法),并且花了几个小时研究代码,谷歌搜索并寻找答案后,我才无法正常工作。

任何帮助将不胜感激。如果您需要了解任何信息,我会张贴您需要的任何代码部分。


31
+1是我很久以来见到的最广泛且写得很好的问题之一。
杰普·玛丽亚·兰姆

问题可能出在Form类型。您能否在RoleNameType“自定义字段类型呈现项目而不是项目”中阐明注释。
kgilden 2012年

哦,我忘了用&lt;书写“ <span>项目”和“ <input>项目”。和&gt; -因此,在我的问题中忽略了这些元素(作为不接受的html元素)
ioleo 2012年

我不喜欢这个冗长的问题,因为我必须找到并搜索“问题” /“问题”才能开始提供帮助-.-
Jakob Alexander Eichler,2012年

此代码有效且有效吗?$ roles = $ em-> getRepository('AvocodeUserBundle:Role')-> findById($ owned_roles); 我从教义和ZF来之前从未见过它
雅各布·亚历山大·埃希勒

Answers:


13

我得出的结论是,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...
    }
}

多谢分享。现在,我正在处理应用程序的不同部分,但是当我要查看/修改应用程序的代码时,我将尽力为您提供解决方案。
ioleo 2012年

10

一年过去了,这个问题变得很流行。此后,Symfony发生了变化,我的技能和知识也得到了改善,因此我目前针对此问题的方法也有所改善。

我为symfony2创建了一组表单扩展(请参阅github上的FormExtensionsBundle项目),其中包括用于处理一个/多个ToMany关系的表单类型。

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

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

看一下EventListener / CollectionUploadListener.php文件,看看我们现在如何处理它。

PS。无需在此处复制代码,最重要的是,此类事件实际上应在EventListener中处理。


8

1.解决方法

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

1.1为什么在我的情况下它停止工作?

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

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

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

    <span>角色名称</ span>

并且由于它不是“只读”的,因此FORM组件有望在POST中获得NAME。

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

这导致案例2(3.2)->创建关联,但用空字符串覆盖角色名称。

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表单类型不完整。

symfony 2.1中的Form组件有一些重大更改,希望可以解决此问题。

PS。如果是我做错了...

...请发布应做的方式!我很高兴看到一个快速,简单和“干净”的解决方案。

PS2。特别感谢:

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


感谢您发布如此详尽的问题并跟进您的解决方案,即使这是一种解决方法。您是否曾经设法找到解决此问题的“干净”方法?
RobMasters 2012年

不,但是我很快会再看这个问题,因为新的symfony版本可能有所改变:)
ioleo 2012年

6

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

当您从提交的表单中获得结果时(即,在之前或之后if($form->isValid())),只需询问角色列表,然后将其全部从实体中删除(将列表另存为变量)。有了这个名单,只是通过他们所有的回路,要求相匹配的ID的角色实体库,和你之前添加这些到您的用户实体persistflush

我刚刚搜索了Symfony2文档,因为我想起了一些有关prototype表单集合的知识,并且发现了以下内容:http : //symfony.com/doc/current/cookbook/form/form_collections.html-它包含有关如何正确处理的示例。 javascript在表单中添加和删除集合类型。也许先尝试这种方法,然后再尝试上面提到的内容,如果您无法使它起作用:)


关于javascript:我确实阅读了本食谱,并且我的javascript代码完全按预期工作(并且ROLES已正确发布到控制器中)。问题纯粹是在PHP代码中的某个地方。我的表单类型或实体类一定有问题。
ioleo 2012年

您的解决方案是两个月前我第一次遇到此问题时所做的。现在由于其他原因,我不得不重新制作表单/视图,并且解决方法停止了工作。我将在案例3中发布错误消息。
ioleo 2012年

寻求帮助,该变通方法由于我在答案中描述的原因而无法正常工作
ioleo 2012年

0

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


GROUPS
id_group(类型:整数)说明
(类型:文本)


AVOROLES
id_avorole(类型:整数)说明
(类型:文本)


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


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


例如,您可以输入以下内容:
用户:
id:3
用户名:john
plainPassword:johnpw
电子邮件:john@email.com


组:
id_group:5说明
:组5


user_group:
id_user_group:1
id_user:3
id_group:5
*该用户可以有多个组,因此在另一行中*

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.