8 Jun 2008
Horde_Routes</a> is a new Horde library that is derived from the <a target="_blank" href="http://routes.groovie.org/">Python Routes</a> project. I've been meaning to give it a look for some time now, and a recent rewrite / cleanup of an Ansel powered <a title="My father-in-law's artwork" target="_blank" href="http://theabramsgallery.com">gallery site</a> gave me the perfect opportunity to dive in.</p>
<p>In previous articles, I've outlined the basics of using Ansel to power an external gallery site. In this article, we'll look at using Horde_Routes to map 'pretty' URLs to the PHP code. </p>
<p>The site is simple. It is basically nothing more than a thin wrapper around some of Ansel's views, with an 'About Us' and 'Home' page thrown in for good measure. I decided to implement the URLs like so:</p>
<p> <code>
/ - The home, or default route <br /> /galleries - The top level, paged gallery list.<br />/x - A gallery view where x represents the gallery id.<br />/x/y - An image view where y represents the image id.
</code> </p>
<p>In all cases, paging is done with a 'page' URL parameter tacked on. For purely static pages, such as the About Us page, I have a path such as:</p>
<p> <code>
/content/about
</code> </p>
<p>With the paths hashed out, it's time to look at the code. The first thing you need to do to enable Routes is to set up a rewrite rule on your webserver to pass all requests for your site to your controller script. On my site, I decided to name my controller script <em>dispatcher.php</em> since that pretty accurately represents it's responsibilities. How to go about setting up the rewrite rules will differ depending on your web server. I use <em>lighttpd</em> for my sites, and, as I found out, this has a particular 'gotcha' when dealing with a Routes enabled site. </p>
<p>Apache has a switch that allows it to ignore any rewrite rules when the requested file already exists. This makes dealing with things like stylesheets, images and script files easy. With lighttpd, it's not so easy. Consider the following rewrite rule:</p>
<p> <code>
"^(.*)$" => "/dispatcher.php?url=$1"
</code> </p>
<p>This basically takes all requests for your site (I'm assuming the Routes site is at the root of your site) and forwards it to <em>displatcher.php</em> and tacks on the requested path as a URL parameter. See the problem? Lighttpd does not ignore rewrite rules for existing files, so a request for a stylesheet, <em>/themes/default.css</em> will fail. The same for images, javascript files etc... To overcome this in lighttpd, you need to add a rewrite rule such as:</p>
<p><code> </code></p>
<p>"^/(css|files|img|js)/.*$" => "$0"</p>
<p>Which, as you might guess, basically causes lighttpd to not rewrite the URLs that match the pattern given. With that in mind, and a rewrite rule to make sure that the default route of '/' is properly dealt with, my rewrite rules for this site look like this:</p>
<p><code> $HTTP["host"] =~ "^(www.)?theabramsgallery\.com$" {
url.rewrite-once += (
"^/?$" => "/dispatcher.php?url=/",
"^/(css|files|img|js)/.*$" => "$0",
"^(.*)$" => "/dispatcher.php?url=$1")
}
</code> </p>
<p>The next step is to set up Routes and tell it about our desired mappings. This should be done in either some sort of config file, or a base include file for your site. First the code, then the explanation:<br /></p>
<p><code> <span style="color: #007700;">* </span><span style="color: #0000bb;">Set up the Routes </span><span style="color: #007700;">*/
</span><span style="color: #0000bb;">$m </span><span style="color: #007700;">= new </span><span style="color: #0000bb;">Horde_Routes_Mapper</span><span style="color: #007700;">();
</span><span style="color: #ff8000;">/* 'Home' route */
</span><span style="color: #0000bb;">$m</span><span style="color: #007700;">-></span><span style="color: #0000bb;">connect</span><span style="color: #007700;">(</span><span style="color: #dd0000;">'home'</span><span style="color: #007700;">, </span><span style="color: #dd0000;">''</span><span style="color: #007700;">, array(</span><span style="color: #dd0000;">'controller' </span><span style="color: #007700;">=> </span><span style="color: #dd0000;">'index'</span><span style="color: #007700;">));
</span><span style="color: #ff8000;">/* General content Pages */
</span><span style="color: #0000bb;">$m</span><span style="color: #007700;">-></span><span style="color: #0000bb;">connect</span><span style="color: #007700;">(</span><span style="color: #dd0000;">'content'</span><span style="color: #007700;">, </span><span style="color: #dd0000;">'/content/:content'</span><span style="color: #007700;">,
array(</span><span style="color: #dd0000;">'controller' </span><span style="color: #007700;">=> </span><span style="color: #dd0000;">'content'</span><span style="color: #007700;">,
</span><span style="color: #dd0000;">'action' </span><span style="color: #007700;">=> </span><span style="color: #dd0000;">'view'</span><span style="color: #007700;">));
</span><span style="color: #ff8000;">/* Gallery List */
</span><span style="color: #0000bb;">$m</span><span style="color: #007700;">-></span><span style="color: #0000bb;">connect</span><span style="color: #007700;">(</span><span style="color: #dd0000;">'list'</span><span style="color: #007700;">, </span><span style="color: #dd0000;">'galleries'</span><span style="color: #007700;">, array(</span><span style="color: #dd0000;">'controller' </span><span style="color: #007700;">=> </span><span style="color: #dd0000;">'galleries'</span><span style="color: #007700;">,
</span><span style="color: #dd0000;">'action' </span><span style="color: #007700;">=> </span><span style="color: #dd0000;">'index'</span><span style="color: #007700;">));
</span><span style="color: #ff8000;">/* Gallery View */
</span><span style="color: #0000bb;">$m</span><span style="color: #007700;">-></span><span style="color: #0000bb;">connect</span><span style="color: #007700;">(</span><span style="color: #dd0000;">'gallery'</span><span style="color: #007700;">, </span><span style="color: #dd0000;">'/:id'</span><span style="color: #007700;">, array(</span><span style="color: #dd0000;">'controller' </span><span style="color: #007700;">=> </span><span style="color: #dd0000;">'galleries'</span><span style="color: #007700;">,
</span><span style="color: #dd0000;">'action' </span><span style="color: #007700;">=> </span><span style="color: #dd0000;">'view'</span><span style="color: #007700;">));
</span><span style="color: #ff8000;">/* Image View */
</span><span style="color: #0000bb;">$m</span><span style="color: #007700;">-></span><span style="color: #0000bb;">connect</span><span style="color: #007700;">(</span><span style="color: #dd0000;">'image'</span><span style="color: #007700;">, </span><span style="color: #dd0000;">'/:id/:image'</span><span style="color: #007700;">, array(</span><span style="color: #dd0000;">'controller' </span><span style="color: #007700;">=> </span><span style="color: #dd0000;">'images'</span><span style="color: #007700;">,
</span><span style="color: #dd0000;">'action' </span><span style="color: #007700;">=> </span><span style="color: #dd0000;">'view'</span><span style="color: #007700;">));
</span><span style="color: #ff8000;">/* Advertise our controllers */
</span><span style="color: #0000bb;">$m</span><span style="color: #007700;">-></span><span style="color: #0000bb;">createRegs</span><span style="color: #007700;">(array(</span><span style="color: #dd0000;">'index'</span><span style="color: #007700;">, </span><span style="color: #dd0000;">'galleries'</span><span style="color: #007700;">, </span><span style="color: #dd0000;">'images'</span><span style="color: #007700;">, </span><span style="color: #dd0000;">'content'</span><span style="color: #007700;">));</span></code></p>
<p>The first line creates a new instance of the Mapper object. With it, we 'connect' new mappings with the <em>connect()</em> method. Each <em>connect() </em>call as called above, takes 3 arguments (it can actually take a variable number of arguments - see the documentation for details). The first is the name of the route. It is not used at all when mapping a URL to an action, but it makes it easier when generating a URL within your site (see below). The second argument is the <em>Route Path</em> and can be composed of both <em>static </em>and <em>dynamic</em> parts. Static parts of the path are not preceded by a ':' , dynamic parts are. For example, the <em>list</em> route contains only a static path - <em>galleries. </em>This means that only the URL /galleries will match this route. The <em>gallery</em> route contains only a dynamic part, /:id. So a URL such as /10 will match this route. The third parameter is what actually determines what controller will be responsible for this action. As you can see, it does not have to mirror the paths...for example, you can see that I use the <em>galleries</em> controller for both the <em>list</em> and the <em>gallery</em> routes.<br /></p>
<p> </p>
<p>OK. So, now we know what controllers are responsible for what routes. Great. Now what? Well, now it's time to write the code that will handle the requests and pass off to the correct controller. For this, as stated above, I used a file named <em>dispatcher.php</em>. In that file is:</p>
<p><code> <span style="color: #007700;">require_once </span><span style="color: #0000bb;">dirname</span><span style="color: #007700;">(</span><span style="color: #0000bb;">__FILE__</span><span style="color: #007700;">) . </span><span style="color: #dd0000;">'/lib/base.php'</span><span style="color: #007700;">;
</span><span style="color: #ff8000;">/* Grab, and hopefully match, the URL */
</span><span style="color: #0000bb;">$url </span><span style="color: #007700;">= </span><span style="color: #0000bb;">Util</span><span style="color: #007700;">::</span><span style="color: #0000bb;">getFormData</span><span style="color: #007700;">(</span><span style="color: #dd0000;">'url'</span><span style="color: #007700;">);
</span><span style="color: #ff8000;">/* Get rid of any query args */
</span><span style="color: #007700;">if ((</span><span style="color: #0000bb;">$pos </span><span style="color: #007700;">= </span><span style="color: #0000bb;">strpos</span><span style="color: #007700;">(</span><span style="color: #0000bb;">$url</span><span style="color: #007700;">, </span><span style="color: #dd0000;">'?'</span><span style="color: #007700;">)) !== </span><span style="color: #0000bb;">false</span><span style="color: #007700;">) {
list(</span><span style="color: #0000bb;">$url</span><span style="color: #007700;">, </span><span style="color: #0000bb;">$query</span><span style="color: #007700;">) = </span><span style="color: #0000bb;">explode</span><span style="color: #007700;">(</span><span style="color: #dd0000;">'?'</span><span style="color: #007700;">, </span><span style="color: #0000bb;">$url</span><span style="color: #007700;">, </span><span style="color: #0000bb;">2</span><span style="color: #007700;">);
</span><span style="color: #0000bb;">parse_str</span><span style="color: #007700;">(</span><span style="color: #0000bb;">$query</span><span style="color: #007700;">, </span><span style="color: #0000bb;">$args</span><span style="color: #007700;">);
} else {
</span><span style="color: #0000bb;">$args </span><span style="color: #007700;">= array();
}
</span><span style="color: #0000bb;">$match </span><span style="color: #007700;">= </span><span style="color: #0000bb;">$m</span><span style="color: #007700;">-></span><span style="color: #0000bb;">match</span><span style="color: #007700;">(</span><span style="color: #0000bb;">$url</span><span style="color: #007700;">);</span> <span style="color: #007700;">.</span> <span style="color: #007700;">. // Do stuff</span> <span style="color: #007700;">.</span> <span style="color: #007700;"></span><span style="color: #007700;"> </span><span style="color: #ff8000;">/* Hand off to the proper controller */
</span><span style="color: #0000bb;">$action </span><span style="color: #007700;">= </span><span style="color: #0000bb;">$match</span><span style="color: #007700;">[</span><span style="color: #dd0000;">'action'</span><span style="color: #007700;">];
include </span><span style="color: #0000bb;">dirname</span><span style="color: #007700;">(</span><span style="color: #0000bb;">__FILE__</span><span style="color: #007700;">) . </span><span style="color: #dd0000;">'/' </span><span style="color: #007700;">. </span><span style="color: #0000bb;">$match</span><span style="color: #007700;">[</span><span style="color: #dd0000;">'controller'</span><span style="color: #007700;">] . </span><span style="color: #dd0000;">'.php'</span><span style="color: #007700;">;</span> </code></p>
<p>In the first section of the code, we get the requested path from the query parameter. We then have to strip off any query parameters that were passed in with the path. Routes will only match URLs with no query arguments. Then, we call the <em>match()</em> method of our <em>Mapper</em> object and are passed back an array representing the matched route. This is a fairly simple site, I use a separate PHP file for each controller. I've omitted code from my dispatcher that doesn't relate to Routes, mainly I also set up a Horde_View object that I use in all my controllers to handle the displaying of the view template.</p>
<p>The only thing left really, for a basic Routes driven site is generating the URLs for the site. That's done with the <em>Horde_Routes_Utils#urlFor </em>method like so:</p>
<p><code> <span style="color: #0000bb;">$url = $m</span><span style="color: #007700;">-></span><span style="color: #0000bb;">utils</span><span style="color: #007700;">-></span><span style="color: #0000bb;">urlFor</span><span style="color: #007700;">(</span><span style="color: #dd0000;">'image'</span><span style="color: #007700;">, array(</span><span style="color: #007700;"> </span><span style="color: #dd0000;">'id' </span><span style="color: #007700;">=> </span><span style="color: #dd0000;">'5'</span><span style="color: #007700;">,
</span><span style="color: #dd0000;">'image' </span><span style="color: #007700;">=> </span><span style="color: #dd0000;">'10'</span><span style="color: #007700;">));</span> </code></p>
<p> This line would generate a URL for an image view like /5/10 where 5 is the gallery id and 10 is the image id. In the above code, you see that the array keys match the <em>dynamic</em> parts of the route path you defined with the <em>connect()</em> method.</p>
<p>I plan on refactoring all the websites under my control to use Horde_Routes, and I'd encourage you to take a look at the documentation at <a href="http://dev.horde.org/routes">http://dev.horde.org/routes</a> to learn more!</p>
<p>Many thanks to Chuck who helped me sort out some things while working with Routes.<br /></p>
Diving into Horde_Routes
<p><a target="_blank" href="http://dev.horde.org/routes">Horde_Routes</a> is a new Horde library that is derived from the <a target="_blank" href="http://routes.groovie.org/">Python Routes</a> project. I've been meaning to give it a look for some time now, and a recent rewrite / cleanup of an Ansel powered <a title="My father-in-law's artwork" target="_blank" href="http://theabramsgallery.com">gallery site</a> gave me the perfect opportunity to dive in.</p>
<p>In previous articles, I've outlined the basics of using Ansel to power an external gallery site. In this article, we'll look at using Horde_Routes to map 'pretty' URLs to the PHP code. </p>
<p>The site is simple. It is basically nothing more than a thin wrapper around some of Ansel's views, with an 'About Us' and 'Home' page thrown in for good measure. I decided to implement the URLs like so:</p>
<p> <code>
/ - The home, or default route <br /> /galleries - The top level, paged gallery list.<br />/x - A gallery view where x represents the gallery id.<br />/x/y - An image view where y represents the image id.
</code> </p>
<p>In all cases, paging is done with a 'page' URL parameter tacked on. For purely static pages, such as the About Us page, I have a path such as:</p>
<p> <code>
/content/about
</code> </p>
<p>With the paths hashed out, it's time to look at the code. The first thing you need to do to enable Routes is to set up a rewrite rule on your webserver to pass all requests for your site to your controller script. On my site, I decided to name my controller script <em>dispatcher.php</em> since that pretty accurately represents it's responsibilities. How to go about setting up the rewrite rules will differ depending on your web server. I use <em>lighttpd</em> for my sites, and, as I found out, this has a particular 'gotcha' when dealing with a Routes enabled site. </p>
<p>Apache has a switch that allows it to ignore any rewrite rules when the requested file already exists. This makes dealing with things like stylesheets, images and script files easy. With lighttpd, it's not so easy. Consider the following rewrite rule:</p>
<p> <code>
"^(.*)$" => "/dispatcher.php?url=$1"
</code> </p>
<p>This basically takes all requests for your site (I'm assuming the Routes site is at the root of your site) and forwards it to <em>displatcher.php</em> and tacks on the requested path as a URL parameter. See the problem? Lighttpd does not ignore rewrite rules for existing files, so a request for a stylesheet, <em>/themes/default.css</em> will fail. The same for images, javascript files etc... To overcome this in lighttpd, you need to add a rewrite rule such as:</p>
<p><code> </code></p>
<p>"^/(css|files|img|js)/.*$" => "$0"</p>
<p>Which, as you might guess, basically causes lighttpd to not rewrite the URLs that match the pattern given. With that in mind, and a rewrite rule to make sure that the default route of '/' is properly dealt with, my rewrite rules for this site look like this:</p>
<p><code> $HTTP["host"] =~ "^(www.)?theabramsgallery\.com$" {
url.rewrite-once += (
"^/?$" => "/dispatcher.php?url=/",
"^/(css|files|img|js)/.*$" => "$0",
"^(.*)$" => "/dispatcher.php?url=$1")
}
</code> </p>
<p>The next step is to set up Routes and tell it about our desired mappings. This should be done in either some sort of config file, or a base include file for your site. First the code, then the explanation:<br /></p>
<p><code> <span style="color: #007700;">* </span><span style="color: #0000bb;">Set up the Routes </span><span style="color: #007700;">*/
</span><span style="color: #0000bb;">$m </span><span style="color: #007700;">= new </span><span style="color: #0000bb;">Horde_Routes_Mapper</span><span style="color: #007700;">();
</span><span style="color: #ff8000;">/* 'Home' route */
</span><span style="color: #0000bb;">$m</span><span style="color: #007700;">-></span><span style="color: #0000bb;">connect</span><span style="color: #007700;">(</span><span style="color: #dd0000;">'home'</span><span style="color: #007700;">, </span><span style="color: #dd0000;">''</span><span style="color: #007700;">, array(</span><span style="color: #dd0000;">'controller' </span><span style="color: #007700;">=> </span><span style="color: #dd0000;">'index'</span><span style="color: #007700;">));
</span><span style="color: #ff8000;">/* General content Pages */
</span><span style="color: #0000bb;">$m</span><span style="color: #007700;">-></span><span style="color: #0000bb;">connect</span><span style="color: #007700;">(</span><span style="color: #dd0000;">'content'</span><span style="color: #007700;">, </span><span style="color: #dd0000;">'/content/:content'</span><span style="color: #007700;">,
array(</span><span style="color: #dd0000;">'controller' </span><span style="color: #007700;">=> </span><span style="color: #dd0000;">'content'</span><span style="color: #007700;">,
</span><span style="color: #dd0000;">'action' </span><span style="color: #007700;">=> </span><span style="color: #dd0000;">'view'</span><span style="color: #007700;">));
</span><span style="color: #ff8000;">/* Gallery List */
</span><span style="color: #0000bb;">$m</span><span style="color: #007700;">-></span><span style="color: #0000bb;">connect</span><span style="color: #007700;">(</span><span style="color: #dd0000;">'list'</span><span style="color: #007700;">, </span><span style="color: #dd0000;">'galleries'</span><span style="color: #007700;">, array(</span><span style="color: #dd0000;">'controller' </span><span style="color: #007700;">=> </span><span style="color: #dd0000;">'galleries'</span><span style="color: #007700;">,
</span><span style="color: #dd0000;">'action' </span><span style="color: #007700;">=> </span><span style="color: #dd0000;">'index'</span><span style="color: #007700;">));
</span><span style="color: #ff8000;">/* Gallery View */
</span><span style="color: #0000bb;">$m</span><span style="color: #007700;">-></span><span style="color: #0000bb;">connect</span><span style="color: #007700;">(</span><span style="color: #dd0000;">'gallery'</span><span style="color: #007700;">, </span><span style="color: #dd0000;">'/:id'</span><span style="color: #007700;">, array(</span><span style="color: #dd0000;">'controller' </span><span style="color: #007700;">=> </span><span style="color: #dd0000;">'galleries'</span><span style="color: #007700;">,
</span><span style="color: #dd0000;">'action' </span><span style="color: #007700;">=> </span><span style="color: #dd0000;">'view'</span><span style="color: #007700;">));
</span><span style="color: #ff8000;">/* Image View */
</span><span style="color: #0000bb;">$m</span><span style="color: #007700;">-></span><span style="color: #0000bb;">connect</span><span style="color: #007700;">(</span><span style="color: #dd0000;">'image'</span><span style="color: #007700;">, </span><span style="color: #dd0000;">'/:id/:image'</span><span style="color: #007700;">, array(</span><span style="color: #dd0000;">'controller' </span><span style="color: #007700;">=> </span><span style="color: #dd0000;">'images'</span><span style="color: #007700;">,
</span><span style="color: #dd0000;">'action' </span><span style="color: #007700;">=> </span><span style="color: #dd0000;">'view'</span><span style="color: #007700;">));
</span><span style="color: #ff8000;">/* Advertise our controllers */
</span><span style="color: #0000bb;">$m</span><span style="color: #007700;">-></span><span style="color: #0000bb;">createRegs</span><span style="color: #007700;">(array(</span><span style="color: #dd0000;">'index'</span><span style="color: #007700;">, </span><span style="color: #dd0000;">'galleries'</span><span style="color: #007700;">, </span><span style="color: #dd0000;">'images'</span><span style="color: #007700;">, </span><span style="color: #dd0000;">'content'</span><span style="color: #007700;">));</span></code></p>
<p>The first line creates a new instance of the Mapper object. With it, we 'connect' new mappings with the <em>connect()</em> method. Each <em>connect() </em>call as called above, takes 3 arguments (it can actually take a variable number of arguments - see the documentation for details). The first is the name of the route. It is not used at all when mapping a URL to an action, but it makes it easier when generating a URL within your site (see below). The second argument is the <em>Route Path</em> and can be composed of both <em>static </em>and <em>dynamic</em> parts. Static parts of the path are not preceded by a ':' , dynamic parts are. For example, the <em>list</em> route contains only a static path - <em>galleries. </em>This means that only the URL /galleries will match this route. The <em>gallery</em> route contains only a dynamic part, /:id. So a URL such as /10 will match this route. The third parameter is what actually determines what controller will be responsible for this action. As you can see, it does not have to mirror the paths...for example, you can see that I use the <em>galleries</em> controller for both the <em>list</em> and the <em>gallery</em> routes.<br /></p>
<p> </p>
<p>OK. So, now we know what controllers are responsible for what routes. Great. Now what? Well, now it's time to write the code that will handle the requests and pass off to the correct controller. For this, as stated above, I used a file named <em>dispatcher.php</em>. In that file is:</p>
<p><code> <span style="color: #007700;">require_once </span><span style="color: #0000bb;">dirname</span><span style="color: #007700;">(</span><span style="color: #0000bb;">__FILE__</span><span style="color: #007700;">) . </span><span style="color: #dd0000;">'/lib/base.php'</span><span style="color: #007700;">;
</span><span style="color: #ff8000;">/* Grab, and hopefully match, the URL */
</span><span style="color: #0000bb;">$url </span><span style="color: #007700;">= </span><span style="color: #0000bb;">Util</span><span style="color: #007700;">::</span><span style="color: #0000bb;">getFormData</span><span style="color: #007700;">(</span><span style="color: #dd0000;">'url'</span><span style="color: #007700;">);
</span><span style="color: #ff8000;">/* Get rid of any query args */
</span><span style="color: #007700;">if ((</span><span style="color: #0000bb;">$pos </span><span style="color: #007700;">= </span><span style="color: #0000bb;">strpos</span><span style="color: #007700;">(</span><span style="color: #0000bb;">$url</span><span style="color: #007700;">, </span><span style="color: #dd0000;">'?'</span><span style="color: #007700;">)) !== </span><span style="color: #0000bb;">false</span><span style="color: #007700;">) {
list(</span><span style="color: #0000bb;">$url</span><span style="color: #007700;">, </span><span style="color: #0000bb;">$query</span><span style="color: #007700;">) = </span><span style="color: #0000bb;">explode</span><span style="color: #007700;">(</span><span style="color: #dd0000;">'?'</span><span style="color: #007700;">, </span><span style="color: #0000bb;">$url</span><span style="color: #007700;">, </span><span style="color: #0000bb;">2</span><span style="color: #007700;">);
</span><span style="color: #0000bb;">parse_str</span><span style="color: #007700;">(</span><span style="color: #0000bb;">$query</span><span style="color: #007700;">, </span><span style="color: #0000bb;">$args</span><span style="color: #007700;">);
} else {
</span><span style="color: #0000bb;">$args </span><span style="color: #007700;">= array();
}
</span><span style="color: #0000bb;">$match </span><span style="color: #007700;">= </span><span style="color: #0000bb;">$m</span><span style="color: #007700;">-></span><span style="color: #0000bb;">match</span><span style="color: #007700;">(</span><span style="color: #0000bb;">$url</span><span style="color: #007700;">);</span> <span style="color: #007700;">.</span> <span style="color: #007700;">. // Do stuff</span> <span style="color: #007700;">.</span> <span style="color: #007700;"></span><span style="color: #007700;"> </span><span style="color: #ff8000;">/* Hand off to the proper controller */
</span><span style="color: #0000bb;">$action </span><span style="color: #007700;">= </span><span style="color: #0000bb;">$match</span><span style="color: #007700;">[</span><span style="color: #dd0000;">'action'</span><span style="color: #007700;">];
include </span><span style="color: #0000bb;">dirname</span><span style="color: #007700;">(</span><span style="color: #0000bb;">__FILE__</span><span style="color: #007700;">) . </span><span style="color: #dd0000;">'/' </span><span style="color: #007700;">. </span><span style="color: #0000bb;">$match</span><span style="color: #007700;">[</span><span style="color: #dd0000;">'controller'</span><span style="color: #007700;">] . </span><span style="color: #dd0000;">'.php'</span><span style="color: #007700;">;</span> </code></p>
<p>In the first section of the code, we get the requested path from the query parameter. We then have to strip off any query parameters that were passed in with the path. Routes will only match URLs with no query arguments. Then, we call the <em>match()</em> method of our <em>Mapper</em> object and are passed back an array representing the matched route. This is a fairly simple site, I use a separate PHP file for each controller. I've omitted code from my dispatcher that doesn't relate to Routes, mainly I also set up a Horde_View object that I use in all my controllers to handle the displaying of the view template.</p>
<p>The only thing left really, for a basic Routes driven site is generating the URLs for the site. That's done with the <em>Horde_Routes_Utils#urlFor </em>method like so:</p>
<p><code> <span style="color: #0000bb;">$url = $m</span><span style="color: #007700;">-></span><span style="color: #0000bb;">utils</span><span style="color: #007700;">-></span><span style="color: #0000bb;">urlFor</span><span style="color: #007700;">(</span><span style="color: #dd0000;">'image'</span><span style="color: #007700;">, array(</span><span style="color: #007700;"> </span><span style="color: #dd0000;">'id' </span><span style="color: #007700;">=> </span><span style="color: #dd0000;">'5'</span><span style="color: #007700;">,
</span><span style="color: #dd0000;">'image' </span><span style="color: #007700;">=> </span><span style="color: #dd0000;">'10'</span><span style="color: #007700;">));</span> </code></p>
<p> This line would generate a URL for an image view like /5/10 where 5 is the gallery id and 10 is the image id. In the above code, you see that the array keys match the <em>dynamic</em> parts of the route path you defined with the <em>connect()</em> method.</p>
<p>I plan on refactoring all the websites under my control to use Horde_Routes, and I'd encourage you to take a look at the documentation at <a href="http://dev.horde.org/routes">http://dev.horde.org/routes</a> to learn more!</p>
<p>Many thanks to Chuck who helped me sort out some things while working with Routes.<br /></p>
Tags: horde, php, routes Permalink
