Dependency Injection and Containers

I realized I haven’t explained dependency injection or containers on here but I reference them in places (Controllers as Service) with little regard to the reads level of understanding.

Dependency Injection itself isn’t a complex subject. Here is an example:

<?php

class A{
    protected $dependencyOne;
    public function __construct($b) {
         $this->dependencyOne = $b;
    }
}

class B{
    public function __construct(){
        echo 'hey';
    }
}

$b = new B();
$a = new A($b);

So instead of A creating B since it needs it, you pass in B. That is dependency injection. Nothing more. Nothing to be scared about.

So a container is something this was built to help this process and do a little bit more.

Using or example above here is what it looks like using Pimple\Container.

<?php
$container = new Pimple\Container();

$container['b'] = function($c){
    return new B();
}

$container['a'] = function($c){
    return new A($c['b']);
}

So that seems like a lot of work to get a simple object into another but image a more complex tree. A->B->C->D,E,F,G,H->I. That would be a lot to type every time you needed A in your project. So instead you pass the container around or pass in A into the utility, controller or any other other class that might require A and the container takes care of the rest.

Like the Controllers as Service article, you can do some more complex requires without having to do it over and over again.

Continue reading Dependency Injection and Containers

Building an MVC while Refactoring – Part 2 – Controllers as a Service

I found hints of this while working on refactoring a project into using MVC.

Framework Independent Controllers by Matthias Noback

Pimple Container with Yaml by Gonzalo

Symfony post about Controllers as a service

Controllers as a Service.

Using Symfony’s Routing and Resolvers, it seems like a simple move.

Well it was(n’t). I tried this tutorials, Messing Around with Silex Pimple, one issue I found was that the Silex is still using v1 of Pimple which now has changed to Pimple\Container, removed the ->share method and just over all matured. So I needed find a way to do this outside of Silex and using a new version of Pimple’s Container.

The second part was fairly easy since ->share is now just = function($c) since its now the default.

The first part was the issue. How do I get Symfony’s Controller Resolver to work with Pimple outside of the Symfony Framework and not in Silex.

The hunt began.

I found this file that depended on the file below it:

  • https://github.com/silexphp/Silex/blob/1.2/src/Silex/CallbackResolver.php
  • https://github.com/silexphp/Silex/blob/1.2/src/Silex/ServiceControllerResolver.php

It also depended on the symfony ControllerResolver but that was easy to add.


<?php use Symfony\Component\ClassLoader\MapClassLoader as MapClassLoader; use Symfony\Component\ClassLoader\UniversalClassLoader; use Pimple\Container; //temporary till mvc is setup use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Config\FileLocator; use Symfony\Component\Routing\Loader\YamlFileLoader; use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing; use Symfony\Component\HttpKernel; use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface; $container['callback_resolver'] = function ($c) { return new \App\Component\CallbackResolver($c); }; $container['request'] = function($c) { return Request::createFromGlobals(); }; $container['resolver'] = function($c) { return new \App\Component\HttpKernel\Controller\ServiceControllerResolver(new HttpKernel\Controller\ControllerResolver(), $c['callback_resolver']); }; $container['routes'] = function($c) { return new RouteCollection(); }; $container['routes'] = $container->extend('routes', function(RouteCollection $routes) { $loader = new YamlFileLoader(new FileLocator(APP_DIR . '/Resource/config')); $collection = $loader->load('routes.yml'); $routes->addCollection($collection); return $routes; }); $container['context'] = function($c) { return new Routing\RequestContext(); }; $container['matcher'] = function($c) { return new Routing\Matcher\UrlMatcher($c['routes'], $c['context']); }; //Controller Service $container['index_controller'] = function($c) { return new \App\Controller\IndexController($c['database']); }; $container['config'] = function($c) { return; }; $container['kernel'] = function($c) { return new \App\Kernel($c['matcher'], $c['resolver']); }; $container['context']->fromRequest($container['request']); $response = $container['kernel']->handle($container['request']); $response->send();

Modified ServiceControllerResolver File from Silex Framework

Modified CallbackResolver File From Silex Framework

There are still somethings to work out with these files so that error handling / logging is taken care of. The services will soon be loaded by a yaml file but in all it was a great fix to make the controller have dependencies and not require being built to meet the Silex/Symfony only needs.

Continue reading Building an MVC while Refactoring – Part 2 – Controllers as a Service