Sunday, June 8, 2008

Apache as an MVC controller

My colleagues know I am not a big fan of PHP frameworks, this is probably why I somewhat agree with the no-framework PHP MVC framework of Rasmus Lerdorf or with the idea of Akash Mehta thinking, to an extent, that PHP IS a framework. Keeping this global picture in mind, let me show you how Apache could take the C of MVC.

Because not mixing the business logic and the presentation is always a good idea, this leads up to have two types of PHP files: those with business logic only (the M of MVC), whether it's OOP or procedural programming, and those that are just templates containing mostly HTML (the V of MVC).

Mapping URLs to actions/views is the job of Apache, by default, it will look at your URL and make the match with the corresponding script on the filesystem. This is why I consider Apache as a controller.

Nice URL

One of the goal of a web controller is also to provide nice URL's to your application, I will present you here two methods to achieve this with Apache exclusively.

Method #1

It is quiet common Apache being configured with

DirectoryIndex index.php
Knowing this you can architect your directories with the same structure as your URLs always with an index.php file handling the request. Let's take the example of a web project management application having a dedicated page for projects and users. Your URLs might be:
  • http://project-management/projects/?id=xxx
  • http://project-management/projects/remove/?id=xxx
  • http://project-management/users/?id=xxx
  • http://project-management/users/add/
Handling this could be done using the filesystem layout as shown on the following picture:

Method #2
Another method, which may provide you even nicer URLs, relies on Apache's mod_rewrite. Let's change our URLs a little bit:
  • http://project-management/projects/xxx
  • http://project-management/projects/remove/xxx
  • http://project-management/users/xxx
  • http://project-management/users/add/
To handle this, I use a flatter filesystem layout: with the following rewrite rules:

RewriteEngine On

# Preventing access to php files directly
RewriteRule \.php$ /NotFound [L]

# Simple URL mapping
RewriteRule ^/$ /index.php [L]
RewriteRule ^/users/$ /ListUsers.php [L]
RewriteRule ^/projects/$ /ListProjects.php [L]
RewriteRule ^/users/add/$ /AddUser.php [L]
RewriteRule ^/projects/add/$ /AddProject.php [L]

# URL mapping with captured IDs
RewriteRule ^/users/([0-9]+)$ /ViewUser.php?id=$1 [L]
RewriteRule ^/projects/([0-9]+)$ /ViewProject.php?id=$1 [L]
RewriteRule ^/users/remove/([0-9]+)$ /RemoveUser.php?id=$1 [L]
RewriteRule ^/projects/remove/([0-9]+)$ /RemoveProject.php?id=$1 [L]

The first thing done is preventing direct access to PHP files, this is not mandatory but it adds some more security. The only way to reach the desired script is to match strictly the regular expression making some input filtering at the same time. Then comes the real and interesting rewrite rules. First ones are very simple mapping while the 4 last ones takes care of extracting a numerical ID from the URL and passing it to PHP as a $_GET parameter.

What do you think about such approach? Please, leave some comments :)


troelskn said...

For a dispatcher/frontcontroller, I agree -- Apache does the job just fine. In my oppinion, the need for a controller-level framework, comes in the interaction between controller and view. For example generating URL's. But there is no reason why this couldn't be combined with an Apache-as-dispatcher style setup, as you're describing it here.

Anonymous said...

Business Logic is the C of the MVC, not the M.