2013-02-28 4 views
5

Einführung

arbeite ich durch eine wiederverwendbare Admin-Modul; verantwortlich für die Handhabung von Authentifizierung und ACL. Dieses Modul verfügt über einen Basiscontroller, den jedes andere implementierte Modul erben kann. Also dieser Controller ist der Cp\AdminController und ist nicht zugänglich, aber geerbt von allen anderen Controllern.Zend Framework 2 - Ausgabeformularelement, Objekte als HTML Felder

Das Problem

Ich habe einen Standard/home-Controller Cp\HomeController, die mehrere Aktionen hat; Einloggen, abmelden und vergessen/Passwort zurücksetzen. Momentan arbeite ich an der Cp\HomeController::indexAction. Innerhalb dieser Methode kann ich einfach folgendes:

// ... 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 ... 

Die Frage ist hier, die Cp\HomeController verwendet standardmäßig die ./module/Cp/view/cp/home/index.phtml Vorlage; und wie folgt aussieht:

<h1>Authorisation Required</h1> 

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

ich Zend\Form mit meiner eigenen Form Klasse ./module/Cp/src/Cp/Form.php verlängert haben, wird dieser dann erweitert durch beliebige Formularklassen. _Bedenken Sie, ich werde diese Klasse in die App verschieben, so dass sie vollständig entkoppelt und vollständig wiederverwendbar ist.

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

ich erben diese Formularklasse, um meine Login-Formular zu erstellen, eine Standard-E-Mail-Adresse und Passwort-Feld, etwas, das wiederverwendet werden kann überall Authentifizierung auftreten können.

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

Welche die geerbte __toString Methode wird die definierte Formularansicht, nehmen und es macht. Diese ist, wo mein Problem ist, und meine Frage auftritt. In der Ansicht (siehe unten) versuche ich, das Formular zu erstellen, indem ich das Framework verwende, ohne die HTML-Elemente hart zu codieren. Da die Cp\Form\Login Klasse könnte erweitert und modifiziert werden, mit einem anderen Feld oder zusätzliche Felder, optional oder obligatorisch oder bedingt.

Gibt es eine Möglichkeit, schnell, Zend zu bekommen, um das folgende HTML zu generieren? Ohne Teilansichten zu verwenden oder physisch zu schreiben <input type="<?= ... ?>" name="<?= ... ?>" />. Dies liegt daran, dass die Attribute innerhalb der Controller definiert oder überschrieben werden können, daher sind die Attribute zu diesem Zeitpunkt unbekannt. und sollte offen für Flexibilität sein.

<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> 

Hoffentlich ist dies klarer, als zuvor.

+0

Wenn es eine Form zu machen, ohne zu wissen, war, wie es gebaut ist, könnten Sie einfach 'echo $ this-> form ($ form);'. Können Sie bitte klären, was die genaue Frage ist? – Ocramius

+0

Ich habe die Frage aktualisiert, ich hoffe, meine Frage und Absichten sind klarer – ash

Antwort

4

Ich bin mir nicht sicher, was Ihre eigentliche Frage ist. Kannst du es bitte explizit angeben?

Zend\Form ist so ausgelegt, dass sie sich nicht machen wird, sondern durch View Helfer gemacht wird:

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

Sie könnten natürlich einen View Helfer schreiben, dass dies für Sie tut.

Alternativ können Sie einen View Helfer schreiben, die eine Liste von Elementen nimmt zu machen und einen View Helfer zu schreiben, die so etwas wie dies funktioniert:

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

Dann alles, was Sie in Ihrer Ansicht Skript brauchen, ist renderForm() anrufen .

+0

Ich denke, Ash fragt nach einer Möglichkeit, das Formular ohne den Einsatz von Helfern zu rendern, wie es in sein eigenes Ansichtsmodell (als Kind von das Ansichtsmodell, das einen anderen Renderer verwendet) – Ocramius

+0

oh! Der einfachste Weg, dies zu tun, besteht darin, das Formular ServiceManager zu aktivieren und dann einen PHPRenderer innerhalb einer render() -Methode abzurufen und dort die View-Helfer zu verwenden. –

+0

Sorry Leute, ich habe meinen Artikel neu geschrieben, ich hoffe, es ist etwas klarer. Ich denke, meine ursprüngliche Frage war zweideutig. @Ocramius - genau das versuche ich zu erreichen. – ash

0

Antwort Robs Mit baute ich meine eigenen Helfer verschiedene Felder als Text zu machen (Beispiel ist eine Stiftung 5 Zeile):

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