Override default Zend_Form element renderer with custom HTML template? - php

I'm dissatisfied with the way Zend_Form renders form elements by default, and want to override it for all forms produced by instantiating a helper class I have that inherits from Zend_Form to take care of some things that I do on all of my forms.
The changes I want to make seem more complicated than is reasonable/possible with decorators, so I'd like to use a custom HTML template to accomplish this, where I get to plug form values into a custom HTML snippet.
How can I set all HTML elements rendered by my class to use an HTML template? And what properties/functions should I call from the template to get the stuff Zend_Form renders by default? Lastly, I would prefer to do this without having to manually set the template on each input element I create in my code.

You can extend the defualt Zend_Form class with your own Custom_Form class. In the init() method overwrite the default element decorators. Here my code snippet:
//class Custom_Form extends Zend_Form
public function init()
{
$this->setElementDecorators(
array(array('ViewScript', array('viewScript' => '/controller_name/forms/fields/input-text.phtml'))),
array('email', 'firstname', 'lastname')
);
}

I've done my share of coding with ZF1 and the best way I found to render nice forms was to use Twitter Bootstrap along with it.
Check the following links to see if that's also a satisfactory solution for you too:
how to use the twitter bootstrap framework in a zend framework 1 application?
http://twitter.github.io/bootstrap/

I wound up using a custom viewscript that I genericized to work with arbitrary forms.
Using this approach, I was able to do the following things:
Add an asterisk after the label of required form elements
Group inputs and errors together in one div, so that when I float the labels to the left things still line up
Add a special class to erroring inputs so I can highlight them
Change certain error messages to include the name of the element instead of "Value"
Pass a text note along with the form elements to be displayed under the input
Not wrap labels and inputs in special elements
Some of these things are impossible without a viewscript, and some are just a pain to implement. I think this solution will be much more flexible for me going forward.
In my helper class' render() function:
$view = new Zend_View();
$view->setBasePath(SRC_ROOT . "/templates/forms");
$this->setDecorators(array(array('ViewScript', array('viewScript' => 'viewscript.php'))));
And here's my viewscript:
<link rel="stylesheet" type="text/css" href="/styles.css" />
<form id="<?php echo $this->element->html_id ?>" class="<?php echo $this->element->html_class ?>" enctype="application/x-www-form-urlencoded" action="" method="post">
<?php foreach($this->element as $element) { ?>
<?php
$decorators = $element->getDecorators();
if(isset($decorators["Zend_Form_Decorator_Label"])) {
$label = $element->getLabel();
} else {
$label = "";
}
if($element->isRequired() === true) {
$label .= " *";
}
?>
<label class="label" for="<?php echo $element->getName(); ?>"><?php echo $label; ?></label>
<div class="formInput">
<?php
// Add the error class to make the form inputs highlight in red
if($element->hasErrors()) {
$attribs = $element->getAttribs();
if(!isset($attribs["class"])) {
$attribs["class"] = "";
}
$attribs["class"] .= " inputError";
$element->setAttribs($attribs);
}
// Print the input using Zend_Form's own mechanisms
$element->setDecorators(array('ViewHelper')); // Removes all decorators (labels, etc.)
$v = new Zend_View();
$element->setView($v);
echo $element->render();
if(isset($element->note)) {
echo "<p>{$element->note}</p>";
}
// Print the error messages
if($element->hasErrors()) {
$errors = $element->getMessages();
?>
<ul class="errors <?php echo sizeof($errors) == 1 ? "noDecorations" : "" ?>">
<?php
foreach($errors as $error => $message) {
// Custom error messages
if($error === "isEmpty") {
$message = $element->getLabel() . " cannot be empty";
} ?>
<li><?php echo $message ?></li>
<?php } ?>
</ul>
<?php } ?>
</div>
<div style="float: clear;"></div>
<?php } ?>
</form>

Related

ZF2 Render Custom Class on Form Validation Error

How can I wrap a fieldset tag around my form rows, and how can I add a has-danger class to the fieldset when an element fail to validate?
I think I need to create a viewhelper, check if a specific formelement has a validation message and wrap the row with a fieldset, but I'm not sure if that's the right approach or how to do it.
The output I want on validation error:
<fieldset class="has-danger"><label for="username">Username</label>
<input type="text" name="username" id="username" class="form-control
input-error" value="f"><ul><li>Needs to be 5-20 characters long</li>
</ul></fieldset>
register.phtml:
<?php
$form = $this->registerForm;
$form->prepare();
echo $this->form()->openTag($form);
echo $this->formHidden($form->get('secret'));
echo $this->formRow($form->get('username'));
echo $this->formRow($form->get('password'));
echo $this->formRow($form->get('email'));
echo $this->formRow($form->get('confirm-email'));
echo $this->formSubmit($form->get('submit'));
echo $this->form()->closeTag($form);
Ok, you should use the formLabel(), formElement() and formElementErrors() view helpers instead of formRow().
To my ZF2 knowledge, the formRow() view helper doesn't let you have control on the HTML output easily. It displays the complete input HTML (label + input + errors) in one line of code.
To simply achieve your goal, your phtml structure for one input has to be as follow :
// NAME_OF_YOUR_FILE.phtml
<?php
$userNameInput = $form->get('username');
$userNameInputErrors = $this->formElementErrors($userNameInput);
?>
<fieldset class="<?= $userNameInputErrors ? 'has-danger' : '' ?>" >
<?= $this->formLabel($userNameInput) ?>
<?= $this->formElement($userNameInput) ?>
<?= $userNameInputErrors ?>
</fieldset>
This is a hard work to do this for each fields in form, so I suggest you to put this logic in a view helper.
// MyFormRow.php
<?php
namespace Your\Namespace;
use Zend\View\Helper\AbstractHelper;
class MyFormRow extends AbstractHelper
{
protected $formLabelViewHelper;
protected $formElementViewHelper;
protected $formElementErrorsViewHelper;
public function __construct($formLabelViewHelper, $formElementViewHelper, $formElementErrorsViewHelper)
{
$this->formLabelViewHelper = $formLabelViewHelper;
$this->formElementViewHelper = $formElementViewHelper;
$this->formElementErrorsViewHelper = $formElementErrorsViewHelper;
}
public function __invoke($formElement)
{
$html = '';
$errors = $this->formElementErrorsViewHelper->__invoke($formElement);
$html .= '<fieldset class=" . ($errors ? 'has-danger' : '') . ">';
$html .= $this->formLabelViewHelper->__invoke($formElement);
$html .= $this->formElementViewHelper->__invoke($formElement);
$html .= $errors;
$html .= '</fieldset>';
return $html;
}
}
?>
Declare it in your Module.php.
// In your Module.php
<?php
...
public function getViewHelperConfig()
{
return [
'factories' => [
'myFormRow' => function (HelperPluginManager $helperPluginManager) {
$formLabelViewHelper = $helperPluginManager->get('formLabel');
$formElementViewHelper = $helperPluginManager->get('formElement');
$formElementErrorsViewHelper = $helperPluginManager->get('formElementErrors');
return new MyFormRow($formLabelViewHelper, $formElementViewHelper, $formElementErrorsViewHelper);
},
],
];
}
?>
And now in your phtml file, simply :
// NAME_OF_YOUR_FILE.phtml
...
<?= echo $this->myFormRow($form->get('username')) ?>
...

placeholder attribute in zf2

How could insert the value of a field's db in the plcaholder in zf2
<div class="form_element">
<?php
$this->placeholder('name')->data = $this->data;
$name = $form->get('name');
echo $formLabel->openTag().$name->getOption('label')." ";
echo $this->formInput($name);
echo $formLabel->closeTag();
?>
</div>
A placeholder is a ViewHelper and therefore is is designed to help render view content.
In order to use your database data witin a placeholder you will need to ensure that the data is first passed to the view from the controller action.
public function modificaAlumnoAction()
{
//...
return ViewModel('data' => $data); // data passed to the view instance
}
Then within the view script
// modifica-alumno.phtml
$this->placeholder('foo')->data = $this->data;
An finally output the data (such as within the layout)
// layout.phtml
echo $this->placeholder('foo)->data;

ZF2 Seperate HTML from Recursive PHP function(s)

I'm trying to seperate the HTML elements from the PHP code within Zend Framework 2, but I have no clue on how to solve this problem/seperate. Im currently echo'ing those HTML elements, which does the job. But there must be a way to seperate the HTML from PHP, instead of echo'ing the HTML elements.
At the moment I made a viewhelper which helps me to let me generate this treeMap for other modules aswell, since those will also use this feature, aslong as this helper is given with a treeMap. The categoryTreeMap contains a treemap of category (Doctrine 2 ORM) objects.
This is what I've got so far:
namespace Application\View\Helper;
use Zend\View\Helper\AbstractHelper;
class CategoryTreeMapHelper extends AbstractHelper
{
public function __invoke($categoryTreeMap)
{
echo "<ol class=\"sortable\">";
foreach ($categoryTreeMap as $category) {
$this->showCategories($category);
}
echo "</ol>";
}
public function showCategories($category)
{
echo "<li><div>" . $category->name . "</div>";
if (isset($category->childs)) {
echo "<ol>";
foreach ($category->childs as $child_category) {
$this->showCategories($child_category);
}
echo "</ol>";
}
echo "</li>";
}
}
Any suggestions on how to solve this, by seperating the HTML from the PHP echo's.
If your helper solely consist of those two methods, you can replicate the functionality in templates by making use of the partial helper
Create a partial for your treemap container
// view/partial-treemap.phtml
<ol class="sortable">
<?php foreach ($this->categoryTreeMap as $category) :
echo $this->partial('partial-category', array('category' => $category));
endforeach; ?>
</ol>
Create a partial for the recursive part (which calls itself recursively for children)
// view/partial-category.phtml
<li>
<div><?php echo $category->name; ?></div>
<?php if (isset($category->childs)) : ?>
<ol>
<?php foreach ($category->childs as $child_category) :
echo $this->partial('partial-category', array('category' => $child_category));
endforeach; ?>
</ol>
<?php endif; ?>
</li>
Then in your controller action view you only need one line
<?php echo $this->partial('partial-treemap', array('categoryTreeMap' => $categoryTreeMap)); ?>

Lithium form helper data and errors missing?

I am building a test Lithium app to learn how it works and I found that the form helper doesn't seem to recognise my data being passed back or any validation errors.
At the moment I'm having to manually pass back my errors and then process them in the view.
QuestionsController::ask
public function ask() {
if (!empty($this->request->data)) {
$question = Questions::create($this->request->data);
if ($question->save()) {
return $this->redirect(array('Questions::view', 'args'=>$question->id));
} else {
$errors = $question->errors();
}
if (empty($question)) {
$question = Questions::create();
}
return compact('question', 'errors');
}
}
views/questions/ask.html.php
<?php
// Assign the protected object to a variable so we can get at it
if(isset($question)){
$data = $question->data();
}else{
$data['title'] = '';
$data['text'] = '';
}
?>
<?=$this->form->create();?>
<?=$this->form->field('title', array('placeholder'=>'Title your question', 'value'=>$data['title']));?>
<?php if(isset($errors['title'])){
echo "<div class='alert alert-error'><a class='close' data-dismiss='alert' href='#'>×</a>";
foreach($errors['title'] as $e){
echo $e."<br/>";
}
echo "</div>";
}?>
<?=$this->form->field('text', array('placeholder'=>'Enter your question (supports Markdown)', 'type'=>'textarea', 'value'=>$data['text']));?>
<?php if(isset($errors['text'])){
echo "<div class='alert alert-error'><a class='close' data-dismiss='alert' href='#'>×</a>";
foreach($errors['text'] as $e){
echo $e."<br/>";
}
echo "</div>";
}?>
<p>Text input supports <?php echo $this->html->link('markdown', 'http://en.wikipedia.org/wiki/Markdown');?></p>
<?=$this->form->submit('Ask', array('class'=>'btn'));?>
<?=$this->form->end();?>
I can see from the lithium\template\helper\Form that the field() method can take a template parameter, which in the example is <li{:wrap}>{:label}{:input}{:error}</li> so there is capacity in the helper for displaying the validation messages.
So how do I organise my data in my controller so that it's passed back to the view in order for the helper to populate my fields and also display errors?
Edit
I should add that the example 'Sphere' app, also uses this method, so is it standard? (ref)
TL;DR
the short answer is that you can bind the form to a subclass of Entity, i.e. a Record or Document as shown in Form::create() (link is shortened as :: breaks the link parser).
your code would look like:
<?= $this->form->create($question); ?>
<?= $this->form->field('title'); ?>
<?= $this->form->field('text'); ?>
Long answer:
QuestionsController::ask():
public function ask() {
$question = Questions::create();
if (!empty($this->request->data)) {
if ($question->save($this->request->data)) {
return $this->redirect(array('Questions::view', 'args'=>$question->id));
}
}
return compact('question');
}
views/questions/ask.html.php:
<?= $this->form->create($question); ?>
<?= $this->form->field('title', array('placeholder'=>'Title your question'));?>
<?= $this->form->field('text', array('placeholder'=>'Enter your question (supports Markdown)', 'type'=>'textarea'));?>
<p>Text input supports <?php echo $this->html->link('markdown', 'http://en.wikipedia.org/wiki/Markdown');?></p>
<?=$this->form->submit('Ask', array('class'=>'btn'));?>
<?=$this->form->end();?>
Note how the form helper will automatically display errors in case there are any :)
Some useful links into the #li3 philosophy:
1 - http://www.slideshare.net/nateabele/lithium-the-framework-for-people-who-hate-frameworks
2 - Video of roughly the same presentation (w/ a good example on changing form templates)

How to Validation Zend Form opening tag : Zend Form

How to Validation Zend Form ? (opening tag)
Example :
Form :
class MyForm extends Zend_Form {
function init() {
$this->addElement('select','my_select',array(
'label'=>'My select :',
'required'=>true,
'multioptions'=>array(''=>'-select please-','1'=>'value1','2'=>'value2')
'validators'=>array(
array('NotEmpty', true, array('messages' => 'This field is required'))),
));
} }
Controller :
$form = new MyForm();
if ($this->_request->isPost()) {
$form_name=$this->getRequest()->getParams();
if($form->isValid($form_name)){
echo "==success==";
}
else{
echo "==no success==";
}
}
$this->view->form = $form;
View :
// Render the form opening tag
echo $this->form->renderForm(false);
echo '<table>';
echo '<tr>';
echo '<th>'
// Render the label
echo $this->form->my_select->renderLabel();
echo '</th>
echo '<td>';
// Render the select
echo $this->form->my_select->renderViewHelper();
echo $this->form->my_select->renderErrors();
echo '</td>';
echo '</tr>';
echo '</table>';
echo '</form>';
i want to show message validation at view
This code is complete in answer 18/02/2011
You can render errors on a specific element with:
echo $this->form->my_select->renderErrors();
If you want to render the errors for all the form in one place :
$form->addDecorator('FormErrors');
echo $form->renderFormErrors();
I'm not really sure what you mean here but here's my best guess...
If you want to render the set of validation errors for the form and its elements in one place, try adding the FormErrors decorator to the form. See Zend_Form_Decorator_FormErrors
As for validation, simply add validators to the elements as normal.
to have validation errors you first need to add validators to your form element ,
$formElement = new Zend_Form_Element_Text('username');
$formElement->addValidator(new Zend_Validate_Alnum());
to get validation error messages do
$arrayOfErrors = $this->view->form->getMessages();

Categories