Slim wildcard routes improved
This is a follow up to Slim wildcard routes via route middleware... you may want to go and read that first.
The method used in the previous post was sufficient to get the job done but was not ideal as the resulting array was stored in the slim environment
. At the time it was the "best" spot to store it without introducing a new dependency. Here is what I said in the previous post:
... this could be better if the route middleware was able to inject the new array back into the parameters rather than storing it into the environment. For now this is an easy solution to implement and is reuseable until the feature is added to the framework itself.
With the release of Slim 1.6.4 the feature to let the Slim_Route inject custom parameter values
was added. We can use this to improve our wildcard routes example with a few simple changes. Instead of using the environment
, our array will be injected back into the parameters being passed directly to the route. As a reminder the example URIs we want to parse into the array are:
http://hostname/api/getitems/seafood/fruit/meat
http://hostname/api/getitems/seafood
http://hostname/api/getitems/seafood/fruit/apples/bananas/chocolate
Here is the diff with the changes to our route middleware:
-$parseWildcardToArray = function ($param_name) use ($app) {
- return function ($req, $res, $route) use ($param_name, $app) {
+$parseWildcardToArray = function ($param_name) {
+ return function ($req, $res, $route) use ($param_name) {
- $env = $app->environment();
- $params = $route->getParams();
-
- $env[$param_name.'_array'] = array();
-
- //Is there a useful url parameter?
- if (!isset($params[$param_name]))
- {
- return;
- }
-
- $val = $params[$param_name];
+ $val = $route->getParam($param_name);
//Handle /api/getitems/seafood//fruit////meat
if (strpos($val, '//') !== false)
{
$val = preg_replace("#//+#", "/", $val);
}
//Remove the last slash
if (substr($val, -1) === '/')
{
$val = substr($val, 0, strlen($val) - 1);
}
//explode or create array depending if there are 1 or many parameters
if (strpos($val, '/') !== false)
{
$values = explode('/', $val);
}
else
{
$values = array($val);
}
- $env[$param_name.'_array'] = $values;
+ $route->setParam($param_name, $values);
};
};
First we removed the use
of $app
for the closure since we don't need it anymore. Next we simplified the code as we were able to remove lines 6-17. We no longer need to access the environment. The check for a value can be removed since we are only getting the specific value and our route condition /.+/
ensures there is something in there. Previously we were getting all route parameters as an associative array so we had a check to ensure the key existed and was set. All of that is replaced by a simple getParam()
call. The final difference is how the modification takes place. We now write it back into the route parameters directly rather than to the environment.
Here is our new route middleware:
$parseWildcardToArray = function ($param_name) {
return function ($req, $res, $route) use ($param_name) {
$val = $route->getParam($param_name);
//Handle /api/getitems/seafood//fruit////meat
if (strpos($val, '//') !== false)
{
$val = preg_replace("#//+#", "/", $val);
}
//Remove the last slash
if (substr($val, -1) === '/')
{
$val = substr($val, 0, strlen($val) - 1);
}
//explode or create array depending if there are 1 or many parameters
if (strpos($val, '/') !== false)
{
$values = explode('/', $val);
}
else
{
$values = array($val);
}
$route->setParam($param_name, $values);
};
};
You can see that our route is a little easier as the parsed array is now just in the parameter.
$app->get('/api/getitems/:items', $parseWildcardToArray('items'), function ($items) {
var_dump($items);
})->conditions(array('items' => '.+'));
As before, this just prints the following arrays for the three urls from above:
array(3) { [0]=> string(7) "seafood" [1]=> string(5) "fruit" [2]=> string(4) "meat" }
array(1) { [0]=> string(7) "seafood" }
array(5) { [0]=> string(7) "seafood" [1]=> string(5) "fruit" [2]=> string(6) "apples" [3]=> string(7) "bananas" [4]=> string(9) "chocolate" }
Read the last follow up to see it integrated into Slim in conjuction with the 1.6.5 release... Slim wildcard routes : Last but not least