我有一个带有表单集合元素的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()方法,您将看到如果数据为空则它什么都不做。
答案 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的保湿器,则提示他们删除不在集合中的元素。