2015-03-02 59 views
0

我有一个带表单集合元素的ZF2表单。我有教条2实体。我将这个实体绑定到表单上。 这里是我的代码: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; 

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

回答

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; 
0

我有两个实体(角色&权限),一个ID我的角色实体存在,名称和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" 
     } 
    } 
    } 
} 

要更新/清除权限,我将数据从窗体发送到我的Rol eDao:

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(); 
    } 
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的水化器的情况下,提示他们移除集合中没有的元素。