Url Routing with PHP - Part Two

This is the second part of a series, I assume you have read Url Routing with PHP - Part One as it covers the basics that I'll build on in Part Two.

Requirements

Assign Responsibilities

The first problem I want to address is that there are two different things going on with the script in part one. 1. The parsing of the URL to obtain a command array and 2. The actual dispatch of the command by the switch statement. I want to create an architecture that easily allows changing the way incoming URLs are formatted, and also the substitution of alternative dispatch schemes.

Standardized Command Objects

To achieve this goal, I create a standard command object. This will allow changing the way the urls are interpreted or dispatched as long as the interpreter creates command objects and the dispatcher accepts them.

  1. class Axial_Command
  2.         {
  3.         var $commandName = ";
  4.         var $parameters = array();
  5.        
  6.         function Axial_Command($commandName,$parameters)
  7.                 {
  8.                 $this->commandName = $commandName;
  9.                 $this->parameters = $parameters;
  10.                 }
  11.         function getCommandName()
  12.                 {
  13.                 return $this->commandName;
  14.                 }
  15.         function getParameters()
  16.                 {
  17.                 return $this->parameters;
  18.                 }
  19.         }

Interpreting URLs

Next we need a class that handles interpreting the incoming URL and creating a command object. The following class uses the same method as in part one and creates commands based on a simple format for the incoming URL, a command followed by its parameters separated by forward slashes.

  1. class Axial_UrlInterpreter
  2.         {
  3.  
  4.         function Axial_UrlInterpreter()
  5.                 {
  6.                 $requestURI = explode('/', $_SERVER['REQUEST_URI']);
  7.                 $scriptName = explode('/',$_SERVER['SCRIPT_NAME']);
  8.                         for($i= 0;$i < sizeof($scriptName);$i++)
  9.                                 {
  10.                                 if ($requestURI[$i] == $scriptName[$i])
  11.                                         {
  12.                                         unset($requestURI[$i]);
  13.                                         }
  14.                                 }
  15.                 $commandArray = array_values($requestURI);
  16.                 $commandName = $commandArray[0];
  17.                 $parameters = array_slice($commandArray,1);
  18.                 $this->command = new Axial_Command($commandArray[0],$parameters);
  19.                      }
  20.        
  21.         function getCommand()
  22.                 {
  23.                 return $this->command;
  24.          }
  25.         }

Dispatching Commands

And finally we can pass the command object to the dispatcher. In order to keep the code simple I use a switch statement that includes different scripts based on the command. There are many other methods that could be used in fact thats the point the of architecture I'm presenting.

  1. class Axial_CommandDispatcher
  2.         {
  3.         var $command;
  4.         function Axial_CommandDispatcher($command)
  5.                 {
  6.                 $this->command = $command;
  7.                 }
  8.  
  9.         function Dispatch()
  10.                 {
  11.                 switch ($this->command->getCommandName())
  12.                         {
  13.                         case 'commandOne' :
  14.                                 include('commandone.php');
  15.                                 break;
  16.                         case 'commandTwo' :
  17.                                 include('commandtwo.php');
  18.                                 break;
  19.                         case ":
  20.                                 include('root.php');
  21.                                 break;
  22.                         default:
  23.                                 include('default.php');
  24.                                 break;
  25.                         }
  26.                 }
  27.         }

Put it all together

In the first part of this series I used an .htaccess file to redirect to index.php. The same .htaccess is all we need now. Our new index.php will look a bit different though. With the changes from part one made we can now substitute different classes to handle the interpretation of URLs or command dispatching easily.

  1. include('axial.command.php');
  2. include('axial.urlinterpreter.php');
  3. include('axial.commanddispatcher.php');
  4. $urlInterpreter = new Axial_UrlInterpreter();
  5. $command = $urlInterpreter->getCommand();
  6. $commandDispatcher = new Axial_CommandDispatcher($command);
  7. $commandDispatcher->Dispatch();

Try it out

You can visit examples.phpaddiction.com/urlrouter/part_2/ to see it in action and download the sample code.

Next up

In the next part of this series I will explore some ways to get rid of the switch statement in the dispatcher and create a small framework to hang your code from.

Comments

5 Responses to “Url Routing with PHP - Part Two”

  1. L!MP on April 6th, 2007 2:38 pm
    Gravatar

    replace

    $this->command = new Axial_Command($commandArray[0],$parameters);

    to

    $this->command = new Axial_Command($commandName ,$parameters);

  2. Doug Hill on April 7th, 2007 12:39 am
    Gravatar

    Sure, either way works, It is quicker to leave out the array access and perhaps the clearer style, thanks for the pointer.

  3. Roman on April 8th, 2007 5:55 am
    Gravatar

    I use $_SERVER['PATH_INFO']. This way I only get what is past the script path.

  4. Doug Hill on April 9th, 2007 4:49 am
    Gravatar

    Roman: I decided against using PATH_INFO since it wouldn't allow for separators other than forward slashes "/". I wanted the entire URL after the script not just the directories. Also I found that support for PATH_INFO wasn't the same across PHP versions.

Leave a Reply




XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>