Skip to Content

Configuring Symfony Forms with Request/Object Variables

In this article we provide a method for passing request/object variables into a form in order to pre-configure it based on that input. This goes beyond default values and is intended for linked form fields which should display different things based on the values selected by users.

Problem, you have a Symfony 1.4 form with linked form fields which display different options based on the value of a prior field. An example probably better illustrates the problem, for instance, we have a job site where a job form has a category and subcategory fields. The subcategories displayed only show the options for the related category. So, this article hopes to provide one method for solving this problem.

In this particular example you would also use AJAX to control the dynamic display of job subcategories but the point of this article is just to outline a technique for passing variables into the form, rather than to discuss AJAX in this instance.

So, first of all, this solution is only important for when a new form is submitted or when an existing object is submitted and there is some sort of error with the other form input. In these cases we want to restrict the options shown to that selected. To do this, we set an object instance to the values from the request in the actions class, like so:

class jobActions extends sfActions {
  public function executeCreate(sfWebRequest $request)
  {
      $this->forward404Unless($request->isMethod(sfRequest::POST));
 
      // get the location params to configure the form based on request vars
      $job_params = $request->getParameter('job');

      // preconfigure a job object with the request vars
      $job = new Job();
      $job->setJobCategoryId($job_params['job_category_id']);
      $this->form = new JobForm($job);

      $this->processForm($request, $this->form);
  }
  // other action methods ...
}  

In this snippet, we have created a job object using variables from the request parameter holder for the job form. Next, we need to take account of the object values in the form and use these to configure the form, like so:

class JobForm extends BaseJobForm
{
  public function configure()
  {
    // our job category field
    $this->widgetSchema['job_category_id'] = new sfWidgetFormDoctrineChoice(
      array('model' => $this->getRelatedModelName('JobCategory'), 
      'add_empty' => true)
    );
    
    // setting the options of our sub category field using the passed 
    // object's category id
    if ($job_category_id = $this->getObject()->getJobCategoryId())
    {
        // use a query from the job subcategory table to filter options by 
        // the object's category_id
        $query = Doctrine_Core::getTable('JobSubCategory')
          ->getSubCatsByCategoryIdQuery($job_category_id);  
        $this->widgetSchema['job_sub_category_id'] = new 
           sfWidgetFormDoctrineChoice(
             array('model' => $this->getRelatedModelName('JobSubCategory'), 
             'add_empty' => 'Choose a job subcategory', 'query'=>$query)
           );
    }
    else 
    {
        // if we don't have a job category then show nothing for job 
        // subcategory
        $this->widgetSchema['job_sub_category_id'] = 
          new sfWidgetFormSelect(array('choices'=>array(
            ''=>'Choose a job subcategory'))
          );
    }
  }
  // validators etc.
}

This snippet shows how we use the passed object's category_id value to set the options for the subcategory field. The last thing we need to do is also set the update method to also take into account variables passed from the request, like so:

class jobActions extends sfActions {
  public function executeUpdate(sfWebRequest $request)
  {
    $this->forward404Unless($request->isMethod(sfRequest::POST) || 
      $request->isMethod(sfRequest::PUT));
    $this->forward404Unless($job = Doctrine::getTable('Job')
      ->find(array($request->getParameter('id'))), 
      sprintf('Object job does not exist (%s).', $request->getParameter('id'))
    );
    
    // here we need to preconfigure the form with request vars, otherwise
    // the form will try to configure itself based on the original job values
    $job_params = $request->getParameter('job');
    $job->setJobCategoryId($job_params['job_category_id']);
    
    $this->form = new JobForm($job);

    $this->processForm($request, $this->form);
  }
}

And that's it, our method for passing variables into the form to set it up in different ways based on request values. We would appreciate any feedback about this method so feel free to use the comments below.

Comments

processForm

$this->processForm($request, $this->form) is just the standard Symfony method for processing forms in generated actions. All the work is done by setting the params of the job object and using that to set the form.

$this->processForm(

I belive you need to show the code for $this->processForm()

Good example. Thank you

Good example. Thank you