====== Introduction to Routes ======
===== What and Why =====
Akelos implements **native PHP rewriting**, thus shifting the responsibility of URL parsing from the webserver to Akelos itself. This feature has been added for these reasons.
- Not all webservers support rewriting. By moving this code to the framework Akelos is able to function “out of the box” on almost all webservers.
- Static-like URLs generated by Akelos are designed to be search-engine and human friendly.
- A rewriting implementation in Akelos can also be used to generate custom URLs by linking it to the standard URL helpers such as url_for, link_to, and redirect_to.
Akelos We will try to guess if mod_rewrite is enabled on your server. If it is not enabled http://example.com/post/all will be replaced by http://example.com/?ak=post/all. If you know that mod_rewrite is enabled, you should define AK_ENABLE_URL_REWRITE as true in your config/config.php file to avoid the overhead of mod_rewrite auto detection.
===== Diving In =====
Routes have been designed to be fully customizable by the average PHP programmer. You’ll no longer have to be a .htaccess wizard to have pretty URLs for your site.
Routes are defined in "config/routes.php". This file is a typical PHP source file which contains a document similar to
$Map->connect('/', array('controller' => 'page', 'action' => 'index'));
Instead of wading through the tedious and obvious, let’s dive right in.
==== Example 1—Setting A Default Controller ====
Let’s say you’re one of those cool kids with a blog, and you’d like "http://www.your-cool-domain.com/" to show your recent posts.
=== Case 1 - BlogController::index() ===
Lets say your BlogController’s index action is already setup to show the list of recent posts. To specify the default controller, we add 'controller' => ‘blog’ to the default route:
$Map->connect('/:controller/:action/:id', array('controller' => 'blog'));
As an additional perk, Routes will opt for the shortest path possible, so "url_for :controller => ‘blog’, :action => ‘index’" will generate a url such as "http://www.your-cool-domain.com/".
=== Case 2—BlogController#recent ===
Lets suppose that for whatever reason, your BlogController displays the recent posts with another action. We need to add a new Route that matches an empty path and points to BlogController’s "recent" action.
$Map->connect('/', array('controller' => 'blog', 'action' => 'recent'));
$Map->connect('/:controller/:action/:id', array('controller' => 'page', 'action' => 'index'));
Notice that we put our new route before the default Akelos route. Routes are recognized and generated in the order they are defined. By placing our custom route before the default Akelos route, we can be assured that "url_for :controller => ‘blog’, :action => ‘recent’" will generate a URL with an empty path, such as "http://www.your-cool-domain.com/".
==== Example 2—Setting up date-based URLs ====
Suppose you want to add a feature to your blog that let’s your visitors view posts by date. You’d like to allow them to browse by year, month, and day, and you already have an action which uses query or post parameters named year, month, and action.
The ideal URL for this looks like "http://www.your-cool-domain.com/2005/02/14", with the month and day components being optional. Because you’re a sane person, you decide that the date order should be YYYY/MM/DD, rather than some arcane order such as MM/DD/YYYY.
Once again, we will want to add our custom route before the default Akelos route. A first try at this might yield
$Map->connect('/:year/:month/:day', array(
'controller' => 'blog',
'action' => 'by_date',
));
Although this will successfully match "http://www.your-cool-domain.com/date/2005/02/14", it will fail to do so for http://www.your-cool-domain.com/date/2005/02 - we need to mark the ":month" and ":day" components as optional. To do so, we add "'month' => OPTIONAL" to our route:
$Map->connect('/:year/:month/:day', array(
'controller' => 'blog',
'action' => 'by_date',
'month' => OPTIONAL,
'day' => OPTIONAL,
));
Now our custom route will recognize URLs such as "http://www.your-cool-domain.com/date/2005/02" or even "http://www.your-cool-domain.com/date/2005". On the flip side, our custom route will also be used automatically when URLs are generated with the standard forms helpers such as link_to and url_for.
Now we run into another problem—our new route is too general, and it will catch all three-component URLs—such as "posts/show/10". To combat this, we must tell place some requirements on our path components. Requirements are placed on the third parameter of $Map->connect like so:
$Map->connect('/:year/:month/:day', array(
'controller' => 'blog',
'action' => 'by_date',
'month' => OPTIONAL,
'day' => OPTIONAL,
'year' => COMPULSORY),
// Requirements
array(
'year'=>'/(20){1}\d{2}/',
'month'=>'/((1)?\d{1,2}){2}/',
'day'=>'/(([1-3])?\d{1,2}){2}/'
)
);
==== Example 3 — Posts by Category ====
Lets move back to your BlogController. Suppose each of your posts belong to a "category", and that we would like URLs to show items based on category, such as "http://www.your-cool-domain.com/posts/akelos". Lets assume that you also use the category “all” to mean show all categories. A quick route for this would be:
$Map->connect('/posts/:category', array('controller' => 'blog', 'action' => 'posts'));
The problem with this route is that your "link_to" statements will all have to include ":category => ‘all’". It would be nicer if our templates could contain
<%= link_to 'Posts', :controller => 'blog', :action => 'posts' %>
We can achieve this by giving the route a default value for ":category":
$Map->connect('/posts/:category', array('controller' => 'blog', 'action' => 'posts', 'category' => 'all'));
An added bonus is that the URL generated for the above "link_to" will omit the extraneous ‘all’ component, and be displayed as "http://www.your-cool-domain.com/posts".