使用数组/Doctrine2绑定并保存带有集合字段的表单



我有两个实体

Room.php

/**
 * @ORMTable(name="room")
 * @ORMEntity(repositoryClass="AhsioStackBundleRepositoryRoomRepository")
 */
class Room
{
    /**
     * @ORMId
     * @ORMColumn(type="integer")
     * @ORMGeneratedValue(strategy="AUTO")
     */
     protected $id;
     // ...    
    /**
     * @ORMOneToMany(targetEntity="AhsioStackBundleEntityWorkstation", mappedBy="room", cascade={"persist", "remove"}, orphanRemoval=true)
     */
     protected $workstations;

工作站.php

/**
 * @ORMTable(name="workstation")
 * @ORMEntity(repositoryClass="AhsioStackBundleRepositoryWorkstation")
 */
 class Workstation
 {
    /**
     * @ORMId
     * @ORMColumn(type="integer")
     * @ORMGeneratedValue(strategy="AUTO")
     */
     private $id;
    /**
     * @ORMManyToOne(targetEntity="AhsioStackBundleEntityRoom")
     * @ORMJoinColumn(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)。

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

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(AhsioStackBundleEntityRoom)#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) {
    }
 }

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

这是我的控制器代码的一部分,我正在使用它来测试更新。。。

        // 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();
        }

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

尝试通过添加跟踪来查看是否调用了它。

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

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

你可能应该试着打电话给:

$em->merge($room);

在与表单数据绑定之前。这样,您将从数据库中恢复数据,剩下的工作由orphanRemoval完成

另外,你不应该用Request而不是用数据对象来bind你的表单吗?

最新更新