使用 Zend Framework 2 动态生成的表单

Dynamic generated form with Zend Framework 2

我正在创建 ZF2 轮询模块。我有很多问题的投票。每个问题都有可以是多个答案或单个答案(单选或多选框)的答案。如何创建可以显示给前端的动态表单?

这是我试过的方法,但表单验证不正确...

module\Polls\src\Polls\Form\PollFillingQuestionsForm.php

  <?php
    namespace Polls\Form;

    use Zend\Form\Form;
    use Polls\Form\Fieldset\PollFillingQuestionAnswerFieldset;
    use Polls\Form\Fieldset\PollFillingQuestionFieldset;

    class PollFillingQuestionsForm extends Form {

    public function __construct($questionsObject) {
        parent::__construct('questionsForm');

        $questionsFieldset = new PollFillingQuestionFieldset('questions');

    //$questionsObject is array of question objects.
        foreach ($questionsObject as $questionObject) {
            $fieldset = new PollFillingQuestionAnswerFieldset($questionObject->id, array(), $questionObject);
                $questionsFieldset->add($fieldset);
            }

            $this->add($questionsFieldset);

            $this->add(array(
                'name' => 'submit',
                'attributes' => array(
                    'type' => 'submit',
                    'value' => 'Submit Poll',
                    'class' => 'btn btn-success',
                ),
            ));
        }
    }

module\Polls\src\Polls\Form\Fieldset\PollFillingQuestionAnswerFieldset.php

<?php

namespace Polls\Form\Fieldset;

use Polls\Model\QuestionAnswer;
use Zend\Form\Fieldset;
use Zend\Stdlib\Hydrator\ArraySerializable;

class PollFillingQuestionAnswerFieldset extends Fieldset {

public function __construct($name, $options, $questionObject) {
    parent::__construct($name, $options);

    $question = $questionObject;

    $this->setLabel($question->title);

    $type = 'Radio';
    $elementType = 'radio';
    switch ($question->answer_type) {
        case 'many':
            $type = 'MultiCheckbox';
            $elementType = 'checkbox';
            break;
        case 'one':
            $type = 'Radio';
            $elementType = 'radio';
            break;
        default:
            $type = 'Radio';
            $elementType = 'radio';
            break;
    }
    $this->setHydrator(new ArraySerializable())
            ->setObject(new QuestionAnswer());

    $answers = $question->getAnswers();

    $answerValues = array();
    foreach ($answers as $answer) {
        $answerValues[$answer->id] = $answer->title;
    }
    $this->add(array(
        'name' => 'answer',
        'type' => $type,
        'options' => array(
            'type' => $elementType,
            'value_options' => $answerValues,
        ),
    ));
}
}

我过去曾这样做过,使用干净的工厂策略,您可以将依赖项注入表单和输入过滤器。魔法在于您的工厂。

首先在您的服务管理器配置中连接一些东西:

'form_elements' => [
    'factories' => [
        DynamicForm::class => DynamicFormFactory::class,
    ],
],

'input_filters' => [
    'factories' => [
        DynamicInputFilter::class => DynamicInputFilterFactory::class,          
    ],
],

首要任务是正确完成 FormFactory。

class DynamicFormFactory implements FactoryInterface, MutableCreationOptionsInterface
{

    /**
     * @var array
     */
    protected $options;

     /**
     * Set creation options
     *
     * @param  array $options
     * @return void
     */
    public function setCreationOptions( array $options )
    {
        $this->options = $options;
    }


    /**
     * {@inheritdoc}
     */
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        /**
         * @var \Zend\Form\FormElementManager       $serviceLocator
         * @var \Zend\ServiceManager\ServiceManager $serviceManager
         */
        $serviceManager = $serviceLocator->getServiceLocator();
        try
        {
            $options   = /* set up your form's config, you have the service manager here */;
            $form      = new DynamicForm( $options );

            $form->setInputFilter( $serviceManager->get('InputFilterManager')->get( DynamicFormFilter::class, $options ) );
        }
        catch( \Exception $x )
        {
            die( $x->getMessage() );
        }
        return $form;
    }       
}

然后,通过 MutableCreationOptionsInterface 实现对 DynamicInputFilterFactory 中的 $options 作出反应。您通常不希望表单和过滤器是 'option aware',让工厂来处理。

class DynamicInputFilterFactory implements FactoryInterface, MutableCreationOptionsInterface
{

    protected $options;

    /**
     * Set creation options
     *
     * @param  array $options
     * @return void
     */
    public function setCreationOptions( array $options )
    {
        $this->options = $options;
    }

    public function createService( ServiceLocatorInterface $serviceLocator )
    {
        /* do stuff with $this->options */

        return new DynamicInputFilter(
             /* pass your transformed options */
        );
    }   
}

接下来,您所要做的就是根据通过 MutableOptions 传递给它们的内容创建表单和输入过滤器。在 __construct 中设置您的依赖项(不要忘记调用 parent::__construct)并根据传入的选项在 init 中初始化您的表单。

我怀疑你在 ZF2 中有很好的基础,所以我就到此为止了。这应该会让你上路。要点是 MutableCreationOptionsInterface 并将 InputFilter 和 Form 构造分开,将两者结合到 Form Factory 中。