ZF2形成集合和学说2

时间:2015-03-02 09:38:45

标签: php zend-framework doctrine-orm zend-framework2 zend-form

我有一个带有表单集合元素的ZF2表单。我有教义2实体。我将此实体绑定到表单。 这是我的代码:

$form->bind($entity); // $entity->roles is not empty. It has two elements
$form->setData($someData); // $someData['roles'] is empty array
if ($form->isValid()) {
    $form->get('roles')->getCount(); // 2(!) it is not empty!
    saveToDb($entity);
}
return $form;

表单集合的名称是“roles”。在将数据设置为表单之前,您可以看到我绑定了实体。 当用户想要更新实体时,实体已经具有值。例如,表单集合中已有两个值。例如,用户想清除角色,$ someData数组有空角色。问题是$ form-> setData不清除角色集合。如何清除这个系列?如果您将查看Collection :: populateValues()方法,您将看到如果数据为空则它什么都不做。

3 个答案:

答案 0 :(得分:1)

似乎与此错误相关:https://github.com/zendframework/zf2/issues/4492

可能的临时解决方案可能是:

if (empty($someData['roles'])) {
    $entity->setRoles(array());
}
$form->bind($entity);
$form->setData($someData);
if ($form->isValid()) {
    saveToDb($entity);
}
return $form;

答案 1 :(得分:0)

我有两个实体(角色和权限),我的角色实体存在id,name和权限实体的ArrayCollections:

object(Authorization\Entity\Role)#525 (3) {
  ["id":protected] => 1
  ["name":protected] => string(7) "admin"
  ["permissions":protected] => object(Doctrine\Common\Collections\ArrayCollection)#524 (1) {
    ["_elements":"Doctrine\Common\Collections\ArrayCollection":private] => array(4) {
      [1] => object(Authorization\Entity\Permission)#527 (2) {
        ["id":protected] => int(1)
        ["name":protected] => "createUser"
      }
      [2] => object(Authorization\Entity\Permission)#529 (2) {
        ["id":protected] => int(2)
        ["name":protected] => "updateUser"
      }
      [3] => object(Authorization\Entity\Permission)#526 (2) {
        ["id":protected] => int(3)
        ["name":protected] => "createRole"
      }
      [4] => object(Authorization\Entity\Permission)#528 (2) {
        ["id":protected] => int(4)
        ["name":protected] => "updateRole"
      }
    }
  }
}

要更新/清除权限,我将表单中的数据发送到我的RoleDao:

public function update(RoleViewObject $roleVO) {
        // Find VO by using the getId() function to update
        // the right VO object
        $role = $this->getRoleById($roleVO->getId());

        // Delete all permissions from VO <--- I think this is what you need
        $role->getPermissions()->clear();

        // Add updated permissions to VO
        foreach($roleVO->getPermissions() as $permissionId => &$permissionVO) {
            $permissionName = $permissionVO->getName();
            if(empty($permissionName)) {
                $role->getPermissions()->set($permissionVO->getId(), $this->entityManager->getReference('Authorization\Entity\Permission', $permissionVO->getId()));
            }
        }

        $this->entityManager->persist($role);
        $this->entityManager->flush();
    }

答案 2 :(得分:0)

实际的问题是,Zend表单不会打扰尚未发送的值,如果清空集合,您只需不发送任何数据 ,这就是表单忽略集合的原因,导致表单和/或其字段集没有告诉他们的保存者对集合进行任何更改。

最终,您可以归咎于this函数,该函数会删除从传递给“setData”的数组中未表示的表单中提取的过滤数据。

我设法通过覆盖表单的“setData”函数来解决此问题,以额外处理传递的数据,以包含仍在字段集中但未在数据数组中表示的集合的空数组:

namespace Module\Form;

class Form extends \Zend\Form\Form
{
    /**
     * Fill the passed data array with placeholder arrays for collections
     * existing in the passed fieldset (and its sub-fieldsets) but not
     * represented in the data array.
     * 
     * @param \Zend\Form\FieldsetInterface $fieldset
     * @param array $data
     * @return array
     */
    protected static function assertCollectionPlaceholders(\Zend\Form\FieldsetInterface $fieldset, array $data)
    {
        foreach ($fieldset as $name => $elementOrFieldset) {
            if (!$elementOrFieldset instanceof \Zend\Form\FieldsetInterface) {
                continue;
            }

            if (array_key_exists($name, $data) && is_array($data[$name])) {
                $data[$name] = static::assertCollectionPlaceholders($elementOrFieldset, $data[$name]);
            } else if ($elementOrFieldset instanceof \Zend\Form\Element\Collection) {
                $data[$name] = array();
            }
        }

        return $data;
    }

    /**
     * Set data to validate and/or populate elements
     *
     * Typically, also passes data on to the composed input filter.
     *
     * @see \Zend\Form\Form
     * @param  array|\ArrayAccess|Traversable $data
     * @return self
     * @throws \Zend\Form\Exception\InvalidArgumentException
     */
    public function setData($data)
    {
        if ($data instanceof \Traversable) {
            $data = \Zend\Stdlib\ArrayUtils::iteratorToArray($data);
        }

        if (!is_array($data)) {
            throw new \Zend\Form\Exception\InvalidArgumentException(sprintf(
                '%s expects an array or Traversable argument; received "%s"',
                __METHOD__,
                (is_object($data) ? get_class($data) : gettype($data))
            ));
        }

        $data = static::assertCollectionPlaceholders($this, $data);

        $this->hasValidated = false;
        $this->data         = $data;
        $this->populateValues($data);

        return $this;
    }
}

通过这样做,表格和/或其字段集告诉他们的水合物集合是空的,如果是Doctrine的保湿器,则提示他们删除不在集合中的元素。