Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Zend Form: How do I make it bend to my will?

Barrett Conrad's advice is what I would have suggested. Also, keep in mind that you don't need to use a form object to render your form.

One thing you could do is create a form in your view script that has elements with the same name as a form class.

Your HTML form:

<form action="/login/" method="post">
<fieldset>
    <label for="username">Username:</label>
    <input type="text" size="10" name="username" />
    <label for="password">Password:</label>
    <input type="password" size="10" name="password" />
    <input type="submit" />
</fieldset>
</form>

Your class:

class LoginForm extends Zend_Form
{
    public function init()
    {
        $username = $this->createElement('text','username');
        $username->setRequired(true);
        $this->addElement($username);

        $password = $this->createElement('password','password');
        $password->setRequired(true);
        $this->addElement($password);        
    }
}

Your form class reflects your HTML form, each element in your class has its own validators and requirements. Back in your action you can create an instance of your form class and validate your post/get vars against that form:

$form = new LoginForm();
if ($this->_request->isPost()) {
    if ($form->isValid($this->_request->getParams())) {
        // do whatever you need to do
    } else {
        $this->view->errors = $form->getMessages();
    }
}

You can display the the error messages at the top of your form in one group, using this method.

This is a basic example, but it allows you to have total control over the presentation of your form without spending the time to learn to use decorators. Much of the strength of Zend_Form is in its validation and filtering properties, in my opinion. This gives you that strength. The main draw back to a solution like this is that your view script HTML form can become out-of-sync with your form class.


Render each element individually in your view - for example

<!-- view script here -->
<form method="POST">
Name: <?php echo $this->myForm->getElement('name')->render(); ?>
some other text between the fields
Birthdate: <?php echo $this->myForm->getElement('birthdate')->render(); ?>
<input type="submit" />
</form>

This maintains the ability to use the Zend_Form view helpers (i.e. to display error messages and maintain the values of the form fields when validation fails) but gives you full customization ability.

If you want to go further, then turn off the default decorators of the individual form elements and then either attach your own to further customize exactly what tags are used (i.e. for error messages and labels) or don't use decorators at all (other than to render the form element itself) and then write all the surrounding HTML manually. Complete customization ability without losing the benefits of Zend_Form, both at the form level and at the view level.


Matthew Weier O'Phinney has started a series of blog posts about Zend_Form decorators:

  1. The simplest Zend_Form decorator
  2. From the inside out: How to layer decorators
  3. Rendering Zend_Form decorators individually
  4. Creating composite elements

Currently we've got the new and shiny Zend\Form which is even more complex than the old component but also much more controllable, encapsulated and powerfull. So, what I said below doesn't apply. The new component is IMHO a huge improvement because it...

  • ...gives you full control over how you want to render your form, you need to write a bit more view code but it's worth it
  • ...separates data, logics and view to the maximally possible extent
  • ...makes use of the HTML5 form elements
  • ...gives you many options how you want to put your forms together, e.g. hydration, annotations, etc.

Old answer regarding Zend_Form

I can not really help probably because I have exactly the same problem. I think the Zend_Form decorators are powerful but by far the least programmer friendly and non-intuitive piece of ZF I've seen so far and I've used a major part of the ZF in various projects.

That said I can only give a few hints from my experience:

  • filters are easy to use without using form
  • most if not all of the things you want to achieve are done with the help of decorators
  • I started with small forms and added stuff piece by piece but I don't get some of the stuff I'm doing in some of my forms because the result is based on trial and error (mainly with the decorators)
  • I've got information from the zend mailinglist which I couldn't have found anywhere on the web

From the related questions to this on the right hand side it is obvious that there is a lack of comprehensive documentation for Zend_Form especially given it's non-intuitive nature. I would really like to see the ZF guys do something about this as much as I like Zend Framework.

So this answer is probably just to let you know that you're not the only one having the this problem.


or alternatively you could use jedi mind tricks of course!


To add to what was said:

Dont be afraid of the decorators, you'll be using them lots if you decide to stick with Zend_Form. It's fairly straightforward once you 'get it', unfortunately the docs are weak and playing with it is almost the only way to get there.

The ViewScript and ViewHelper decorators give you lots of power.

Don't be afraid to dig through the source for the different decorators that exist and see how they're doing things (I gained a fair amount of insight comparing the original decorators with the dojo ones).

I think what Sean was suggesting is that you don't need to call form->render, you can use something like this in your viewscript.

 <someHtmlThingy name="blah" value="<?php echo $this->formInstance->getElement('whatever')->getValue(); ?>" />

I worked on one project (pre Zend_Form) where we built sets of validators and used standard viewscripts all the way through. It was a little more work (plumbing for error messages and the like), but not excessive compared to creating elements with Zend_Form.


If you just want to add arbitrary markup before or after your form elements without using the ViewScript decorator, you could use my AnyMarkup decorator: http://www.zfsnippets.com/snippets/view/id/62

For example, here is how you would prepend an input field with an image inside a wrapper tag (needs include paths for autoloading to be set correctly):

$form->addElement('text', 'my_field', array(
  'label' => 'Enter Info:',
  'decorators' => array(
    'ViewHelper',
    array('AnyMarkup', array(
      'markup' => '<span class="imgwrapper"&gt'.
        '<img src="info.png" alt="info icon"/></span>'),
      'placement' => 'prepend'
    ),
    'HtmlTag',
    'Label'
  )
);