Skipping to Another Action

June 30, 2007 at 6:14 am (Symfony)

In some cases, the action execution ends by requesting a new action execution. For instance, an action handling a form submission in a POST request usually redirects to another action after updating the database. Another example is an action alias: the index action is often a way to display a list, and actually forwards to a list action.

The action class provides two methods to execute another action:

  • If the action forwards the call to another action:
    $this->forward('otherModule', 'index');
  • If the action results in a web redirection:
    $this->redirect('otherModule/index'); $this->redirect('http://www.google.com/');

The code located after a forward or a redirect in an action is never executed. You can consider that these calls are equivalent to a return statement. They throw an sfStopException to stop the execution of the action; this exception is later caught by symfony and simply ignored.

The choice between a redirect or a forward is sometimes tricky. To choose the best solution, keep in mind that a forward is internal to the application and transparent to the user. As far as the user is concerned, the displayed URL is the same as the one requested. In contrast, a redirect is a message to the user’s browser, involving a new request from it and a change in the final resulting URL.

If the action is called from a submitted form with method="post", you should always do a redirect. The main advantage is that if the user refreshes the resulting page, the form will not be submitted again; in addition, the back button works as expected by displaying the form and not an alert asking the user if he wants to resubmit a POST request.

There is a special kind of forward that is used very commonly. The forward404() method forwards to a “page not found” action. This method is often called when a parameter necessary to the action execution is not present in the request (thus detecting a wrongly typed URL). Listing 6-12 shows an example of a show action expecting an id parameter.

Listing 6-12 – Use of the forward404() Method

public function executeShow() {   $article = ArticlePeer::retrieveByPK($this->getRequestParameter('id'));   if (!$article)   {     $this->forward404();   } }

If you are looking for the error 404 action and template, you will find them in the $sf_symfony_ data_dir/modules/default/ directory. You can customize this page by adding a new default module to your application, overriding the one located in the framework, and by defining an error404 action and an error404Success template inside. Alternatively, you can set the error_404_module and error_404_ action constants in the settings.yml file to use an existing action.

Experience shows that, most of the time, an action makes a redirect or a forward after testing something, such as in Listing 6-12. That’s why the sfActions class has a few more methods, named forwardIf(), forwardUnless(), forward404If(), forward404Unless(), redirectIf(), and redirectUnless(). These methods simply take an additional parameter representing a condition that triggers the execution if tested true (for the xxxIf() methods) or false (for the xxxUnless() methods), as illustrated in Listing 6-13.

Listing 6-13 – Use of the forward404If() Method

// This action is equivalent to the one shown in Listing 6-12 public function executeShow() {   $article = ArticlePeer::retrieveByPK($this->getRequestParameter('id'));   $this->forward404If(!$article); }   // So is this one public function executeShow() {   $article = ArticlePeer::retrieveByPK($this->getRequestParameter('id'));   $this->forward404Unless($article); }

Using these methods will not only keep your code short, but it will also make it more readable.

When the action calls forward404() or its fellow methods, symfony throws an sfError404Exception that manages the 404 response. This means that if you need to display a 404 message from somewhere where you don’t want to access the controller, you can just throw a similar exception.

Post a Comment