我想要实现一个非常简单的表单。使事情复杂化的唯一因素是我在表单中使用了两个集合。在视图中显示两个集合就像一个魅力。问题是表格的绑定实体的验证和相关的水合作用。如果所有都经过验证并且没有错误发生,那么表单实例会尝试使绑定实体保持水合并最终出现异常:
Zend \ Hydrator \ ArraySerializable :: hydrate期望提供的对象实现exchangeArray()或populate()
但首先是示例代码......
表单类
namespace Application\Form;
use Zend\Form\Element\Collection;
use Zend\Form\Element\Text;
use Zend\Form\Form;
class MyForm extends Form
{
public function __construct($name = '', $options = [])
{
parent::__construct($name, $options);
$this->setAttribute('method', 'post');
$this->setAttribute('id', 'my-form');
}
public function init()
{
$this->add([
'name' => 'my-text-field',
'type' => Text::class,
'attributes' => [
...
],
'options' => [
...
],
]);
// The first collection
$this->add([
'name' => 'first-collection',
'type' => Collection::class,
'options' => [
'count' => 2,
'should_create_template' => true,
'template_placeholder' => '__index__',
'allow_add' => true,
'allow_remove' => true,
'target_element' => [
'type' => FieldsetOne::class,
],
],
]);
// the second collection
$this->add([
'name' => 'second-collection',
'type' => Collection::class,
'options' => [
'count' => 2,
'should_create_template' => true,
'template_placeholder' => '__index__',
'allow_add' => true,
'allow_remove' => true,
'target_element' => [
'type' => FieldsetTwo::class,
],
],
]);
}
}
绑定到集合的已提到的Fieldset类看起来几乎相同。
namespace Application\Form;
use Zend\Form\Element\Number;
use Zend\Form\Fieldset;
use Zend\InputFilter\InputFilterProviderInterface;
class FieldsetOne extends Fieldset implements InputFilterProviderInterface
{
public function init()
{
$this->add([
'name' => 'my-number',
'type' => Number::class,
'options' => [
...
],
'attributes' => [
...
],
]);
}
public function getInputFilterSpecification()
{
return [
'my-number' => [
'required' => true,
'filters' => [
[
'name' => StripTags::class,
],
[
'name' => ToInt::class,
],
],
'validators' => [
[
'name' => NotEmpty::class,
],
[
'name' => IsInt::class,
'options' => [
'locale' => 'de_DE',
],
],
],
],
];
}
}
总结表单得到了两个数字元素集合。通过表单提供的所有数据应最终出现在以下实体中。
输入过滤器类
表单会被以下输入过滤器过滤和验证。输入过滤器将通过工厂绑定到表单。工厂将在稍后展出。
class MyFormInputFilter extends InputFilter
{
public function init()
{
$this->add([
'name' => 'my-text-field',
'required' => true,
'filters' => [
[
'name' => StripTags::class,
],
[
'name' => StringTrim::class,
],
],
]);
}
}
输入过滤器仅包含my-text-field
元素的设置。将使用设置为目标元素的字段集中的已实现InputFilterProviderInterface
验证集合。输入过滤器类是在工厂创建的,并在input_filters
的{{1}}部分中标注。
表单实体
实体将作为对象绑定到工厂中的表单,如下例所示。
module.config.php
此实体将作为对象绑定到表单。表格将被水化为zend自己的namespace Application\Entity;
class MyFormEntity
{
protected $myTextField;
protected $firstCollection;
protected $secondCollection;
public function getMyTextField()
{
return $this->myTextField;
}
public function setMyTextField($myTextField)
{
$this->myTextField = $myTextField;
return $this;
}
public function getFirstCollection()
{
return $this->firstCollection;
}
public function setFirstCollection(array $firstCollection)
{
$this->firstCollection = $firstCollection;
return $this;
}
public function getSecondCollection()
{
return $this->secondCollection;
}
public function setSecondCollection(array $secondCollection)
{
$this->secondCollection = $secondCollection;
return $this;
}
}
保湿剂类。对于收集品,将两种水合物策略添加到水化器中。收藏品的保湿策略看起来像这样。
ClassMethods
此策略将数据从集合1水合到相应的实体。
全部包含在工厂中
这是创建表单实例的工厂。
namespace Application\Hydrator\Strategy;
class FirstCollectionStrategy extends DefaultStrategy
{
public function hydrate($value)
{
$aEntities = [];
if (is_array($value)) {
foreach ($value as $key => $data) {
$aEntities[] = (new ClassMethods(false))->hydrate($data, new CollectionOneEntity());
}
}
return $aEntities;
}
}
此工厂在class MyFormFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$parentLocator = $serviceLocator->getServiceLocator();
$filter = $parentLocator->get('InputFilterManager')->get(MyFormInputFilter::class);
$hydrator = (new ClassMethods())
->addStrategy('first-collection', new FirstCollectionStrategy())
->addStrategy('second-collection', new SecondCollectionStrategy());
$object = new MyFormEntity();
$form = (new MyForm())
->setInputFilter($filter)
->setHydrator($hydrator)
->setObject($object);
return $form;
}
}
文件的form_elements
部分提及。
问题
一切正常。 input元素以及集合在视图中呈现。如果表单已提交且控制器中调用module.config.php
方法,则所有方法都以$form->isValid()
结尾。
Zend \ Hydrator \ ArraySerializable :: hydrate期望提供的对象实现exchangeArray()或populate()
我没有将收集实体绑定到控制器中的表单,因为水化器策略被添加到表单水合器中,该水合器应该使表单实体保持水合。这对我来说很有意义,因为zend表单只能绑定一个对象。如果我在控制器中调用BadMethodCallException
方法两次,则第一个绑定对象将被覆盖。
是否可以使用表单的bind
方法添加多个对象,以便可以处理两个集合?替代品看起来像什么?我做错了什么?