views:

6404

answers:

13

I've read the manual many times, I've scoured the posts offered by Google on the subject, I have even bought a couple of books that deal with ZF. Now, why am I still confused?

I can, using Zend_Form, make a form that validates and functions fine. What I cannot do it make a form that looks exactly like I want it to look with the error messages that I want it to have. I want custom buttons, I want funky layouts, I want to insert text in the midst of the form, etc.

Does anyone have a simple way of achieving these sorts of things? Something that makes me feel like the framework is saving me time rather than costing? I could forego Zend Form... make my own form, have its action hit a page to validate and process the posted data and I could do it about as fast as I can type but I really want to "get" this and be able to use it as it was apparently intended.

Any advice? Any simple "how to's" for custom buttons, funky layouts and basic (or rather advanced as there are tons of basic tutorials that skip over the harder issues) "getting things done" with zend form?

+1  A: 

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!

tharkun
lol... sometimes jedi mind tricks are the only way to go.
gaoshan88
+1  A: 

Skipping out on the form-wide decorators (IE - printing individual elements of the form rather than just relying on the Form's standard View Helper to handle everything) is one way to get a bunch of control back.

Another option is to simply hand-code your form and only use ZF to handle validation and filtering.

Sean McSomething
How do you then get the validation messages back into your page if the input isn't valid?
Evan
Zend_Form has a bunch of accessor functions : $form->isValid(), $form->getErrors(), $form->getValue() and the like.
Sean McSomething
You can also use flashMessenger to handle error messages. I used it in the past.
gaoshan88
+2  A: 

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.

+1  A: 

I wrote some sub-classes to Zend_Form and the decorators to make it layout the form in a <table>. It even had some special tricks to do things like make multiple submit buttons show on the same row.

Took a full day of hacking around to get it working. It was written against Zend 1.5.1 so don't know if it will work with the current version, but if you are interested I could probably upload the source somewhere.

This seems to be a very common complaint with Zend Forms.

(I know I'll get poo-poo'd by the CSS purists over using tables to layout forms, and while I agree that CSS is better for most things, I have yet to see good form layout using CSS that doesn't look like a butt-ugly kludge. With tables the forms 'just work' pretty much on every browser I need them to.)

EDIT: Okay, speaking of butt-ugly kludges, I've put my code for producing tabular zend forms in github. Go here to see it. (Because gaoshan88 asked for it.)

Evan
I'm one of the CSS purists (unless I'm outputing tabular data in which case I wil use tables) but aside from that I would love to see an example of specifically what you did.
gaoshan88
http://www.themaninblue.com/experiment/InForm/ and http://www.themaninblue.com/writing/perspective/2004/03/24/Excellent form designs done using standard compliant XHTML/HTML and using standard CSS to style the various elements. And it looks awesome.
X-Istence
+1  A: 

Unfortunately, the more complex issues are skipped over because without a real specific purpose or goal in mind, it's really hard to write an example or how-to. I spent some time helping out another developer here on SO who wanted to modify the way hidden elements were displayed, but his case was very specific so it was easier to drill down into specifics.

The majority of the more complex tasks really come down to extending the default helper for a specific field type. For example, I had a project where I wanted to apply the class "error" to all fields that did not pass validation after a form had been submitted instead of writing out the validation error text:

<label for="field">Label:</label>
<input type="text" name="field" id="field" class="error">

It was a fairly complex process because the actual form element is not available to the view helper by default, so the helper cannot check if the element has a validation error. So I went about the following process:

  1. I had to create a customer view helper for each field type that I wanted to apply the "error" class to. In it, I overrode the formXXX() method, and add a check to see if the element had an error. Additionally, I added a setElement() method that the decorator could call to set an instance of the element so my helper could check for errors.
  2. Next I had to override the default Zend_Form_Decorator_ViewHelper. In it, I accessed the view and instantiated the helper for the form element type and checked for the existence of the setElement() method I created in my view helper, setting it if it existed. By doing this, I could extend some form element types and not others without busting the entire script.
  3. In my init() function for each form, I had to add a new element prefix path (addElementPrefixPath('My_Form_Decorator'), 'path/to/decorator')) which pointed to my new form decorator.
  4. Finally, I had to add the helper path to my application so that Zend Framework could find the helpers I had created in the first bullet point: addHelperPath('/path/to/helpers', 'My_View_Helper');

You can see why writing complex tutorials really requires real world problems. The great part about setting up these kinds of helpers, or complex decorator schemes is that, all be it annoying up front, it allows you to very easily create many forms that adhere to the same design scheme and modify their output uniformly very quickly if changes need to be made. But if on the other hand you feel like you're spending a great deal of time figuring out how to do what should be a simple task for the benefit of one form, I would say skip it!

If you would like help for something more specific, however, I would be more than happy to help. Just pose another question (or update this one) and I'll do my best to help out.

chuckg
A: 

I'm not sure if Zend already has that feature but, a quick solution would be to extend the class , make it accept a html template.

For example:

<?php
$form = new zend_form_whatever($field_list + $validators + $template);
echo $form;
?>

template:

<form id="my_custom_form">
    <label>{label.email}</label>
    {input.email}
    <span class="red">{error.email}</span>

    <div>
        {label.password}
        {error.password}
        {input.password}
    </div>

    <div class="purple">{input.submit}<div>
</form>
Mario
Zend_Form is the most flexible of any form class I have ever seen, and it is very easy to use as well. It just requires one wrapping ones head around the whole concept of decorators and how they apply to the various parts of the form.
X-Istence
+1  A: 

whycantitbemorethan25c mentioned them above, but ViewScripts give you extremely fine-grained control for rendering forms. Zend_Form is meant to be fast and so it assumes many defaults like standard decorators and orders the element the way they were added to the form object. With the ViewScript you can skip much of that that and place all of your elements however you would like within normal HTML.

Don't skip over the concept of Decorators entirely though. They style the individual elements even if they are used in a ViewScript later. For example, you can use them for error messages as others have suggested.

If you have very complicated form that has multiple data points with similar actions (think of a list of users with active/inactive buttons and a delete button for each) you should consider Zend_Form_SubForm. The subforms can utilize the ViewScripts just like normal forms and if you cascade a form with a ViewScript with subforms with their own ViewScripts you end up with nicely contained logic and presentation that is much more powerful than just a straight form.

Barrett Conrad
A: 

Sean McSomething's first advice is the way to go for me. I've always thought that doing <?php echo $this->form ?> to render a form is too magical. I'll take it a step further though and render individual decorators rather than individual elements via $element->renderDecorator() magic methods. This way, you won't have to worry about the order in which you defined your decorators. You just need them to be there, and you won't have to add those pesky, unintuitive HtmlTag decorators. I made a blog post about this.

monzee
You can turn off the HtmlTag decorators.
X-Istence
+12  A: 

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.

can you update your example and add the following code1) when username didn't fill then add class "error" to input element and show some error message above2) special validation for username, for example unique check plus symbol check
se_pavel
+5  A: 

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
mercator
+1  A: 
chiborg
A: 

ANSWER HERE. HOPE it will help you. I went through the enormal amount of information till I found it.

<table>
    <tr>
        <td>Page name: *</td>
        <td><?php echo $this->pageForm->header_title;?></td>
    </tr>

    <tr>
        <td>H1 tag: *</td>
        <td><?php echo $this->pageForm->h1_tag;?></td>
    </tr>

    <tr>
        <td>Page URL: *</td>
        <td><?php echo $this->pageForm->url;?></td>
    </tr>

    <tr>
        <td>Meta Description: </td>
        <td><?php echo $this->pageForm->meta_description;?></td>
    </tr>

    <tr>
        <td>Meta Keywords: </td>
        <td><?php echo $this->pageForm->meta_keywords;?></td>
    </tr>

    <tr>
        <td>Short Description: *</td>
        <td><?php echo $this->pageForm->short_description;?></td>
    </tr>

    <tr>
        <td colspan="2"><a href="<?php echo $this->websiteUrl;?>backend_template/list?placeValuesBeforeTB_=savedValues&TB_iframe=true&height=200&width=300&modal=true"
                           title="add a caption to title attribute / or leave blank" class="thickbox">Open iFrame Modal</a></td>
         <td>
            <a href="<?php echo $this->websiteUrl;?>backend_template/list?placeValuesBeforeTB_=savedValues&TB_iframe=true&height=200&width=300&modal=true" onclick="javascript:getDataFromAddPage()" title="Select Template For Page" class="thickbox" > TEST FORM  </a>
         </td>
    </tr>

    <tr>
        <td>Featured: </td>
        <td><?php echo $this->pageForm->featured;?></td>
    </tr>

    <tr>
        <td>Mark as 404: </td>
        <td><?php echo $this->pageForm->is_404page;?></td>
    </tr>

    <tr>
        <td>Show in Navigation Menu: </td>
        <td><?php echo $this->pageForm->in_navmain;?></td>
    </tr>

    <tr>
        <td>Show in Static Menu:</td>
        <td><?php echo $this->pageForm->in_navstatic;?></td>
    </tr>

    <tr>
        <td><?php echo $this->pageForm->submit;?></td>
        <td><?php echo $this->pageForm->button_close;?></td>
    </tr>

</table>
A: 

You probably have solved this by now, but I've been doing some work and needed a similar solution.

form->getSubform('subform'); 
foreach ($subform as $key => $value) {
//some markup and custom code here
    print $value;
//some markup and custom code here

}
?>

within the foreach loop, you can add table markup. If you've named your keys for your table rows appropriately, they should match up with the form keys. You could even use a loop that grabs the appropriate subform by key, or even an element by a key. you could skip the foreach loop if you know the keys, and simply say print $subform['somekey']; assuming you set the main form by saying $form->setIsArray(true); (not sure if that last part is strictly necessary, but for complicated forms, it should be set like that anyway.

I removed the default decorators so I could have complete control of printing within each element. Zend_Form ought to have a built-in method for grabbing individual elements a little more easily.. but I think this works pretty well.

Hope that's helpful to someone!

msumme