powered by Slim Framework
Follow @NesbittBrian rss

Slim wildcard routes improved

Jul 3, 2012

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

Multilingual site using Slim  Home Slim wildcard routes : Last but not least  
blog comments powered by Disqus