Alternative way to inject providers in a Silex application


I normally use Silex when I need to build one Backend. It’s simple and straightforward to build one API endpoint using this micro framework. But there’s something that I don’t like it: The “array access” way to access to the dependency injection container. I need to remember what kind of object provides my service provider and also my IDE doesn’t help me with autocompletion. OK I can use PHPDoc comments or even create one class that inherits from Silex\Application and use Traits. Normally I’m lazy to do it. Because of that I’ve create this simple service provider to help me to do what I’m looking for. Let me explain it a little bit.

Imagine that I’ve got this class

namespace Foo

class Math
{
    public function sum($i, $j)
    {
        return $i+$j;
    }
}

And I want to add this service to my DIC

$app['math'] = $app->share(function () {
    return new Math();
});

Now I can use my service within my Silex application

$app->get("/", function () use ($app) {
    return $app['math']->sum(1, 2);
});

But I want to use my service in the same way that I’m using my services within my AngularJS applications. I what to do something like that:

use Foo\Math;
...
$app->get("/", function (Math $math) {
    return $math->sum(1, 2);
});

And that’s exactly what my service provider does. I only need to append my provider to my Application and tell to the provider what’s the relationship between Pimple’s services keys and its provided Instance

$app->register(new InjectorServiceProvider([
    'Foo\Math' => 'math',
]));

This is one example

composer require gonzalo123/injector
include __DIR__ . "/../vendor/autoload.php";

use Silex\Application;
use Injector\InjectorServiceProvider;
use Foo\Math;

$app            = new Application(['debug' => true]);

$app->register(new InjectorServiceProvider([
    'Foo\Math' => 'math',
]));

$app['math'] = function () {
    return new Math();
};

$app->get("/", function (Math $math) {
    return $math->sum(1, 2);
});

$app->run();

And this is the Service Provider

namespace Injector;
use Silex\Application;
use Silex\ServiceProviderInterface;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class InjectorServiceProvider implements ServiceProviderInterface
{
    private $injectables;
    public function __construct($injectables = [])
    {
        $this->injectables = $injectables;
    }
    public function appendInjectables($providedClass, $key)
    {
        $this->injectables[$providedClass] = $key;
    }
    public function register(Application $app)
    {
        $app->on(KernelEvents::CONTROLLER, function (FilterControllerEvent $event) use ($app) {
            $reflectionFunction = new \ReflectionFunction($event->getController());
            $parameters         = $reflectionFunction->getParameters();
            foreach ($parameters as $param) {
                $class = $param->getClass();
                if ($class && array_key_exists($class->name, $this->injectables)) {
                    $event->getRequest()->attributes->set($param->name, $app[$this->injectables[$class->name]]);
                }
            }
        });
    }
    public function boot(Application $app)
    {
    }
}

As we can see I’m listening to CONTROLLER event from event dispatcher and I inject the dependency form container to requests attributes.

Full code in my github account

Advertisements

About Gonzalo Ayuso

Web Architect. PHP, Python, Node, Angular, ionic, PostgreSQL, Linux, ... Always learning.

Posted on October 19, 2015, in Dependency Injection, php, silex, Technology and tagged , , , , , . Bookmark the permalink. 11 Comments.

  1. Cool! I always bothered by fact that a wonderful IDE like PhpStorm can’t help me with I use, for example, $app[‘db’]. Now I can get that. Thanks a lot.

  2. Nice article. Have you seen this one ? this https://github.com/saxulum/saxulum-route-controller-provider

    They use doctrine annotations to configure controller dependencies. I’ve been using it, it’s really cool =)

    • Time ago I was a big fan of annotations. Nowadays I’m not. I perceive them as “magic”. As far as PHP don’t compile them I try to avoid them. OK PHPStorm and other IDEs can “compile” them, but it’s not the same than Java or even Python. Because of that I prefer to “cast” my objects in one way or another. And this post is one example.

  3. Great idea, really appreciated this post!
    I generally used to adopt php documentor type hinting (reassigning the $c[‘something’] to a variable) whenever I wanted to have a decent auto-completion with PhpStorm. It is kind of a trick and it requires a lot of keystrokes. This solution is way better, thanks for sharing it šŸ˜‰

  4. Hi! Maybe you’d be interested by the PHP-DI/Silex bridge, it does something similar: http://php-di.org/doc/frameworks/silex.html

  1. Pingback: Formas alternativas para injetar providers em uma aplicaĆ§Ć£o Silex -

  2. Pingback: Formas alternativas para injetar providers em uma aplicaĆ§Ć£o Silex - Caderno de estudo TI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: