Pretty URL's SES Support
ColdBox now supports SES support right out of the box thanks to Adam Fortuna's Coldcourse project. ColdBox SES support is based on coldcourse and its rails style routing but taken to an interceptor form. You will now see an ses interceptor in the core ColdBox interceptors. So now you instead of going to urls like:
http://localhost/index.cfm?event=home.about
You can have the same URL available at
http://localhost/home/about
Requirements
There are no requirements for using the ses interceptor if you will be using the index.cfm file as a routing mechanism:
http://localhost/index.cfm/home/about
However, if you would like to see minimal url's (those without index.cfm in the URL) like:
http://localhost/home/about
Then you must be able to run either .htaccess files, which is enabled with apache, or be running IIS and be able to install an ISAPI filter for URL rewriting. If you have any of these rewrite engines installed then you can use the following rules:
.htaccess
RewriteEngine on
RewriteRule ^$ index.cfm [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.cfm/%{REQUEST_URI} [QSA,L]
IsapiRewrite.ini
IterationLimit 0
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(/.+/.+/.*\?.+\..*)$ /index.cfm/$1
RewriteRule ^(/[^.]*)$ /index.cfm/$1
Once either of those rules are applied, the ColdBox ses interceptor will correctly route.
Some Resources
- http://httpd.apache.org/docs/2.0/misc/rewriteguide.html
- http://cheeso.members.winisp.net/IIRF.aspx
- http://www.isapirewrite.com/
Configuring Your Application For SES Support
Let's start off by setting up SES support in our application. So just open your coldbox configuration file and look for the interceptors elements. If not found, create it like so:
<Interceptors> <Interceptor class="coldbox.system.interceptors.ses"> <Property name="configFile">config/routes.cfm</Property> </Interceptor> </Interceptors>
That interceptor declaration tells coldbox to use the ses interceptor and look for a configuration file in the config folder called routes.cfm. You can name your routes configuration file anything you like.
That's it, with this declaration you are ready to write your routes.
The routes configuration file
Now that you have defined where the interceptor will find its routes, all you need to do is grab the sample routes.cfm from the Application Template and start modifying it.
Below are the basic methods you will use:
| setEnabled( boolean ) | Enable/Disable routing, enabled by default |
| setUniqueURLS( boolean ) | This can produces 301 permanent moved redirects on normal ?event=handler.action URLS to SES urls. Default is true |
| setBaseURL( snippet ) | The base URL to use. If using the index.cfm approach, please write it. |
| addCourse(pattern="handler/action/:id", handler="handler_name", action="action_name") | Your method to add routes. |
Below are the methods described in detail
setEnabled
This is just a simple flag to enable ses routing or not. It is up to you.\
setUniqueURLS
This determines if non-ses urls should be routed back to the interceptor. If someone goes to
http://localhost/index.cfm?event=home.main
should we redirect (301, permanantly moved) to the url:
http://localhost/home/main
This will also make sure that any trailing index pages get redirected as well, so if you go to
http://localhost/home/index
it would redirect to
http://localhost/home
setBaseURL
The Base URL for your site. If you want your URLs to look like
http://localhost/handler/action
then you should put http://localhost here. For this option you'll need .htaccess or isapi rewrite support as described above. If you want your URLs to look more like
http://localhost/index.cfm/handler/action
then put http://localhost/index.cfm here. You can place any tier detection within this section if needed.
addCourse
This is the meat and potatoes for your routes. This is where you declared all your application routing. The syntax of these is the same as that of Coldfusion on Wheels, and similar to Ruby on Rails. The idea is that the number of variables in a URL will be the first indicator of which course to use. Here's the general setup:
<cfset addCourse(pattern="handler/action/:id", # Set the pattern handler="handler_name", # Set the handler action="action_name" )> # Set the action
Notice how the pattern argument has three parts. In this case if a request comes in that starts with /handler/action, such as
http://localhost/handler/action/oneOtherItem
, this course will match. The oneOtherItem variable will be set to the request collection as a variable with the name ID
<cfset rc["ID"] = "oneOtherItem">
before then routing to the handler_name handler and the action_name action. This would be the same as the URL
http://localhost/index.cfm?event=handler_name.action_name&id=oneOtherItem
It's important to remember that courses are evaluated in order and go with the first one that matches. For instance, if you have a course for /:handler/:action/:username, and another course later for /:handler/:action/:id, then the second course will NEVER be run. If instead you change your first course to something more generic such as /user/:action/:username, and specify (handler="user") as a second parameter, then only URLs that start with /user will qualify for having the third argument of username, while everywhere else will use a third argument of ID. The Coldfusion on Wheels help files say it best:
By the way, what's with the : syntax? In the Ruby programming language, any variable starting with a : is a symbol. Symbols are just like strings but they always point to the same place in memory and are therefore more efficient. They don't work that way here in ColdFusion?, but they make a good variable marker without worrying about where to put quotes and stuff
Route Examples
<cfset addCourse(pattern="blog/entry/:year/:month/:day", handler="blog", action="entry" )> <cfset addCourse(pattern="profile/view/:username", handler="profile", action="view" )> <cfset addCourse(":handler/:action/:id")> <cfset addCourse(":handler/:action")> <cfset addCourse(":handler")>
The Default Routes
As you can see from the sample above, the last three routes are actually the default routes that your application should have
<cfset addCourse(":handler/:action/:id")> <cfset addCourse(":handler/:action")> <cfset addCourse(":handler")>
So by having these default routes, you can easily route to any handler-action combination, or just handler combo. Very easy and snappy to use. That's it folks. That is all to know about creating your routes and configuration ses support on ColdBox. So how do I use this? Well, keep reading.
How to I relocate?
The next important part of your paths into SES is that you need to relocate to other events and also create links. So how do I do this? Well, a new method is introduced into the mix:
- setNextRoute( route, persist )
The setNextRoute() method is used as if you where using the setNextEvent method, only that you do not send in an event, but an actual route:
<cfset setNextRoute("handler/action")> <cfset setNextRoute("home/about")> <cfset setNextRoute("blog/entry/223443")>
The second parameter persist is a flash variable that you can use to persist variables in the request collection across the relocation. The framework will loop over the list and create a flash instance for all those variables and then re-inject them to the request collection upon relocation. You can even persist complex variables or even objects. How cool is that!
How about links on my pages?
Well, you would use the settings that the interceptor places for you in your configuration structure or write the absolute URL by hand:
<a href="#getSetting('sesBaseURL')#/home/about">About</a>
<a href="/home/about">About</a>
How about Form Submissions (Posts)?
As you are now using SES, the ses interceptor will parse all requests, so you have to accurately change your posting actions to the correct processor. You cannot just post it to the index with an event variable. You need to post to the correct ses action.
<form action="index.cfm/handler/action" method="post" name="testform"> All your form elements here </form>
So as you can see from the sample, the action points to: index.cfm/handler/action if you are not using the index.cfm processor then it would be: /handler/action.
How about the BASE tag
Well, for the base tag you can use either the sesBaseURL setting, if using minimal URL support, or the htmlBaseURL setting if using the index.cfm in the URL. Both of these settings are set by the interceptor at configuration time and available for your usage via the getSetting() method.
<base href="#getSetting('htmlBaseURL')#"> <base href="#getSetting('sesBaseURL')#">
Conclusion
As you can see, SES support in ColdBox is a breeze. Very easy to configure and use:
- Declare your interceptor
- Create your routes configuration file and create your routes
- Code away with the new setNextRoute() method and your two new settings: sesBaseURL & htmlBaseURL
