views:

74

answers:

4

This might sound like an odd scenario, but I've got two forms on one page. One is just posting back to itself. I made the second post to another action to keep the code cleaner. Maybe not the right choice...

The problem I'm having now is that if that second form doesn't validate, I redirect back to the page with the form but I don't know how to keep my form fields filled in with the original information the user entered. Is there a way to do that and keep posting to two separate actions, or do I need to just bite the bullet and have both forms post back to the same action and deal with the messy logic?

A: 

How do you redirect? I don't see the problem if you just display the form page again. You can prefill you forms using Zend_Form::populate().

Tim
Seems like I didn't read your questions properly. I would say the cleanest way is to post to the same action. Everything else would complicate your controller code.
Tim
I'm not redirecting. I want to display the same page again. I think I will have to just pre-populate the form (as you hint at) that isn't getting submitted and then let Zend Form do its thing to keep the changed form fields on the form that did get submitted.
Jeremy Hicks
+1  A: 

I would submit both forms to the same action. There really shouldn't be anything too messy about it. In each form include a hidden field to signify which form is being submitted.

Application_Form_Login:

 /* other form elements */
 $this->addElement('hidden', 'login', array(
      'value' => 1
 ));

Application_Form_Register:

 /* other form elements */
 $this->addElement('hidden', 'register', array(
      'value' => 1
 ));

Controller:

$loginForm = new Application_Form_Login();
$registerForm = new Application_Form_Register();

if($this->_request->isPost()) {
     if($this->_request->getPost('login')) {
         if($loginForm->isValid($this->_request->getPost())) {
             // validated, redirect
             $this->_helper->redirector('profile', 'user');
         }
     }
     if($this->_request->getPost('register')) {
         if($registerForm->isValid($this->_request->getPost())) {
             // validated, proceed as needed
         }
     }
}

$this->view->loginForm = $loginForm;
$this->view->registerForm = $registerForm;

View:

echo $this->loginForm;

echo $this->registerForm;

With this type of a setup, if either of your forms fail validation, isValid() will preserve any data that has been entered and you still redirect on a successful validation of one or both of the forms.

Lee
The assumption you're making, and its my fault because I wasn't clear, is that these forms don't have data in them to begin with. Using an example of login/register forms makes sense in your scenario. However, in my situation, these are both forms that are already pre-populated with data. So, instead of redirecting, they will always just display the original page again after processing. It doesn't complicate things too much more, but it is a difference.
Jeremy Hicks
Ah, that clarifies it a bit. If the two forms are being displayed on the same page, then it just seems most logical to keep the actions directed back to the same controller. I think I've ran into this same bind before, and juggling the data through another controller and back to the old one seemed like more of a hassle to me.
Lee
+1  A: 

Personally, I think that each form should post to its own controller, as you have. This keeps the code for processing that form in a single place. The issue here is that you want to return to the original page on failed validation. But why? Why not simply redisplay the form in the target controller, just like you would if there were a single form on the page?

For example, consider a login form that appears on every page of a sie (perhaps because it in the site template/layout). It posts to something like AuthController::loginAction(). If the login fails, then you don't typically send him back to the page from which he came. You leave him at the login page, with the form as pre-filled from the $_POST as you want it to be (probably a username, but not his password).

See this answer for a similar discussion.

Update: Had another thought in this. If you really want to handle the processing in two different controllers in order to keep him on the page from which he posted the form, at least extract that form processing out into an action helper. This way, you could at least keep that form-processing DRY.

Update: Rob Allen has just written a great blog post "A form in your layout" in which he describes a method that uses an action-helper with a preDispatch() method that instantiates and processes the form. Very nice.

David Weinraub
See my comment for the post above of why I re-display the original page again.
Jeremy Hicks
A: 

Well, I would just keep both forms submitting on the same page.

I don't see why your code should get any less readable. Learn how to use action helpers and your controllers will suddenly look extremely simple and readable:

public function indexAction() 
{
    $request = $this->getRequest();

    // send forms to view, so we can print them
    // but also so we can access them in action helpers
    $this->view->form = $this->_getForm('Form1', '/');
    $this->view->form2 = $this->_getForm('Form2', '/');

    if ($request->isPost())
    {
        // process the first form
        if (isset($_POST['form_submit_button']) && $this->view->form->isValid($_POST))
        {
            $this->_helper->form($this->view->form->getValues());
        }
        // process the second form
        else if (isset($_POST['form2_submit_button']) && $this->view->form2->isValid($_POST))
        {
            $this->_helper->form2($this->view->form2->getValues());
        }
}

Each form's processing would have its own action helper.

Richard Knop
Isn't one of the main points of creating a customer action helper to allow code reuse - so you have something you can use in many controllers? In this situation I can see how it would declutter the code, but I could really do that by just creating a helper function in my controller. Maybe I'm not understanding this correctly.
Jeremy Hicks
Well, yes. But it's still better to have simple controllers and move some application logic to action helpers (plus make sure to have all validation outside of controllers too, extend Zend_Form, you can also write custom validators if needed). I often use action controllers like this because in some applications I have taken part in programming there were complicated tasks in some controller actions (we had many actions which had 300+ lines of code even after we delegated lots of logic to third party libraries or our own classes) and we just had to make them more readable...
Richard Knop
... for the sake of maintainability. Plus it is not that bad in case of form handling because nothing says a form will appear in your application only once. There might be forms which will be used in more controllers or even site-wide forms which will be used across whole modules (like search form, login form) so it's not that bad of a practice.
Richard Knop