zf2表单和对象绑定,不清除未传递的值

时间:2012-12-25 10:32:13

标签: php zend-form zend-framework2

我已经阅读了Zend-Framework 2中Form-Component的教程/参考资料,也许我错过了它,所以我在这里问。

我有一个名为Node的对象并将其绑定到表单。我正在使用Zend\Stdlib\Hydrator\ArraySerializable - Standard-Hydrator。所以我的Node - 对象有exchangeArray()getArrayCopy()这两种方法:

class Node
{
    public function exchangeArray($data)
    {
        // Standard-Felder
        $this->node_id        = (isset($data['node_id']))   ? $data['node_id']   : null;
        $this->node_name      = (isset($data['node_name'])) ? $data['node_name'] : null;
        $this->node_body      = (isset($data['node_body'])) ? $data['node_body'] : null;
        $this->node_date      = (isset($data['node_date'])) ? $data['node_date'] : null;
        $this->node_image     = (isset($data['node_image'])) ? $data['node_image'] : null;
        $this->node_public    = (isset($data['node_public'])) ? $data['node_public'] : null;
        $this->node_type      = (isset($data['node_type'])) ? $data['node_type']:null;
        $this->node_route      = (isset($data['node_route'])) ? $data['node_route']:null;
    }

    public function getArrayCopy()
    {
        return get_object_vars($this);
    }
}

在我的控制器中,我有一个editAction()。在那里,我想修改此Node - 对象的值。所以我正在使用我的表单的bind - 方法。我的表单只有字段来修改node_namenode_body - 属性。验证表单并在提交表单后转储Node - 对象后,node_namenode_body - 属性现在包含提交表单中的值。但是现在所有其他字段都是空的,即使它们之前包含初始值。

class AdminController extends AbstractActionController
{
    public function editAction()
    {
        // ... more stuff here (getting Node, etc)             

        // Get Form
        $form = $this->_getForm(); // return a \Zend\Form instance
        $form->bind($node); // This is the Node-Object; It contains values for every property

        if(true === $this->request->isPost())
        {
            $data = $this->request->getPost();
            $form->setData($data);

            // Check if form is valid
            if(true === $form->isValid())
            {
                // Dumping here....
                // Here the Node-object only contains values for node_name and node_body all other properties are empty
                echo'<pre>';print_r($node);echo'</pre>';exit;
            }
        }

        // View
        return array(
            'form' => $form,
            'node' => $node,
            'nodetype' => $nodetype
        );
    }
}

我想只覆盖来自表单(node_namenode_body)而不是其他表单的值。它们应该保持不变。

我认为一个可能的解决方案是将其他属性作为隐藏字段添加到表单中,但我不想这样做。

是否有可能不覆盖表单中不存在的值?

4 个答案:

答案 0 :(得分:3)

我重新检查了\ Zend \ Form的代码,说实话,我只是猜到了如何解决我的问题。

我唯一改变的是Hydrator。似乎Zend\Stdlib\Hydrator\ArraySerializable不适用于我的情况。由于我的Node - 对象是一个对象而不是一个数组,我检查了其他可用的水合器。我找到了Zend\Stdlib\Hydrator\ObjectProperty - 保湿剂。它完美地运作。只有表单中可用的字段才会填充在绑定对象中。这正是我需要的。似乎ArraySerializable - hydrator重置了对象属性,因为它调用绑定对象的exchangeArray - 方法(Node)。在这种方法中,我将非给定字段设置为null(请参阅我的问题中的代码)。另一种方法可能是更改exchangeArray - 方法,因此只有在它们不可用时才设置值。

所以代码中的解决方案很简单:

$form = $this->_getForm();
$form->setHydrator(new \Zend\Stdlib\Hydrator\ObjectProperty()); // Change default hydrator

答案 1 :(得分:2)

类form.php中存在一个错误,过滤器未在bindvalues方法中初始化,只需添加 $ filter-&gt; setData($ this-&gt; data); < / p>

在包含行

后,它应该如下所示
public function bindValues(array $values = array())
{
    if (!is_object($this->object)) {
        return;
    }
    if (!$this->hasValidated() && !empty($values)) {
        $this->setData($values);
        if (!$this->isValid()) {
            return;
        }
    } elseif (!$this->isValid) {
        return;
    }

    $filter = $this->getInputFilter();
    $filter->setData($this->data);          //added to fix binding empty data
    switch ($this->bindAs) {
        case FormInterface::VALUES_RAW:
            $data = $filter->getRawValues();
            break;
        case FormInterface::VALUES_NORMALIZED:
        default:
            $data = $filter->getValues();
            break;
    }

    $data = $this->prepareBindData($data, $this->data);

    // If there is a base fieldset, only hydrate beginning from the base fieldset
    if ($this->baseFieldset !== null) {
        $data = $data[$this->baseFieldset->getName()];
        $this->object = $this->baseFieldset->bindValues($data);
    } else {
        $this->object = parent::bindValues($data);
    }
}

很珍贵,我的zf2.0.6库中的第282行

这可以解决您的问题,这只发生在绑定对象情况

答案 2 :(得分:1)

我遇到了同样的问题,但Raj的解决方案不是正确的方法。这不是一个错误,因为今天代码保持相似而没有Raj的“修复”,添加了一行:

$filter->setData($this->data);

这里的主要问题是当您将对象绑定到表单时,inputfilter不存储在Form对象中。但每次都从绑定的对象调用。

public function getInputFilter()
    ...
    $this->object->getInputFilter();
    ...
}

我的问题是我在调用函数getInputFilter时每次创建一个新的InputFilter对象。所以我更正了以下内容:

protected $filter;
...
public function getInputFilter {
    if (!isset($this->filter)) {
        $this->filter = new InputFilter();
        ...
    }
    return $this->filter;
}

答案 3 :(得分:0)

我今天遇到了同样的问题,但修复Raj建议不起作用。我正在使用最新版本的ZF2(截至撰写本文时),所以我并不感到惊讶它不起作用。

由于我的属性保存在数组中,因此无法更改为另一个Hydrator。 ObjectProperty和ClassMethods水槽都依赖于实际声明的属性(ObjectProperty使用 object_get_vars 而ClassMethods使用 property_exists )。我不想创建自己的Hydrator(懒惰!)。

相反,我坚持使用ArraySerializable水合器并略微改变了我的exchangeArray()方法。

原来我有:

public function exchangeArray(array $data)
{
    $newData = [];
    foreach($data as $property=>$value)
    {
        if($this->has($property))
        {
            $newData[$property] = $value;
        }
    }
    $this->data = $newData;
}

大部分时间都可以正常工作,但正如您所看到的那样,它会消除$ this-&gt;数据中的所有现有数据。

我把它调整如下:

public function exchangeArray(array $data)
{
    $newData = [];
    foreach($data as $property=>$value)
    {
        if($this->has($property))
        {
            $newData[$property] = $value;
        }
    }
    //$this->data = $newData; I changed this line...
    //to...
    $this->data = array_merge($this->data, $newData);
}

这保留了$ this-&gt;数据中的任何现有密钥,如果新数据中缺少这些密钥。这种方法的唯一缺点就是我不能再使用exchangeArray()来覆盖$ this中包含的所有内容。 ;数据。在我的项目中,这种方法是一次性的,所以这不是一个大问题。此外,新的 replaceAllData() overwrite()方法在任何情况下都可能是首选,如果除了明显的原因之外别无其他原因。