Zend Framework 2 - 输出表单元素,对象作为HTML字段

ash*_*ash 5 zend-framework2

介绍

我正在研究一个可重复使用的管理模块; 负责处理身份验证和ACL.该模块附带一个基本控制器,实现的任何其他模块都可以继承.所以这个控制器是Cp\AdminController并且不可访问,但是由所有其他控制器继承.

问题

我有一个默认/家庭控制器Cp\HomeController,有几个动作; 登录,注销和忘记/重置密码.目前我正在努力Cp\HomeController::indexAction.在这种方法中,我只需执行以下操作:

// ... controller logic ...
public function indexAction()
{
    if ($this->getAuth()->hasIdentity()) {
        # XXX: This is the authorised view/dashboard.
    } else {
        # XXX: This is the unauthorised view; login page.

        $loginForm = new Form\Login();

        # XXX: validation, and login form handling here.

        return array(
            'form' => $loginForm
        );
    }
}
// ... controller logic ...
Run Code Online (Sandbox Code Playgroud)

这里的问题是,Cp\HomeController默认情况下,使用./module/Cp/view/cp/home/index.phtml模板; 看起来像:

<h1>Authorisation Required</h1>

<section id="admin-login">
    <?= $form ?>
</section>
Run Code Online (Sandbox Code Playgroud)

我扩展Zend\Form了自己的表单类./module/Cp/src/Cp/Form.php,然后由任何表单类扩展._Bare,我会将这个类移到应用程序中,以便它完全解耦并完全可重用.

<?php
// @file: ./module/Cp/src/Cp/Form.php

namespace Cp;

use Zend\Form\Form as ZendForm;
use Zend\Form\Fieldset;
use Zend\InputFilter\Input;
use Zend\InputFilter\InputFilter;
use Zend\View\Model\ViewModel;
use Zend\View\Renderer\PhpRenderer;
use Zend\View\Resolver;

class Form extends ZendForm
{
    /**
     * Define the form template path.
     * @var String
     */

    protected $__templatePath;

    /**
     * Define the view variables.
     * @var Array
     */

    protected $__viewVariables = array();

    /**
     * Set the view variable.
     * @param String $key The index for the variable.
     * @param Mixed $value The value for the view variable.
     * @return Cp\Form
     */

    public function set($key, $value)
    {
        $this->__viewVariables[$key] = $value;
        return $this;
    }

    /**
     * Set the template path.
     * @param String $path The path for the template file.
     * @return Cp\Form
     */

    public function setTemplatePath($path)
    {
        $this->__templatePath = $path;
        return $this;
    }

    /**
     * When the object is buffered in output, we're going to generate the view
     * and render it.
     * @return String
     */

    public function __toString()
    {
        // Define our template file as form for resolver to map.
        $map = new Resolver\TemplateMapResolver(array(
            'form' => $this->__templatePath
        ));

        // Define the render instance responsible for rendering the form.
        $renderer = new PhpRenderer();
        $renderer->setResolver(new Resolver\TemplateMapResolver($map));

        // The form view model will generate the form; parsing the vars to it.
        $view = new ViewModel();
        $view->setVariable('form', $this);
        $view->setTemplate('form');

        foreach ($this->__viewVariables as $key => $value) {
            if (! property_exists($view, $key)) {
                $view->setVariable($key, $value);
            }
        }

        return $renderer->render($view);
    }
}
Run Code Online (Sandbox Code Playgroud)

我继承了这个表单类,以便创建我的登录表单,一个标准的电子邮件地址和密码字段,可以在任何可能发生身份验证的地方重复使用.

<?php

namespace Cp\Form;

use Zend\Form\Element;

class Login extends \Cp\Form
{
    public function __construct($name = 'Login', $action)
    {
        // Parse the form name to our parent constructor.
        parent::__construct($name);

        // Override default template, defining our form view.
        $this->setTemplatePath(MODULE_DIR . 'Cp/view/cp/form/login.phtml');

        // Create our form elements, and validation requirements.
        $email = new Element\Email('email');
        $email->setLabel('E-mail Address');

        $password = new Element\Password('password');
        $password->setLabel('Password');

        $submit = new Element\Submit('login');

        $this->setAttribute('action', $action)
            ->setAttribute('method', 'post')
            ->setAttribute('autocomplete', 'autocomplete')
            ->add($email)
            ->add($password)
            ->add($submit);
    }
}
Run Code Online (Sandbox Code Playgroud)

继承的__toString方法将采用定义的表单视图,并呈现它.就是我的问题,我的问题出现了.在视图中(见下文)我试图通过使用框架创建表单,而无需对HTML元素进行硬编码.由于Cp\Form\Login可以扩展和修改类,使用不同的字段或其他字段,可选的或强制的,或者有条件的.

有没有办法快速,让Zend生成以下HTML?不使用部分视图或物理写入<input type="<?= ... ?>" name="<?= ... ?>" />.这是因为可以在控制器内定义或覆盖属性,因此,此时属性是未知的; 并应灵活开放.

<section class="authentication-form">
    <h2>Authentication Required</h2>

    <!-- How-to:  Generate the <form> tag and all it's attributes. -->
    <?= $form->openTag() ?>

    <? if ($ipAllowed): ?>
        <p>Please choose an account to log in through.</p>

        <fieldset>
            <?= $form->get('email') ?>
        </fieldset>
    <? else: ?>
        <p>Please log in using your e-mail address and password.</p>

        <fieldset>
            <?= $form->get('email') ?>
            <?= $form->get('password') ?>
        </fieldset>
    <? endif ?>

    <div class="action">
        <!-- How-To:  Generate the <input type="submit" name="" ... attributes ... />
        <?= $form->get('login') ?>
    </div>

    <!-- How-To: Generate the form close tag.
    <?= $form->closeTag() ?>
</section>
Run Code Online (Sandbox Code Playgroud)

希望这比以前更清楚.

Rob*_*len 4

我不确定你的实际问题是什么。您能明确指定吗?

Zend\Form被设计为不渲染自身,而是由视图助手渲染:

<?php
echo $this->form()->openTag($this->form);
echo $this->formCollection($this->form);
echo $this->form()->closeTag($this->form);
Run Code Online (Sandbox Code Playgroud)

您当然可以编写一个视图助手来为您完成此操作。

或者,您可以编写一个视图助手来获取要渲染的元素列表,并编写一个执行如下操作的视图助手:

<?php
namespace MyModule\View\Helper;

use Zend\View\Helper\AbstractHelper;


class RenderForm extends AbstractHelper
{
    public function __invoke($fieldsToRender, $form)
    {
        $html = $this->view->form()->openTag($form) . PHP_EOL;

        foreach ($fieldsToRender as $fieldName) {
            $element = $form->get($fieldName);
            $html .= $this->view->formRow($element) . PHP_EOL;
        }

        $html .= $this->view->form()->closeTag($form) . PHP_EOL;

        return $html;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您在视图脚本中所需要做的就是调用renderForm().