title: Zend Framework 2 - Output form element, objects as HTML fields
body: <h1>Introduction</h1>
  
  <p>I'm working through a re-usable Admin module; responsible for handling Authentication, and ACL.  This module comes with a base controller that any other module implemented can inherit.  So this controller is the <code>Cp\AdminController</code> and isn't accessible, but inherited by all other controllers.</p>
  
  <h1>The problem</h1>
  
  <p>I have a default/home controller <code>Cp\HomeController</code> that has several actions; login, logout and forgotten/reset password.  Currently i'm working on the <code>Cp\HomeController::indexAction</code>.  Within this method I simply do the following:</p>
  
  <pre><code>// ... controller logic ...
  public function indexAction()
  {
      if ($this-&gt;getAuth()-&gt;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' =&gt; $loginForm
          );
      }
  }
  // ... controller logic ...
  </code></pre>
  
  <p>The issue here is, the <code>Cp\HomeController</code> by default, uses the <code>./module/Cp/view/cp/home/index.phtml</code> template; and looks like:</p>
  
  <pre><code>&lt;h1&gt;Authorisation Required&lt;/h1&gt;
  
  &lt;section id="admin-login"&gt;
      &lt;?= $form ?&gt;
  &lt;/section&gt;
  </code></pre>
  
  <p>I have extended <code>Zend\Form</code> with my own form class <code>./module/Cp/src/Cp/Form.php</code>, this is then extended by any form classes. _Bare in mind, I will move this class into the App so that it's entirely decoupled and completely reusable.</p>
  
  <pre><code>&lt;?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-&gt;__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-&gt;__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' =&gt; $this-&gt;__templatePath
          ));
  
          // Define the render instance responsible for rendering the form.
          $renderer = new PhpRenderer();
          $renderer-&gt;setResolver(new Resolver\TemplateMapResolver($map));
  
          // The form view model will generate the form; parsing the vars to it.
          $view = new ViewModel();
          $view-&gt;setVariable('form', $this);
          $view-&gt;setTemplate('form');
  
          foreach ($this-&gt;__viewVariables as $key =&gt; $value) {
              if (! property_exists($view, $key)) {
                  $view-&gt;setVariable($key, $value);
              }
          }
  
          return $renderer-&gt;render($view);
      }
  }
  </code></pre>
  
  <p>I inherit this form class in order to create my Login form, a standard e-mail address and password field, something which can be re-used anywhere authentication may occur.</p>
  
  <pre><code>&lt;?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-&gt;setTemplatePath(MODULE_DIR . 'Cp/view/cp/form/login.phtml');
  
          // Create our form elements, and validation requirements.
          $email = new Element\Email('email');
          $email-&gt;setLabel('E-mail Address');
  
          $password = new Element\Password('password');
          $password-&gt;setLabel('Password');
  
          $submit = new Element\Submit('login');
  
          $this-&gt;setAttribute('action', $action)
              -&gt;setAttribute('method', 'post')
              -&gt;setAttribute('autocomplete', 'autocomplete')
              -&gt;add($email)
              -&gt;add($password)
              -&gt;add($submit);
      }
  }
  </code></pre>
  
  <p>Which the inherited <code>__toString</code> method will take the defined form view, and render it. <em>This</em> is where my problem is, and my question occurs.  Within the view (see below) I am trying to create the form, by using the framework, without hard-coding the HTML elements.  Since the <code>Cp\Form\Login</code> class could be extended and modified, with a different field, or additional fields, optional or mandatory, or conditionally either.</p>
  
  <p>Is there a way to quickly, get Zend to generate the following HTML? Without using partial views or physically writing <code>&lt;input type="&lt;?= ... ?&gt;" name="&lt;?= ... ?&gt;" /&gt;</code>.  This is because the attributes can be defined or overwritten inside the controllers, thus, the attributes are unknown at this point; and should be open to flexibility.</p>
  
  <pre><code>&lt;section class="authentication-form"&gt;
      &lt;h2&gt;Authentication Required&lt;/h2&gt;
  
      &lt;!-- How-to:  Generate the &lt;form&gt; tag and all it's attributes. --&gt;
      &lt;?= $form-&gt;openTag() ?&gt;
  
      &lt;? if ($ipAllowed): ?&gt;
          &lt;p&gt;Please choose an account to log in through.&lt;/p&gt;
  
          &lt;fieldset&gt;
              &lt;?= $form-&gt;get('email') ?&gt;
          &lt;/fieldset&gt;
      &lt;? else: ?&gt;
          &lt;p&gt;Please log in using your e-mail address and password.&lt;/p&gt;
  
          &lt;fieldset&gt;
              &lt;?= $form-&gt;get('email') ?&gt;
              &lt;?= $form-&gt;get('password') ?&gt;
          &lt;/fieldset&gt;
      &lt;? endif ?&gt;
  
      &lt;div class="action"&gt;
          &lt;!-- How-To:  Generate the &lt;input type="submit" name="" ... attributes ... /&gt;
          &lt;?= $form-&gt;get('login') ?&gt;
      &lt;/div&gt;
  
      &lt;!-- How-To: Generate the form close tag.
      &lt;?= $form-&gt;closeTag() ?&gt;
  &lt;/section&gt;
  </code></pre>
  
  <p>Hopefully this is more clearer, than previously.</p>