4

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

我有一个对象被调用Node并将它绑定到一个表单。我正在使用Zend\Stdlib\Hydrator\ArraySerializable-Standard-Hydrator。所以我的Node-object 有两种方法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-object 之后,node_namenode_body-properties 现在包含来自提交表单的值。然而,所有其他字段现在都是空的,即使它们之前包含初始值。

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

4 回答 4

3

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

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

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

$form = $this->_getForm();
$form->setHydrator(new \Zend\Stdlib\Hydrator\ObjectProperty()); // Change default hydrator
于 2012-12-26T22:21:24.387 回答
2

类 form.php 中有一个 bug,在 bindvalues 方法中没有初始化过滤器,只需添加行$filter->setData($this->data);

包含该行后应该是这样的

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 行

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

于 2012-12-26T09:10:20.977 回答
1

我遇到了同样的问题,但 Raj 的解决方案不是正确的方法。这不是一个错误,因为在没有 Raj 的“修复”的情况下,代码仍然相似,添加以下行:

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

这里的主要问题是当您将对象绑定到表单时,输入过滤器不会存储在 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;
}
于 2015-02-09T15:38:47.043 回答
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->data 中的所有现有数据。

我对其进行了如下调整:

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->data 中的任何现有键,如果它们从传入的新数据中丢失。这种方法的唯一缺点是我不能再使用 exchangeArray() 来覆盖 $this->data 中保存的所有内容。在我的项目中,这种方法是一次性的,所以它不是一个大问题。此外,在任何情况下都可能首选新的replaceAllData()overwrite()方法,如果没有其他原因,只是很明显它的作用。

于 2013-09-26T10:15:21.817 回答