2013-02-28 49 views
5

简介

我正在通过可重用的Admin模块工作;负责处理认证和ACL。该模块附带一个基础控制器,其他模块可以继承。所以这个控制器是Cp\AdminController并且不可访问,但是被所有其他控制器继承。Zend Framework 2 - 输出表单元素,作为HTML字段的对象

问题

我有一个缺省的/ home控制器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 ... 

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

<h1>Authorisation Required</h1> 

<section id="admin-login"> 
    <?= $form ?> 
</section> 

我有我自己的表单类./module/Cp/src/Cp/Form.php扩展Zend\Form,这然后通过任何形式的类扩展。 _请记住,我会将这个类移入应用程序,以便它完全解耦并且完全可重用。

<?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); 
    } 
} 

我为了创建我的登录表单,一个标准的电子邮件地址和密码字段,这东西可以再任何地方使用,可能会发生认证继承这个窗体类。

<?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); 
    } 
} 

哪个继承__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> 

希望这比以前更清晰。

+0

如果是有关呈现形式,根本不知道它是如何构建的,你可以只需'echo $ this-> form($ form);'。你能否澄清一下确切的问题是什么? – Ocramius 2013-02-28 08:40:50

+0

我已经更新了这个问题,我希望我的问题和意图更清晰 – ash 2013-02-28 09:27:04

回答

4

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

Zend\Form的设计使得它不表现自己,而是由视图助手渲染:

<?php 
echo $this->form()->openTag($this->form); 
echo $this->formCollection($this->form); 
echo $this->form()->closeTag($this->form); 

你当然可以写,这是否给你一个视图助手。

或者,您可以编写需要的元素的列表来呈现,写,做这样的事情一个视图助手视图助手:

<?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; 
    } 
} 

然后你在你的视图脚本需要的是调用renderForm()

+0

我认为Ash正在寻求一种不使用帮助器的方式来呈现表单,例如将其封装到自己的视图模型中(设置为使用其他渲染器的视图模型) – Ocramius 2013-02-28 08:38:23

+0

哦!最简单的方法是使ServiceManager识别表单,然后在render()方法中检索PHPRenderer,并在其中使用视图助手。 – 2013-02-28 09:08:06

+0

对不起,我重写了我的文章,希望它更清楚一点。我想我的原始问题是不明确的。 @Ocramius - 这正是我想要完成的。 – ash 2013-02-28 09:19:11

0

使用Rob的回应,我建立了自己的助手来解析不同领域的文本(例如是基金会5行):

namespace MyApp\View\Helper; 

use Zend\Form\View\Helper\FormRow; 
use Zend\Form\ElementInterface; 


class RenderForm extends AbstractHelper 
{ 
    public function __invoke(ElementInterface $element) 
    { 

     $html = ''; 
     $value = ''; 

     $attributes = $element->getAttributes(); 

     $type = $attributes['type']; 
     $label = $element->getLabel(); 

     if($type == 'text' or $type == 'textarea' or $type == 'datetime' or $type == 'hidden'){ 
      $value = $element->getValue(); 
     } 

     if($type == 'select'){ 
      $selectedValue = $element->getValue(); 
      if(is_bool($selectedValue)){ 
       $selectedValue = (int) $selectedValue; 
      } 
      $options = $element->getValueOptions(); 
      $values = ''; 
      foreach($options as $value => $option){ 
       if((!empty($value) or $value == 0) and $value === $selectedValue){ 
        $values .= $option . '<br />'; 
       } 
      } 
      $value = $values; 
     } 

     if($type == 'multi_checkbox' ){ 
      $selectedOptions = $element->getValue(); 
      $options   = $element->getValueOptions(); 
      $values = ''; 
      foreach($options as $option){ 
       $optionValue = $option[ 'value' ]; 
       if( in_array($optionValue, $selectedOptions)){ 
        $values .= $option[ 'label' ]. '<br />'; 
       } 
      } 

      $value = $values; 
     } 

     if($value == ''){ 
      $value = 'N/A'; 
     } 

     $html .= '<div class="row"> 
         <div class="small-12 column"> 
          <div class="row"> 
           <div class="small-3 columns"><label class="right inline" for="tag_id">' . $label . '</label></div> 
           <div class="small-9 columns left" style="padding-top:10px">' . $value . '</div> 
          </div> 
         </div> 
        </div>'; 
     return $html; 
    } 
}