The Secret of CakePHP Advanced Routing – Even Better URLs

The power of CakePHP has a lot to do with conventions. The framework (like many others) harnesses its power by enforcing certain conventions and standards that users must follow. You name your database tables, file names, etc; a particular way and boom, models, views and controllers are automatically created and ready for use. This is the beauty of the MVC structure. Your URLs also follow thing structure: www.site.com/controller/action/params.

Straying From Convention

But sometimes, conventions suck. Sometimes you want greater control over things, but still don’t wanna do them from scratch. The strictness of the MVC structure dictates how your URLs will look. Consider this: CakePHP has a basic pages controller, which you can use when you don’t need a model or controller. You just enter the view and voilà , a page. But your pages have a URL of:

www.site.com/pages/page

Wouldn’t you rather:

www.site.com/page.htm

The Routes Configuration examples in the CakePHP manual are a bit simple. Here’s how to use a bit more advanced routing:

Router::connect('/(.*).htm', array('controller' => 'pages', 'action' => 'display'));

This says, consider everything that comes in with an HTM extension and send the URL as a parameter to the display action on the pages controller.

The idea was stolen from Lumad CMS. They use the following in Rewrite in .htaccess for their pages:

RewriteRule ^~(.*) content_pages/displayurl/$1 [L]
They use a prefix of ‘~’ instead of a suffix of ‘.htm’, but you get the picture. I’m sorry to disappoint you, I’m not as creative as you thought.

How I Use Advanced Routing

I maintain a makeshift CMS using CakePHP. In this project I have a basic model (contents) with a title and body fields, among others. I would use the pages controller, but I need end users to be able to end pages through the database.

Router::connect('/(.*).htm', array('controller' => 'contents', 'action' => 'view'));

Conventions are great as long as they don’t get in the way. The great thing about CakePHP is that they frequently provide ways to get what you need done easily.

Make your static content look like static pages with Advanced routing.

Source: Routes Configuration [CakePHP Manual]

Comments

  1. Thank you very much,Very Usefull!

  2. why would you want to add a .htm file extension? That totally goes against creating a RESTful style application. File extensions are about telling a browser or an OS what type of file they’re dealing with….why clutter up the url with technical data like that? Bad for UX, bad for SEO and totally 1999.

    • you might want to know how to do what you don’t wanna do.. ;)

    • Very good question Mr. Matt. Let me enlighten you.
      A couple things you may note:
      1. As you can see, this is used on the “pages” controller, which by definition, is used for static HTML pages. So, the terms “RESTful” and “application” don’t apply.

      2. About cluttering up the URL and UX. It is easy to argue that going from “www.site.com/pages/page” to “www.site.com/page.htm” will both unclutter the URL and enhance the UX

      3. I think you mean “content type” is about telling the browser what type of file they’re dealing with.

      4. Not everything from 1999 is horrible.

  3. need some more guidance on how to creating home page having all widgets of other models

    • Josenivaldo Benito Jr. says:

      @web forum

      In this case, your home page is not a static page. It contains dynamic data (from other models). In order to solve this I probably would create a specific controller for the home page that query data from other models (binding and calling specific methods of each model). These data would be passed to a view (index) which would be composed by elements (each one being a model widget). As you may guessed the view should call each element passing the corresponding model data variable as parameter.

      Due the elements, queries and data manipulation necessary to accomplish this task I think pages_controller should not be used (even being perfectly suitable for). Create a specific controller for this situation is a clear pretty way to do it.

      After all you just connect you controller index method to the url you want. For a home page example something like below might solve:

      Router::connect(‘/’, array(‘controller’ => ‘my_new_controller’, ‘action’ => ‘index’));

      And, for sure, remove the similar entry point “/” to pages_controller display action.

      Regards,
      Benito

  4. Atul Dravid says:

    Its not working for me… I am doing something wrong?
    I used the same Router::connect(‘/(.*).htm’, array(‘controller’ => ‘pages’, ‘action’ => ‘display’)); for my pages controller but whenever I try to open any page it says Missing Controller.