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 Cp\AdminController
and isn't accessible, but inherited by all other controllers.
I have a default/home controller Cp\HomeController
that has several actions; login, logout and forgotten/reset password. Currently i'm working on the Cp\HomeController::indexAction
. Within this method I simply do the following:
// ... 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 ...
The issue here is, the Cp\HomeController
by default, uses the ./module/Cp/view/cp/home/index.phtml
template; and looks like:
<h1>Authorisation Required</h1>
<section id="admin-login">
<?= $form ?>
</section>
I have extended Zend\Form
with my own form class ./module/Cp/src/Cp/Form.php
, 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.
<?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);
}
}
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.
<?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);
}
}
Which the inherited __toString
method will take the defined form view, and render it. This 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 Cp\Form\Login
class could be extended and modified, with a different field, or additional fields, optional or mandatory, or conditionally either.
Is there a way to quickly, get Zend to generate the following HTML? Without using partial views or physically writing <input type="<?= ... ?>" name="<?= ... ?>" />
. 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.
<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>
Hopefully this is more clearer, than previously.
I'm unsure what your actual question is. Could you specify it explicitly please?
Zend\Form
is designed so that it doesn't render itself, but is rendered by view helpers:
<?php
echo $this->form()->openTag($this->form);
echo $this->formCollection($this->form);
echo $this->form()->closeTag($this->form);
You could of course write a view helper that does this for you.
Alternatively, you could write a view helper that takes a list of elements to render and write a view helper that does something like this:
<?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;
}
}
Then all you need in your view script is to call renderForm()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With