【问题标题】:Bind and save a form with a collection field using an array / Doctrine2使用数组 / Doctrine2 绑定并保存带有集合字段的表单
【发布时间】:2012-03-09 16:02:01
【问题描述】:

我有两个实体

Room.php

/**
 * @ORM\Table(name="room")
 * @ORM\Entity(repositoryClass="Ahsio\StackBundle\Repository\RoomRepository")
 */
class Room
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
     protected $id;

     // ...    

    /**
     * @ORM\OneToMany(targetEntity="Ahsio\StackBundle\Entity\Workstation", mappedBy="room", cascade={"persist", "remove"}, orphanRemoval=true)
     */
     protected $workstations;

和workstation.php

/**
 * @ORM\Table(name="workstation")
 * @ORM\Entity(repositoryClass="Ahsio\StackBundle\Repository\Workstation")
 */
 class Workstation
 {
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
     private $id;

    /**
     * @ORM\ManyToOne(targetEntity="Ahsio\StackBundle\Entity\Room")
     * @ORM\JoinColumn(name="room_id", referencedColumnName="id", nullable=false)
     */
     private $room;

     // ...

我添加了一个带有集合字段的房间类型,用于添加/更新/删除工作站

RoomType.php

class RoomType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder
            ->add('id', 'hidden', array(
                'read_only' => true,
            ))
            // ....
            ->add('workstations', 'collection', array(
                 'type'         => new WorkstationType(),
                 'allow_add'    => true,
                 'allow_delete' => true,
                 'by_reference' => false,
            ))
        ;
     }
     // ...
}

工作站类型很简单,只有两个字段(id 和number)。

问题是,当我尝试将 RoomType 绑定到现有 Room(其中包含两个 id 为(1 和 2)的工作站)与以下数组(仅包含两个工作站之一)时:

array(4) {
  ["id"]=> string(1) "3"
  ["workstations"]=> array(1) {
    [0]=> array(2) {
      ["id"]=> int(1)
      ["number"]=> int(200)
     }
  }

更新完成,id=2 的工作站被删除。但是当我尝试删除给定房间的所有工作站时,使用:

array(4) {
  ["id"]=> string(1) "3"
  ["workstations"]=> array(0) {
  }

工作站还在那里,我所做的绑定执行得很好,这是我在使用最后一个给定的数组绑定我的 $form 后执行 $form->getData() 时得到的结果:

object(Ahsio\StackBundle\Entity\Room)#229 (4) {
    ["id":protected]=> string(1) "3"
    ["name":protected]=> string(20) "first room (updated)"
    ["description":protected]=> string(39) "This first room is an old one (updated)"
    ["workstations":protected]=> array(0) {
    }
 }

因此,更新后的 Room 没有工作站。有人能告诉我为什么我坚持最后一个绑定的房间时我的工作站没有被删除吗?

这是我用来测试更新的控制器代码的一部分...

        // The Room $id is given ... 
        $roomArray = array(
        'id'           => $id, 
        'name'         => 'first room (updated)',
        'description'  => 'This first room is an old one (updated)',
            'workstations' => array(),
        );
        $form     = $this->createForm(new RoomType(), $room);      

        $form->bind($roomArray);

        if ($form->isValid()) {
            $em = $this->getDoctrine()->getEntityManager();
            $em->persist($room);
            $em->flush();
        }

【问题讨论】:

  • 你好,艾哈迈德,你好吗?您能否在第 113 和 146 行的 src/Symfony/Component/Form/Extension/Core/EventListener/ResizeFormListener.php 中设置一个断点(如果您使用的是最新版本的 Symfony)并告诉我们发生了什么? +1 有趣的问题
  • 你好格雷瓜尔!我很好,你怎么样?当我在 ResizeFormListener.php(第 113 行)中设置断点时,我得到一个空数组array(0) { },用于使用没有任何工作站的房间数组进行更新。即使我为这个阵列设置了一个或多个工作站,它也会出现并且工作正常。 form->remove($name) 是使用每个工作站的数组索引执行的。我认为问题与绑定无关。

标签: forms symfony doctrine-orm


【解决方案1】:

我认为接收workstations 数组的setter 永远不会被调用,因为数组是空的。

加个trace试试看是否调用。

此外,您应该在工作站映射中添加 cascade="merge" 选项。

【讨论】:

  • 它被调用并将一个空数组传递给房间的工作站,我认为这是正确的行为。
  • 我接受了这个答案,因为它帮助我弄清楚了如何解决这个问题。我稍后会更新你的答案。
【解决方案2】:

我认为在尝试更新和删除实体/相关实体时不应调用persist。

你或许应该尝试调用:

$em->merge($room);

在绑定表单数据之前。这样您就可以从数据库中恢复数据,而 orphanRemoval 应该完成剩下的工作。

另外,您不应该在bind 表单中使用Request 而不是使用数据对象吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-12
    • 2014-08-25
    相关资源
    最近更新 更多