Yii 1.1: urlrouter

UrlRule class that allows easier working with slugs and translations (WiP)
7 followers

A CBaseUrlRule derived class that helps you to work with urls that contains slugs and so on.

The format of slugged urls is in general: /controller/folder-title-slug/contentId-content-title-slug[/customAction]

Note that you can modify the format per controller (perhaps you don't want folders?)

Some examples of supported urls (routing shown assumes default configuration and a map entry for 'forum'):

  • /forum/18/some-forum-name/index -> routes to forum/index with $_GET['id'] = 18
  • /forum/25/some-forum-name/some-topic-name -> routes to forum/routeRequest with $_GET['id'] = 25
  • /forum/25/some-forum-name/some-topic-name/post -> routes to forum/post with $_GET['id'] = 25

If you use the "alias" configuration it is possible to specify aliased controller names. Can be handy if you want to use translations for your controllers in an easy way.

For example: 'forum' => array('board') will allow "board" instead of "forum" in all previous examples as well.

The default configuration assumes the following:

  • /controller/id/folder-slug/index -> The "id" is referring to the "folder" (a forum in the example)
  • /controller/id/folder-slug/content-slug -> The "id" refers to the content (a topic in the example)
  • /controller/id/folder-slug/post -> Custom action for the folder
  • /controller/id/folder-slug/content-slug/post -> Custom action for the content

If you remove the "CONTENT_ID" from the urlFormat, the component will add the ID to the content slug. For example: /controller/folder-slug/id-content-slug

Requirements

Since this class uses the Custom URL rule functionality it requires Yii 1.1.8 or later.

Usage

Add it as an URL rule in your urlManager config on the appropriate place (the order in which rules are defined is important as the first matching one is used):

array
(
   'class' => 'application.components.UrlRouter',
   ... rest of the configuration
)

I'm hoping most of the configuration is self explanatory (there are a lot of comments in the file). A few pointers though:

  • There is a main configuration section that contains some global entries, they count for all the mapped controllers
  • The "map" variable is used to define the controllers that the UrlRouter can handle.
  • 'defaultConfig' is the global entry with which every 'map' item is merged. If you wish to just support a controller but the default configuration suffices, it is enough to add an entry with 'controller' => array()

Creating Urls

This rule also implements functionality for Yii's createUrl(). It will create urls for you with slugs, based on the specified parameters. Parameters supported are: - f: [optional] Either a model or a string to be used for the folder slug - c: Either a model or a string to be used for the content slug - id: [optional] The ID to use. It will be obtained from the content-model if specified - action: [optional] name of a custom action

Configuration allows you to change the parameter names for folder and content.

An example, assuming a "forum" object with a title "A Cool Forum" and id 15: Yii::app()->urlManager->createUrl('forum', array('c' => $oForum));

The returned result will be: /forum/15/a-cool-forum The router will ask the forum object for the title and the id property and assemble the url with that.

Imagine a "topic" object in this forum with title "Awesome topic" and id 12: Yii::app()->urlManager->createUrl('forum', array('f' => $oForum, 'c' => $oTopic));

Result will be: /forum/12/a-cool-forum/awesome-topic

Note: Imagine you added the "board" alias talked about in the beginning. If the user entered the site using that, it will be used instead of the forum for these Urls as well. Since you have the code you can remove this behavior but for me the consistency is important.

Total 7 comments

#8207 report it
saegeek at 2012/05/17 02:43pm
ok

finally i used the default url manager and it correctly suited my needs. I just understood how to use it. It's not like simple regex syntax as I thought

#8148 report it
Blizz at 2012/05/13 02:10am
Not wrong...

The examples I gave are correct, because its not common practice to actually directly call the createUrl in the UrlManager. You have to use the one from either the controller or the request. Those will take care of all the necessary stuff.

As for your problem, you are probably getting the url back from the default url manager as my class will remove those names if configured correctly.

Yii's URL system is created so that multiple rules can be active at any given time. This url router only works for the controllers that you configure it for. If it cannot find the controller specified in the route in it configuration it will declare a no-match and let Yii handle the rest. What you need at the very least is:

'urlManager' => array(
   'rules' => array(
      array
      (
         'class' => 'application.components.UrlRouter',
         'map' => array('product' => array()), // Activate for product controller, default configuration 
      )
   ),
),
#8147 report it
saegeek at 2012/05/13 01:11am
wrong

The examples you gived are wrong. I checked the class and i found the "route" as 2nd parameter:

public function createUrl($oManager, $sRoute, $aParams, $sAmpersand)
    {
         ...

I tried to create an url using (using your default class config) :

echo Yii::app()->urlManager->createUrl('products/details',array('id'=>$data->id,'c'=>$data->title));

the result was: localhost/products/details/id/54/c/alcatel-one-touch-585d

I expected the class will autoremove /id/ and /c/

#8134 report it
saegeek at 2012/05/12 05:13pm
oops

oops, i had to add it as an url rule :

'urlManager' => array(
   'rules' => array(
      array
      (
         'class' => 'application.components.UrlRouter',
      )
   ),
),
#8132 report it
saegeek at 2012/05/12 11:12am
http://www.yiiframework.com/extension/urlrouter

Finally it recognized by Yii when modifying the class to look like this:

Yii::import('system.web.CUrlManager',true);
 
class UrlRouter extends CBaseUrlRule
{
        public $urlFormat,$rules,$showScriptName;
        ...

But i can't show my index page, i get:

PHP warning
Missing argument 2 for UrlRouter::parseUrl(), called in /var/www/framework/web/CWebApplication.php on line 134 and defined
/var/www/protected/components/UrlRouter.php(294)
#8131 report it
saegeek at 2012/05/12 05:40am
error

Hi, i moved the extension to /protected/components/ and i added this to my config so it looks like:

'urlManager' => array(
            'class' => 'application.components.UrlRouter',
            'urlFormat' => 'path',
            'showScriptName' => false,
            'rules' => array(
            ...

But i get a Yii exception : include(CBaseUrlRule.php): failed to open stream: No such file or directory /var/www/framework/YiiBase.php(418)

Stack Trace:

/var/www/protected/components/UrlRouter.php(35): spl_autoload_call("CBaseUrlRule")
 
class UrlRouter extends CBaseUrlRule
{
#6692 report it
Blizz at 2012/01/29 06:00am
Update: Separate content ID, pre-slugged titles and arguments

I just updated the extension. The URL Parts can now also contain an CONTENT_ID in which case the ID will not be rendered as part of the slug. The parsing also supports this format.

The default settings changed from /controller/folderSlug/id-contentSlug to /controller/id/folderSlug/contentSlug

This behavior can be reversed by removing the CONTENT_ID variable from the default configuration.

A new variable was also added (can be set per controller): preSlugged (default FALSE). If this is set to TRUE, the code wont try to re-slug the titles anymore, making it possible to use your own slug class.

Last but not least there is now the possibility to have all the other specified arguments being used as url parts (they can also be read back). Use the "collectParameters" setting to enable this. Things like this are now possible: /forum/15/forumName/topicName/page/2

Leave a comment

Please to leave your comment.

Create extension