获取表单助手以自动使用cakephp 3.0 beta2确定默认值

时间:2014-10-22 09:27:03

标签: xml cakephp cakephp-3.0

我正在开发一个应该处理XML数据的Web应用程序,当我尝试编辑之前保存的数据时,我遇到了一些问题。

这就是我从一开始就要做的事情:用户必须填写一个包含多个输入的表单,我在控制器中获取数据,将其转换为带有Xml :: fromArray的XML字符串并将其存储在一个数据库字段。这完美地工作,生成的XML字符串正是我需要的。这是表格的一部分。

echo $this->Form->input('data.FT.Header.Transmission.Number');
echo $this->Form->input('data.FT.Header.Transmission.Format');
echo $this->Form->input('data.FT.Header.Transmission.Destination');

现在我正在尝试为该数据添加编辑功能。从我的控制器中获取数据,将其转换回具有Xml :: build的对象......这就是问题开始的地方。

如果我这样做

debug($invoice->data->FT->Header->Transmission);

一切看起来都很好,因为它告诉我我有一个包含它的对象:

object(SimpleXMLElement) {
    Number => 'Npslu'
    Format => 'Rgytz'
    Destination => 'Uheac'
}

但是,如果我试图查看$ invoice-> data-> FT-> Header-> Transmission-> Number包含,而不是字符串,我得到一个空结果。这就是为什么(我认为)所有表单输入都是空的。

我查看了官方文档,尝试将其转换为数组(这应该是cakephp处理数据的旧方式)以及我想到的所有内容......仍然没有结果。

我做错了什么?


更新:我设法以这种(脏)的方式创建一个工作对象:

$array = Xml::toArray( Xml::build( $xmlString ) );
$object = json_decode(json_encode($array), FALSE);

现在,如果我调试$ invoice-> data-> FT-> Header-> Transmission我有正确的值,这在我的情况下向前迈出了一大步:)

问题是Form帮助程序仍然无法识别该值。如果我在我的编辑模板中有这个

echo $this->Form->input('data.FT.Header.Transmission.Number');

然后该字段为空。如果我以这种方式指定其值

echo $this->Form->input('data.FT.Header.Transmission.Number', array('value' => $invoice->data->FT->Header->Transmission->Number);

它可以正常工作。我知道我可以指定每个值,但我想自动拥有它,就像我在该页面中的其他字段(非XML相关)一样,例如$ invoice->发送,这被$ this-正确识别>形状配合>输入( '发送')...


更新2:这是XML生成的代码:

<?xml version="1.0" encoding="UTF-8"?>
<FT>
   <Header>
      <Transmission>
         <Number>1234</Number>
         <Format>qwer</Format>
         <Destination>asdf</Destination>
      </Transmission>
   </Header>
</FT>

这些是我用来将输入字段的值转换为XML并返回的函数:

// Values to XML, called from the add function this way:
// $this->request->data['data'] = $this->_arrayToXml($this->request->data['data']);
protected function _arrayToXml($array) {
    $xmlObject = Xml::fromArray($array);
    $xmlString = $xmlObject->asXML();
    return $xmlString;
}
// XML to Values, called from the edit function this way:
// $invoice->data = $this->_xmlToObject($invoice->data);
protected function _xmlToObject($xmlString) {
    $array = Xml::toArray( Xml::build( $xmlString ) );
    $object = json_decode(json_encode($array), FALSE);
    return $object;
}

P.S。请原谅我,如果你看到一些小的不一致,我试图剥离所有不相关的代码,以避免发布大量的代码......

1 个答案:

答案 0 :(得分:2)

清空SimpleXMLElement个对象

返回的对象实际上不是空的,Cakes debug()函数只能处理SimpleXMLElement之类的对象,其中值未明确存储在属性中。使用var_dump()或投放价值,您就会看到它在那里:

var_dump($invoice->data->FT->Header->Transmission);
debug((string)$invoice->data->FT->Header->Transmission);

神秘解决了。

表格输入中未显示的值

现在为什么表格输入中出现的值不是?好吧,表单中的数据是通过context providers访问的,因为您传递的是实体,所以表单使用实体上下文提供程序。

如果实体提供程序在请求对象中不可用,则该实体提供程序会尝试从该实体获取数据,这是尚未提交的编辑表单的情况。这里的问题是提供者无法处理您的数据结构,它需要嵌套实体,而不是数组或标准/ SimpleXML对象。

实现您要做的事情的最简单方法是始终设置请求数据,以便实体上下文提供程序不会尝试从实体获取数据,但始终从实体获取数据请求数据(参见EntityContext::val())。类似的东西:

<强>控制器

public function edit($id = null) {
    // ...
    if ($this->request->is(['post', 'put'])) {
        // convert array input data to XML string
        $this->request->data['data'] =
            Xml::fromArray($this->request->data['data'])->asXML();

        $invoice = $this->Invoices->patchEntity($invoice, $this->request->data);
        if ($this->Invoices->save($invoice)) {
            // ...
        }
    }

    // convert XML string to array
    $this->request->data['data'] = XML::toArray(Xml::build($invoice->data));

    // ...
    $this->set(compact('invoice'));
}

这样,在获取输入数据时不会触及实体,一切都应该正常工作。

一种可能更清洁的方法

可能更简洁但更复杂的方法可能是使用转换数据的自定义数据类型,以及可以处理对XML对象的点标记路径访问的自定义上下文提供程序。这样就不需要在控制器中进行任何特殊的转换等。

然而,这并不是问题/问题的真正部分,所以我只是通过提供一些示例(未经过彻底测试)来提及这一主题。

XML数据类型

这会将从数据库中检索到的字符串转换为实体将要公开的XML对象,并将数组请求输入数据编组为XML字符串

namespace App\Database\Type;

use Cake\Database\Driver;
use Cake\Database\Type;
use Cake\Utility\Xml;

class XmlType extends Type {

    public function toPHP($value, Driver $driver)
    {
        if($value === null)
        {
            return null;
        }
        return Xml::build($value);
    }

    public function marshal($value) {
        return Xml::fromArray($value)->asXML();
    }

}

XML实体背景

如果需要,它将从XML对象中提取数据。外部部分是从原始Entity::val()方法复制的。

namespace App\View\Form;

use Cake\ORM\Entity;
use Cake\View\Form\EntityContext;

class XmlEntityContext extends EntityContext
{
    public function val($field) {
        $val = $this->_request->data($field);
        if ($val !== null) {
            return $val;
        }
        if (empty($this->_context['entity'])) {
            return null;
        }
        $parts = explode('.', $field);
        $entity = $this->_getEntity($parts);

        // begin: special XML element treatment
        if($entity instanceof \SimpleXMLElement)
        {
            array_shift($parts);
            return current($entity->xpath('/' . implode('/', $parts)));
        }
        // end: special XML element treatment

        if (end($parts) === '_ids' && !empty($entity)) {
            return $this->_extractMultiple($entity, $parts);
        }

        if ($entity instanceof Entity) {
            return $entity->get(array_pop($parts));
        }
        return null;
    }
}

查看

有关详细信息,请查看