Search code examples
zend-frameworkzend-routezend-router

Zend adding parameter to URL before generating view


The title might be misleading but I'm trying to do something very simple but cant figure it out.

Lets say I have a Question controller and show action and question id is the primary key with which I look up question details - so the URL looks like this

http://www.example.com/question/show/question_id/101

This works fine - So when the view is generated - the URL appears as shown above.

Now in the show action, what I want to do is, append the question title (which i get from database) to the URL - so when the view is generated - the URL shows up as

http://www.example.com/question/show/question_id/101/how-to-make-muffins

Its like on Stack overflow - if you take any question page - say

http://stackoverflow.com/questions/5451200/

and hit enter The question title gets appended to the url as

http://stackoverflow.com/questions/5451200/make-seo-sensitive-url-avoid-id-zend-framework

Thanks a lot


Solution

  • You will have to add a custom route to your router, unless you can live with an url like:

    www.example.com/question/show/question_id/101/{paramName}/how-to-make-muffins
    

    You also, if you want to ensure that this parameter is always showing up, need to check if the parameter is set in the controller and issue a redirect if it is missing.

    So, in your bootstrap file:

    class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
    {
      public function _initRoutes ()
      {
        // Ensure that the FrontController has been bootstrapped:
        $this->bootstrap('FrontController');
        $fc = $this->getResource('FrontController');
        /* @var $router Zend_Controller_Router_Rewrite */
        $router = $fc->getRouter();
    
        $router->addRoutes( array ( 
          'question' => new Zend_Controller_Router_Route (
            /* :controller and :action are special parameters, and corresponds to
             * the controller and action that will be executed.
             * We also say that we should have two additional parameters:
             * :question_id and :title. Finally, we say that anything else in
             * the url should be mapped by the standard {name}/{value}
             */
            ':controller/:action/:question_id/:title/*',
            // This argument provides the default values for the route. We want
            // to allow empty titles, so we set the default value to an empty
            // string
            array (
               'controller' => 'question',
               'action' => 'show',
               'title' => ''
            ),
            // This arguments contains the contraints for the route parameters.
            // In this case, we say that question_id must consist of 1 or more
            // digits and nothing else.
            array (
               'question_id' => '\d+'
            )
          )
        ));
      }
    }
    

    Now that you have this route, you can use it in your views like so:

    <?php echo $this->url(
             array(
                'question_id' => $this->question['id'], 
                'title' => $this->question['title']
             ),
             'question'
          );
          // Will output something like: /question/show/123/my-question-title 
    ?>
    

    In your controller, you need to ensure that the title-parameter is set, or redirect to itself with the title set if not:

    public function showAction ()
    {
      $question = $this->getQuestion($this->_getParam('question_id'));
      if(!$this->_getParam('title', false)) {
         $this->_helper->Redirector
            ->setCode(301) // Tell the client that this resource is permanently 
                           // residing under the full URL
            ->gotoRouteAndExit(
               array(
                 'question_id' => $question['id'],
                 'title' => $question['title']
               )
            );
      }
      [... Rest of your code ...]
    }