Custom Yii Url Rules

January 10, 2012 9:31 PM

Recently I had the requirement to have a route that was powered by the database, the Yii docs cover this, but having the create and parse run at the same point was problematic.  The situation was that the route was just a controller and an action with search form parameters, of course the route parsed to createUrl() would be just "controller/action"; there was a normal "<controller>/<action>" rule as well.

If I wanted the createUrl() method to return the database powered slugs then the custom url rule would need to be above the generic rule.  The danger there is that if anyone entered a slug that matched an existing url this would prevent the normal page from displaying.  So I needed the createUrl() to be above the generic url but I needed the parseUrl() rule to be below it.  I had a couple of solutions, create two classes, or add an attribute that controlled behaviour, I opted for the attribute as it is a cleaner solution.

First, we create the class:

class DbUrlRule extends CBaseUrlRule
{
   public $connectionID = 'db';
   public $mode;

   public function createUrl( $manager, $route, $params, $ampersand )
   {
      if ( 'create' != $this->mode )
      {
         return false;
      }

      // Check the route and params and return the URL string if valid.
   }

   public function parseUrl( $manager, $request, $pathInfo, $rawPathInfo )
   {
      if ( 'parse' != $this->mode )
      {
         return false;
      }

      // Check the pathInfo and request to see if we match, if so set $_GET
      // variables and return route.
   }
}

Then, in our rules, we simply create two rules, same class but with different modes:

'urlManager' => array(
   ...
   'rules' => array(
      ...
      array( 'class' => 'DbUrlRule', 'mode' => 'create' ),
      '<controller>/<action>' => 'controller/action',
      array( 'class' => 'DbUrlRule', 'mode' => 'parse' ),
      ...
   )
)

And there you have it, one class that encapsulates the behaviour of the rule that can be used in multiple places in the rules.  One place to ensure that you get a nice URL if you createUrl() with the appropriate values and the parseUrl() in a place that ensures system integrity.

Comments

No comments yet, be the first to comment.