Samuel Sjöberg's weblog

Skip to navigation

An URL Dispatcher

This is part two of the Improving my MVC controllers post. I have now implemented an URL dispatcher that dispatches the request to a configurable Controller.

My goal was to make a minimal implementation as a contrast to the frameworks that already exists out there. If a lot of fancy functionality (e.g., scaffolding, caching, ajax-helpers and database migration) is needed, a framework should probably be used instead. I haven't written a framework. I have written a Dispatcher that don't require me to use a framework!

A quick look at the directory structure

The minimal number of files needed to use the dispatcher are those contained in the core directory, paired with a .htaccess file and the index.php file that invokes the dispatcher. For the dispatcher to actually do something, an application configuration ini-file is also needed.

The structure to the right is the one I chose to work with when I implemented the pattern. This is of course configurable in config.php. If you have used any of the PHP frameworks, or even RoR, you probably recognize the overall structure.

The app folder contains the whole webapp, except for images, CSS and other static content files that needs to be in the web-root (the www directory). The structure of the webapp is arbitrary and configurable, but this is the structure I think will be useful. The classes directory should contain logic that isn't related to the data model, this could for example be the template engine and other helper classes.

The error-doc directory in the structure above contains error message files (dynamically handled), but are not required to be placed there.

How the dispatcher works

A requested URL is mapped to a Controller in the application.ini file. The mapping is performed against a partial URL and the defined parameters.

The controller must be contained in a file with the same name as the class. The controller Demo must for example be defined in Demo.class.php. The file ending is however configurable.

Below is an example definition:

[demo/*]
controller = Demo
parameters = int year, int month, mixed title

[/]
controller = Frontpage

In the example above, the Demo controller is invoked for requests to the demo application, i.e. http://example.org/demo. The wildcard (*) denotes that everything following demo will be matched against the parameters.

Parameters are used to map consecutive parts of the URL into GET variables. The parameters are matched against their defined type and the controller will only be invoked if the supplied value matches the definition. Valid parameter types are int, string and mixed.

It is also important to know that the controller can be invoked with only the first, or the first and second parameters set, but it will never be invoked with only the last parameter set. It will neither be invoked if more than the number of defined parameters are defined in the URL.

Perhaps best explained with examples:

Request Dispatched
/demo/ yes
/demo/2007 yes
/demo/2007/01 yes
/demo/2007/01/title yes
/demo/title no
/demo/2007/title no
/demo/2007/01/title/extra no
/demo/2007/01/title?extra=more yes

If no match is found, a 404 file not found page will be displayed. If you need to handle arbitrary requests you can do this by providing a wildcard controller:

[*]
controller = DynamicController

This controlled will always be invoked, just make sure to put it last in the ini-file. This feature can be useful in a CMS, when a dynamic page is loaded. The dispatcher isn't responsible for checking if a page exists in the database.

Putting it into work

To use the dispatcher, the web-root should contain a .htaccess file that contains the following (I assume mod_rewrite is active on the server):

Options +FollowSymLinks -Indexes
RewriteEngine On

RewriteCond %{REQUEST_FILENAME}  !-l
RewriteCond %{REQUEST_FILENAME}  !-d
RewriteCond %{REQUEST_FILENAME}  !-f
RewriteRule .* index.php?%{QUERY_STRING} [L]

The above rules will ensure that every request that isn't to an existing file, directory or symbolic link will be redirected to our script.

The index.php file only needs to contain the following:

<?php
require_once('../core/core.php');

$dispatcher = &new Dispatcher();
$dispatcher->dispatch($_SERVER['REQUEST_URI']);
?>

Download example

I have uploaded a zip that contains the solution. Feel free to try it out. In addition to the dispatcher, it contains my Template and DB classes.

Download the dispatcher-1.0.zip

Reader comments

  1. Hi,

    Thanks for sharing that,I really like the idea. I was just starting to design my own dispatcher and template system (simple class with some helper methods) and this is great jumping of point.

    AJ

    17th January 2009, 03:33 CET. 
  2. nice thing and very useful.

    i am coding my own framework/mvc/cms so i got inspired by your dispatcher :)

    but i have a little problem you may solve

    my webproject supports different languages and works with and without .htaccess (mod_rewrite)

    so my urls are like these :
    www[dot]mydomain[dot]com/language/dir/subdir/

    how would you dispatch the language inside this? i thought about a seperate language class (loaded if multi lingual) with a 'getlanguages' function. So i can get all accepted languages (client) and can compare them to all possible languages (server). but how find the best match?

    example german user :
    de,de-DE,q=0.8;de,q=0.6;en
    my site supports de and en
    so my
    'accepted' are de,en
    'possible' are de,en

    maybe you can find a good solution

    11th May 2010, 15:40 CET. 
  3. gj

    6th October 2010, 18:23 CET. 

Pages linking to this entry

Pingback is enabled on all archived entries. Read more about pingback in the Pingback 1.0 Specification.

About this post

Created 2nd January 2007 15:39 CET. Filed under PHP.

3 Comments
0 Pingbacks