Pragmatism in the real world

Dependency injection in Slim framework 2

Slim framework comes with a Dependency Injection container called Set.

The basics

The DIC is accessed via the container property of $app.

To set, you use the set() method:

$app->container->set('foobar', function() { return new Foo\Bar(); } );

If you need a given resource to be shared, then use the singleton method:

$app->container->singleton('foobar', function() { return new Foo\Bar(); } );

And then to retrieve from the container, there are multiple ways to do it:

$fooBar = $app->container->get('foobar');
$fooBar = $app->container['foobar'];
$fooBar = $app->foobar;

The shortcut version ($app->foobar) only works if the key is a valid PHP variable name.

Dependent dependencies

The callback is passed the container instance, you can also retrieve dependencies and use them to configure the object that you are instantiating as shown in this example:

$app = new \Slim\Slim(
    [
        'db.dsn' => 'mysql:host=localhost;dbname=something',
        'db.username' => 'user',
        'db.password' => 'pass',
    ]
);

// Add dependencies
$app->container->singleton('PDO', function ($container) {
    $settings = $container['settings'];
    return new PDO($settings['db.dsn'], $settings['db.username'], $settings['db.password']);
});

$app->container->singleton('UserMapper', function ($container) {
    $pdo = $container['PDO'];
    return new User\UserMapper($pdo);
});

// Routes
$app->get('/', function ($name) use ($app) {
    // (Using the DIC as a service locator here...)
    $userMapper = $app->container['UserMapper'];
    // etc...
});

In this example the '/' route uses an instance of User\Mapper, which requires a PDO object. We therefore add two resources to the container: one for PDO and one for the UserMapper.

Slim uses its own DIC

Note that Slim uses it’s own DIC for all its dependencies which means that you can override them. It even uses it for the configuration settings that you pass in to the Slim constructor which is accessible via $app->container['settings'] (or $app->settings).

The classic example is that Slim creates its own instance of Slim\Log and attaches it to the log key in the container. If you wanted to use monolog instead, you can simply do:

$app->container->singleton('log', function () {
    $log = new \Monolog\Logger();
    $log->pushHandler(new \Monolog\Handler\StreamHandler('path/to/log.txt'));
    return $log;
});

We have now replaced Slim’s own log system with monolog.

Fin

I know that it’s tempting to grab $app directly, but Slim makes is nearly as easy to configure your objects using dependency injection which will make your life much easier in the long-run!