slimphp / Slim

Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs.
http://slimframework.com
MIT License
11.96k stars 1.95k forks source link

Make Slim a DI container with Pimple #398

Closed ziadoz closed 11 years ago

ziadoz commented 12 years ago

It would really cool as a future enhancement to make the main Slim class a dependency injection container using Pimple (https://github.com/fabpot/Pimple). The Silex micro framework does this and it makes storing and using your application dependencies really simple. It could also be useful for accessing the request, response, environment and log objects too:

$app = new Slim;

$app['config'] = Yaml::parse(__DIR__ . '/config.yml');

$app['pdo'] = $app->share(function($app) {
    $config = $app['config'];
    $pdo = new PDO($config['dsn'], $config['user'], $config['pass']);
});

$app->get('/', function() use ($app) {
    $app['response']['X-Powered-By'] = 'Awesome Sauce';

    $post = $app['request']->post();
    $app['pdo']->query('...');

    $app['log']->debug('foobar');
});
codeguy commented 12 years ago

This is definitely something I will consider. Up to this point, Slim has supported PHP 5.2 and newer so Pimple was not an option. Slim 2.0 will move to 5.3 and newer which opens up all sorts of new possibilities. Leaving open and marking for 2.0 milestone.

ziadoz commented 12 years ago

Thanks for considering the feature, I think it would be really nice for Slim to have.

Another thing that might be useful is binding any route closure objects to the Slim application object (PHP 5.4 only) using the Closure::bindTo() method:

$app = new Slim;

$app->get('/', function() {
    // No need to write: use ($app)
    print_r($this->request());
});

No idea if you'd want to include this in Slim now (using a PHP version check) or later in the 2.0 milestone, but I thought I'd just throw it out there anyway.

chelmertz commented 12 years ago

I use Pimple and Slim now, it's not that many extra letters to write + the dependency is optional.

$app = new Slim;
$di = new Pimple;

$app->get('/', function() use ($app, $di) { .. });

I really like use of Closure::bindTo() but I think DI can be mimicked in 20 lines or less and included in Slim without that extra dependency of Pimple.

ziadoz commented 12 years ago

Yes, mimicking Pimple probably makes sense since there isn't much to it really.

StJudeWasHere commented 12 years ago

I just created a pull requested to experiment with this idea.

pyrsmk commented 12 years ago

Really interesting, hope it will come soon ;)

Until today I was using a similar framework of my own but with Chernozem instead of Pimple. It provides more features which I needed for better flexibility. Then, it's not as lightweight as Pimple but still keeps a tiny footprint, I think.

gcaplan commented 11 years ago

I've been evaluating Slim and Silex - preferred Slim but was on the edge of going with Silex to get the testability of the IoC. Then I needed to dig into the Silex code and realised it was 13 megs of bloat - not exactly micro. Quickly realised that it's pretty trivial to get 98% of the same benefits in Slim, by simply passing the $app into the closures along with a Pimple IoC. Tried to embed the IoC into $app but unless I'm missing something it's not doable. Here's a sketch of how it's done - hardly rocket science and I'm sure many of you are doing it already:


$app = new \Slim\Slim;
$IoC = new \Pimple\Lib;

$IoC = new \Pimple\Lib;
$IoC['test_var'] = 'foohoo';

// Pimple offers closures access to the
// container - nice feature.

$IoC['test_service'] = function ($c) {
    return $c['test_var'];
};

$IoC['DB'] = $IoC->share(function () {

    $config = new \Doctrine\DBAL\Configuration();
    $connectionParams = array(
    'dbname' => 'xxx_dev',
    'user' => 'root',
    'password' => 'moohoo',
    'host' => 'localhost',
    'driver' => 'pdo_mysql',
    );

    $conn = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $config);
    return $conn;
});

$app->get('/', function() use($app, $IoC) {

    $sql = "SELECT * FROM customers LIMIT 50";
    $conn = $IoC['DB'];
    $stmt = $conn->query($sql);

    while ($row = $stmt->fetch()) {

        echo $row['bill_to_name'];
    }
});

This works fine and offers me the opportunity to mock any service I stick in the IoC. In some ways it seems to me that this is more of a pattern than an engineering decision. FabPot's approach offers a little syntactical sugar, in that you only have to pass in $app becuase Pimple is imbedded into it. But on the other hand when I played with Silex I found that his approach added a certain amount of complexity and conceptual overhead when initialising objects which I'm not convinced offers much payback. This would be a disruptive upgrade - I guess my question is, what can the Silex approach offer that the simple (slim!) approach above is missing?

colonelchlorine commented 11 years ago

gcaplan +1 for using slim, doctrine, and pimple. swiftmailer for email and we're clones

thelinuxlich commented 11 years ago

+1

codeguy commented 11 years ago

So this is happening. I've got a working prototype on a local branch. Super excited about this. More info coming soon.

codeguy commented 11 years ago

Working prototype available in the "feature-ioc" branch. Feel free to have a look and submit improvements. All unit tests pass and it should be backwards compatible.

StJudeWasHere commented 11 years ago

Thanks a lot for this feature, It was one of the only pieces I was missing in Slim.

I was wondering if it would make sense to use \Slim\Helper\Set as a container instead of having a new class, I made a pull request in case you want to give it a try. #535

codeguy commented 11 years ago

Pulled in your changes. This feature will be merged into the develop branch soon for the next upcoming point release. Closing this out.