codeguy/Slim — pull request #436 by mnlg (2012-09-27 09:41:44+00:00)
Title: Di container proposal

There're quite a few changes in this pull request but it should be mostly compatible with the develop branch.

I implemented a DI container in it's own class which Slim and Enviroment extend from. The way it works is not unlike Pimple but I included only the methods I needed in Slim.

// share the Request object
$this['request'] = $this->share(function($c) {
return new \Slim\Http\Request($c['environment']);
});

// return a new route object
$this['route'] = function($c) {
return new \Slim\Route();
};

// store parameters too
$this['log.enabled'] = true;

The Environment, Request, Response, Router and Log objects are shared in the slim application and can be accessed using the container's ArrayAccess like $app['request']. I didn't remove the previous methods for compatibility so they can also be accessed like $app->getLog().

There'r also changes in the HTTP cache and Cookies methods, now they are in their own classes and loaded in to the Slim DI container using middleware. Both classes are loaded in the Slim constructor and I also kept the old methods for compatibility, but ideally they should be removed and let the developer decide if he wants to use HTTP cache or Cookies in his app.

Then I merged #432 which simplifies the call method and modified the way the Routes work. This moves the Route dispatch method from the Router to the Route class instead, then it uses the DI container to create a Route factory in the Slim class. The cool thing about it is we can now change the Route class on the fly.

// create a new Route class
namespace Slim;

class AfterRoute extends \Slim\Route
{
protected $afterCallable;

public function dispatch()
{
foreach ($this->getMiddleware() as $mw) {
if (is_callable($mw)) {
call_user_func_array($mw, array($this));
}
}

if (is_callable($this->getCallable())) {
call_user_func_array($this->getCallable(), array_values($this->getParams()));
call_user_func($this->afterCallable); // call the after callable
return true;
}

return false;
}

// add an after callable
public function after($callable) {
$this->afterCallable = $callable;
return $this;
}
}

// Using the default Route
$app->get('/', function() { echo 'foo';});

// Using our new Route class
$app->config('route.class', '\Slim\AfterRoute');
$app->get('/after', function() { echo 'foo';})->after(function() {echo ' bar';});

I think we should provide some interfaces or abstract classes here but it seems like a cool feature.