views:

466

answers:

3

When using Zend_Form I find myself creating a lot of controller methods that look like this:

function editPersonAction()
{
   $model = $this->getPersonModel();
   $form = $this->getPersonEditForm();
   if ($this->getRequest()->isPost() {
       $data = $this->getRequest()->getPost();
       //$form->populate($data); [removed in edit]

       if ($form->isValid($data)) {
           $data = $form->getValues();
           $model->setFromArray($data);
           // code to save model then decide which page to redirect to
       }
   } else {
       $form->populate($model->toArray());
   }
   $this->view->form = $form;
}

Most of that code is always the same, and I'm sure there are better ways to do this. What other patterns do people use with Zend_Form to cut down on the amount of boilerplate code used?

A: 

Is $form->populate() really necessary? IIRC non-valid forms will get populated automagically.

Karsten
thanks, I've removed the first $form->populate(). The second one is still necessary to initially populate the form from the database.
Paul Stone
A: 

To be honest, I have similar looking actions in my controllers too. One thing that I do to keep the weight down in the controller and by way of convention, is to do the validation checking in the model. I also call the form object from the model to facilitate this (you might already be doing this via your getPersonEditForm method in your controller. So if I had written your action, it would look like this:

function editPersonAction()
{
   $model = $this->getPersonModel();
   $form  = $this->getPersonEditForm();

   if($this->getRequest()->isPost()) 
   {
       if($model->setFromArray($this->getRequest()->getPost()))
       {
           // code to decide which page to redirect to
       }
   }
   else
   {
       $form->populate($model->toArray());
   }

   $this->view->form = $form;
}

So then in the model method setFromArray I'd have:

public function setFromArray(array $data)
{
    $form = $this->getRegistrationForm();

    if($form->isValid($data))
    {
        // code to save model state

        return true;
    }
    else
    {
        return false;
    }
}

Admittedly, it's not considerably more concise than your existing approach and I, like yourself, often feel this could be better abstracted.

Kieran Hall
i would name the method in the models validate or something similar since setFromArray does not seem a proper definition at least from my point of view
solomongaby
I agree that setFromArray doesn't sound like a good method name, however, validate worse as it's not describing what is happening to the data (only that it must be first validated). The majority of my model methods begin with either 'get', 'add', 'edit' or 'delete', so to give a clear indication on what is to be done with the data.
Kieran Hall
+4  A: 

I like to keep as much as possible in the models

function editPersonAction()
{
   $model = $this->getPersonModel();

   if ($this->getRequest()->isPost() {
       $data = $this->getRequest()->getPost();

       if ($model->validateForm($data)) {
           // code to save model then decide which page to redirect to
       } else {
          // error management
       } 
   } 

   $this->view->form = $model->getForm();
}

So then in the model I'd have:

public function validateForm(array $data)
{    
    $form = $this->getForm();

    if($form->isValid($data))
    {
        // code to save model state

        return true;
    } else {
        return false;
    }
}

public function getForm($instance = 'default') {
   if (!isset($this->_forms[$instance])) {
       $this->_forms[$instance] = new Your_Form_Class();           
       $this->_forms[$instance]->populate($this->toArray());
   }

   return $this->_forms[$instance];
}

Plus you can add this methods to an abstract model that all your application models would extend, and then only overwrite them when you need to do something special.

solomongaby
Your use of storing form objects as an array is insightful. This is something I could do with in my models, as I currently just have getters for specific forms. +1
Kieran Hall