7

Brief Summary

This question is asking for guidance on how to deal with Zend Form library that allows me to specify how to construct each form element (Controller side) and how to render each element (View side), essentially creating 2x amount of work, when compared to a non-Zend-Form approach where each form element is dealt with exactly once -- in the View only

How Zend Form does things

On my Controller side I can use Zend Form to build up each form element. Note: in the code I want to show that I can build Object Oriented HTML elements and populate their values and even attributes (including CSS attributes I want to render later) all inside the Controller code programmatically.

Exhibit A - Zend Form Controller Side

    //create checkbox
    $checkbox = new Element\Checkbox('construction');
    $checkbox->setLabel("Construction: ");
    $checkbox->setChecked(true);
    $checkbox->setAttribute('onclick', 'return false'); // disable checkbox

    // Set up
    $listPrice = new Element\Text('listprice');
    $listPrice->setLabel("List Price: ");
    $listPrice->setValue('123.00');
    $listPrice->setAttribute('disabled', 'disabled');
    $listPrice->setAttribute('style', 'color:black;text-align:right');
    $listPrice->setAttribute('size', 9);

    // Assemble Form
    $form = new Form('form');
    $form->add($checkbox);
    $form->add($listPrice);

    // return rendered HTML
    return $this->partial("form.phtml", array(
        'form' => $form
    ));

Then in my View

I want to show first that in View, ZF2 sometimes takes up the bulk of actual HTML form rendering and I don't have to do much sometimes. i.e. I could just use $this->form()->render($form) to render out entire form for me, but then I would not be able to place custom style on each element if I so desire. And also all the elements will be rendered in a single row, which is rarely what I want.

In my case in the next code block below I had to go deeper and semi-automate form rendering, to be able to add my own HTML elements such as <p></p> during the rendering process. i.e. I had to use things like openTagand closeTag and formRow methods.

Exhibit B - Zend Form View Side

/**
 * inside view template - with custom HTML 
 * custom HTML is one that contains form_row class
 * It will not render if I use $this->form()->form($form)
 * to render out complete form in one go.
 *
 * @var $this \Zend\View\Renderer\PhpRenderer
 * @var $form \Zend\Form\Form
 */
$form = $this->form;
?>
<style>
.form_row {
    margin-bottom: 14px;
    margin-top: 14px
}
</style>
<fieldset>
    <?php
    //renders <form ... >
    echo $this->form()->openTag($form);

    //loops through each form element, and passes it to "formrow" method
    //that renders out full element in HTML    
    foreach ($form as $element)
        $formContent .= '<p class="form_row">' . $this->formrow($element) . '</p>';

    echo $formContent;

    //renders </form>
    echo $this->form()->closeTag();
    ?>
</fieldset>

But, the deeper I go, the more code I have to write. If I was desiring to custom-style each element, I would have to manually refer to each element in my View

Rendering Individual Element with custom styling using Zend Form

<label>
    <span><?=$this->formLabel($form->get('listPrice'));?></span>
    <?=$this->formInput($form->get('listPrice'));=>
    <?=$this->formElementErrors($form->get('listPrice'));?>

    <div id="custom_form_div_between_elements">
        Custom div that would not be rendered inside this form, 
        if I left ZF2 on auto-pilot like in a previous example
    </div>

</label>

Imagine doing the above for each Form Element.

So essentially I write code, both programmatically defining form elements in Controller and then write code to render them out in the view. Double Work. Double Code.

Question

It Bothers me that I more often than not write code twice in a way (for both Controller and View) to deal with each form element.

I could instead do better by placing everything into my view script like i.e.

Exhibit C - Example not using Zend Form (rendering my own element)

<label>
    <span>List Price: </span>
    <input name="listprice" disabled="disabled" 
        style="color:black;text-align:right" size="9" 
        value="<?=$price?>" type="text">
</label>

Exhibit D - Full 'real code' [select] example when not using Zend Form

<select name="id" id="modelid" class="validate[required]">
    <option>blank</option>
<?
$sql = "SELECT distinct(model), id FROM product GROUP BY model";
$result = db_query($sql);

for ($i = 0; $i < db_num_rows($result); $i ++)
{
    $row = db_fetch_array($result);
    ?>
    <option value="<?=$row['id']?>"
        <?=$productid == $row['id'] ? ' selected="selected"' : ''?>>
            <?=$row['model']?>
    </option>
    <?
}
?>
</select>

Question Summary

ZF2 lets me use Zend Form code to create Form Elements in Controller, populate them with values, and then use various Zend facilities to render the elements in the View. Depending on how detailed you want to get (i.e. if you want custom styling for each element), you are doing quite a bit of work for each element, which feels like it is duplicated -- you have to deal with each element in your Controller and in your View. Granted, some work is easier, i.e. in a <select> or <input type="radio"> element you don't have to deal with hacking up PHP and HTML to make sure a select box displays with a particular value as selected. Zend takes care of that for you.

Now it's great if you just use native default Zend Form facilities to output whatever it gives you. You then do work only in Controller. But the moment you want custom styling, you do additional work in View, sometimes pretty much having code just as much code for each element of the form in the View as you have in Controller.

Bonus Questions

  • What problem does Zend Form solve by splitting Controller & View code? Am I using this correctly? (Is this 2x work justified?)

  • Will I do better do something like move all the Zend Form code Controller into and have the all the "2x code" live in the View?

1
  • I tried it both ways, I gotta say>> Controller-side set up lets me not worry about the presentation. I can define and declare elements as I see fit without worrying about the order much. Later, I can do the order in the view. Non-Zend-Form just piles everything into one heap. Zend Form separates Controller side as Form Basics and then lets the View deal more with more standardized rendering
    – Dennis
    Feb 27, 2016 at 0:13

2 Answers 2

1

The examples shown is correct, but Zend\Form is not exactly what you want to use in your controllers. I'm talking about Exhibit A, where it shows how much code to create, populate and style a form with two elements. It is tedious to create forms that way.

To avoid turning the controller into a form factory, you need to create a factory that will create the form that you need (e.g. AppFormFactory). So, your controller should look like this:

$product = Model::getRandomProduct();
$form = AppFormFactory::create('ProductForm');
$form->bind($product);

The Zend\Form related code will be inside the implementation of AppFormFactory or you can use Zend\Form\Factory to create the form by passing a configuration array instead of creating the form programmatically.

Another thing that I'd like to point out is when you have a Model and a configured Form, as you can see, you can do $form->bind($product) instead of setting values of every element inside a form. This can be helpful when working with form with many elements (e.g. Edit product form).

You can also use annotations to create a Form with all the wirings (validation, hydration, etc.), just check the last section of Zend\Form documentation. As final comment, the styling part (font size, colour) should really just be part of css.

0

Trying examples out I guess I am using it correctly. Namely I can see some benefit to using Zend Form in that it makes the view neater and more standardized and it was not as much work as I had originally thought.

The "bulk" of setting up a form element is actually shifted into the Controller. In View all you do is just render the label and element itself using Zend Form view helper method calls, which are the same for all elements (standardized). This also makes the view cleaner. So if someone who is a non-programmer is editing the view, they do not have to see or deal with the mess of "Exhibit D" in Question.

Compare below to "Exhibit D" in Question.

Controller (Zend Form)

    $result = $this->em->createQuery('SELECT m.name from Entity\Product m')
        ->getScalarResult();
    $options = array();
    foreach ($result as $key => $value)
        $options[$value['name']] = $value['name'];

    $productSelect = new Element\Select('product_name');
    $productSelect->setLabel('Product Name');
    $productSelect->setValueOptions($options);
    $productSelect->setValue('143AT');

View (Zend Form)

    <?=$this->formLabel($form->get('product_name'));?>
    <?=$this->formSelect($form->get('product_name'));?>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.