包含多个集合的表单

时间:2017-08-14 20:17:48

标签: php oop zend-framework2 zend-form

我想要实现一个非常简单的表单。使事情复杂化的唯一因素是我在表单中使用了两个集合。在视图中显示两个集合就像一个魅力。问题是表格的绑定实体的验证和相关的水合作用。如果所有都经过验证并且没有错误发生,那么表单实例会尝试使绑定​​实体保持水合并最终出现异常:

  

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方法添加多个对象,以便可以处理两个集合?替代品看起来像什么?我做错了什么?

0 个答案:

没有答案