Environment: Support methods in param matching

Some of you probably remember the fine Environment Class developed by Rafael Bandeira. I still use and love it for handling dev, staging and production environments. And it’s super awesome that you may create a AppEnvironment class to tweak the config and param mapping. However, i found one thing missing and that’s support for arrays when matching the mapped params.
For example: You have one “development” environment but you have multiple domains pointing to it and the app needs to behave differently based on that (language preset based on domain extension, vanity urls for user profiles, .. that kind of stuff).

There are of course alot of other reasons why that’s a good a idea. In general to avoid duplicate code and conflicts. To get around all that i needed support for arrays.
One approach to support arrays would be to just add it to the _match($param, $value) method in the Environment class, but it may not have been appropiate in all occassions. So i just followed Rafael’s lead and simply added support for instance methods. Since we may have our own class for environment config/param mapping (just create app_environment.php in /config/), it’s a good place to also add some helper methods.
That was the previous code (around line 90).
if (function_exists($param)) {
$match = call_user_func($param, $value);
} else {
$match = (env($param) === $value);
}
if (!$match) {
return false;
}

I just added another “if-condition” and used getInstance to get the object.
$instance = self::getInstance();
if (method_exists($instance, low($param))) {
$match = call_user_method(low($param), $instance, $value);
} elseif (function_exists($param)) {
$match = call_user_func($param, $value);
} else {
// ... as above

Note the “low($param)“. I’ve set the value of $param to lower-case because param would be HTTP_HOST which doesn’t makes up for a good method name. Maybe could have used Inflector to make it camelcase just to enforce conventions here – but that would be overkill. ;-)
Okay.. so what happens here and how can we use that?

  1. The getInstance method returns the AppEnvironment object, if present. So it’s imperative to have it, because we don’t want to mess with the original class.
  2. method_exists looks in AppEnvironment for a lower-case method name of whatever is in $param. In our case this results to “http_host”.
  3. If found, it calls the method on the $instance and returns the result. The result should be boolean.

I’ve edited my app_environment.php and added the following method:

/**
* Support Arrays in HTTP_HOST param matching
*
* @param mixed $value string or array of hostnames
* @return boolean
*/
public function http_host($value) {
if (is_array($value)) {
foreach ($value as $host) {
if (env('HTTP_HOST') == $host) {
return true;
}
}
} else {
if (env('HTTP_HOST') == $value) {
return true;
}
}
return false;
}

Should be pretty self explaining. Default to false. If $value is an array, walk through it and return true on the first match. If it’s not an array just check if $value matches the current HTTP_HOST.
With that in place i can now tweak my ‘server’ config in the environment setup.
App::import('Vendor', 'Environment');

Environment::configure('development',
array(
'server' => array('localhost', 'testapp-local.com') // there we go!
),
array(
'debug' => Configure::read('Env.development.debug'),
'security' => Configure::read('Env.development.security')
)
);
Environment::start();

That’s it. From now on we have the “development” environment running if the current HTTP_HOST is either “localhost” or “testapp-local.com”.
Edit: Oh.. btw. This is not just about http_host. You can of course add helper methods for any other param.
http://j.mp/bXHezg)">