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
- Apache with mod_rewrite enabled
- PHP
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.
-
class Axial_Command
-
{
-
var $commandName = ";
-
-
function Axial_Command($commandName,$parameters)
-
{
-
$this->commandName = $commandName;
-
$this->parameters = $parameters;
-
}
-
function getCommandName()
-
{
-
return $this->commandName;
-
}
-
function getParameters()
-
{
-
return $this->parameters;
-
}
-
}
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Â.
-
class Axial_UrlInterpreter
-
{
-
-
function Axial_UrlInterpreter()
-
{
-
{
-
if ($requestURI[$i] == $scriptName[$i])
-
{
-
}
-
}
-
$commandName = $commandArray[0];
-
$this->command = new Axial_Command($commandArray[0],$parameters);
-
}
-
-
function getCommand()
-
{
-
return $this->command;
-
}
-
}
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.
-
class Axial_CommandDispatcher
-
{
-
var $command;
-
function Axial_CommandDispatcher($command)
-
{
-
$this->command = $command;
-
}
-
-
function Dispatch()
-
{
-
switch ($this->command->getCommandName())
-
{
-
case 'commandOne' :
-
include('commandone.php');
-
break;
-
case 'commandTwo' :
-
include('commandtwo.php');
-
break;
-
case ":
-
include('root.php');
-
break;
-
default:
-
include('default.php');
-
break;
-
}
-
}
-
}
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.
-
include('axial.command.php');
-
include('axial.urlinterpreter.php');
-
include('axial.commanddispatcher.php');
-
$urlInterpreter = new Axial_UrlInterpreter();
-
$command = $urlInterpreter->getCommand();
-
$commandDispatcher = new Axial_CommandDispatcher($command);
-
$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
12 Responses to “Url Routing with PHP – Part Two”
Leave a Reply
replace
$this->command = new Axial_Command($commandArray[0],$parameters);
to
$this->command = new Axial_Command($commandName ,$parameters);
Sure, either way works, It is quicker to leave out the array access and perhaps the clearer style, thanks for the pointer.
I use $_SERVER['PATH_INFO']. This way I only get what is past the script path.
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.
I dont understand why is a url router?
Here an example of an url router:
$listRoutes = array(
"home" => "",
"articleHome" => "articles",
"news" => "articles/news",
"category" => "articles/",
"article" => "articles//article-.html"
);
foreach ($listRoutes AS $name => $route)
{
if (strpos($route,'<') === false)
{
echo "Static $name: ".(match_static_route($url,$route) ? 'Yes' : 'No');
}
else
{
echo "Dynamic $name: ".(count($r = match_dynamic_route2($url,$route)) != 0 ? 'Yes':'No')." — ";
print_r($r);
}
}
function match_static_route($url,$route)
{
return $url == $route;
}
function match_dynamic_route2($url,$route)
{
$result = array();
$route = str_replace("/","\/",$route);
$route = str_replace("<","(?P",">[^\/]*)",$route);
if (preg_match("/$route$/",$url,$matches) > 0)
{
foreach ($matches AS $key=>$value)
{
if (!is_numeric($key))
{
$result[$key] = $value;
}
}
}
return $result;
}
You can exploit the parameters on $r.
Please can you Tom from the previous comment or someone else explain to me the point?
What does that mean "you can exploit". Also the introducing sentence is not quite clear for me, I am not english.
But I see in the code some interesting point, so I'd like to understand the whole thing
Thank You
Carlo
I don't really like the whole thing with cases there, I'd say it's quite static and should be worked on to be more dynamic, I will work on it and see if I find any neat solution
There is a bug on that script.
we can see it on the example. while testing the link with two parameters, the css style disappear.
how can we fix that?
i mean in the example that we download from the link
While using the url router,
in the functions that I am using instead of variables I get
AC_RunActiveContent.js
Scripts
robots.txt, loaded into the urls – array
and the the actual url (for example – events, ot contacts)
Also I think it is reloading the page every time. with these values into the urls – array
Have anyone idea why this is happening.
Regards
Vulo
i cant get the code to work arghhhh!
Great Article.
//
// Shorter way of parsing the path.
//
array_diff (
explode('/', $_SERVER['REQUEST_URI']),
explode('/', $_SERVER['SCRIPT_NAME'])
);