Developed with love by KnpLabs Hire us for your project!
35

LiipContainerWrapperBundle

by liip

Because mommy taught you to not screw DI by just injecting everything.

ContainerWrapperBundle

Because mommy taught you to not screw DI by just injecting everything.

This bundle is for people who do not like container injection but are forced to use it.
It provides a configurable proxy container that exposes only parts of the actual container,
or has certain services re-defined. Instead of injecting the full container you can then
inject this wrapper instead, which gives you back fine-grained control over the dependencies
of that component.

1. It provides an abstract ``liip_container_wrapper.service`` service to extend from.

2. It provides a way to easy set default service and parameters to map

3. It can replace itself with an alias to ``service_container`` via a config
   option as long as no service/parameter is mapped to a different id/name

Installation

1. Install with Composer

    `php composer.phar require liip/container-wrapper-bundle`

2. Add this bundle to your application's kernel:

    // application/ApplicationKernel.php
    public function registerBundles()
    {
      return array(
          // ...
          new Liip\ContainerWrapperBundle\LiipContainerWrapperBundle(),
          // ...
      );
    }

Configuration

Default services and parameters maybe configured inside the application configuration.
Setting disable_optimization to true will remove the ContainerWrapper service in favor of an
alias to service_container in all cases where no mapping is used:

# app/config.yml
liip_container_wrapper:
    services:
        templating: acme_hello.templating
    parameters:
        kernel.debug: true
    disable_optimization: %kernel.debug%

Both services and parameters are configured as key value pairs. The key is the id/name
that is reachable from this specific ContainerWrapper instance. The value may either be
true or an id/name of a different service or parameter. In case of a non true value
the id/name will be mapped to this other id/name.

Take the above example:

// will return an instance of the 'acme_hello.templating' service
$container->get('templating');

// will return an the value of the 'kernel.debug' parameter
$container->getParameter('kernel.debug');

Note that because templating is mapped to a different service id, setting
disable_optimization to false would have no effect, since a normal
Container instance would not be able to support setting different alias's
for templating.

Example use

The following YAML configuration extends the liip_container_wrapper.service abstract
service to define an acme_hello.container service that can be injected in place of
a Container instance that limits access to the services and parameters defined
in the bundle configuration as well as the ones defined in this configuration:

acme_hello.foo.controller:
    class: Acme\HelloBundle\Controller\FooController
    calls:
        - ['setContainer', [ @acme_hello.container ] ]

acme_hello.container:
    parent: liip_container_wrapper.service
    arguments:
        index_0:
            some_service: true

The story of saved kittens

Why oh why?

Yes, why oh why would someone bother to setup a nice dependency injection container
and then waste all its goodness by just injecting the entire container, thereby
effectively making their code dependent on essentially everything configured in the
DI container? I am sure god kills more than a few kittens whenever ..

Aside from the kittens, injecting the container also prevents granular adjustments
to your dependencies. Aka controller Blabla needs a different templating service
injected than controller DingDing, but how do you do that if your code uses
$this->container->get('templating') in both? Praying to god is not the answer,
he is busy killing kittens anyway.

And those insane enough to bother with unit testing will also quickly realize that
its even less fun to have to wrap everything they want to inject into a container
mock object.

Oh and no IDE auto completion support without jumping through hoops is also a major
let down of injecting the container or is there an IDE yet that can parse your DIC
to figure out wtf $this->container->get('i_hate_kittens') returns?

But ok, there are many crappy answers like lazyness and such to still inject the DIC,
but there are three semi acceptable reasons:

1) someone else wrote useful code, but thought it was a great idea to require injecting
the entire DIC

2) there are a fair bit of optional dependencies which do not really solve themselves
by splitting up the service (actually 2) is often a reason why 1) happens even for
code written by good people).

3) you need to inject a service before the service actually can exist, like the
request service in Symfony2

But wait there is hope!

In those cases you now have a way to prevent little kittens from being slain!

Instead you can use the ContainerWrapper to explicitly configure your dependencies
again and to map hardcoded service id's to regain the flexibility that was forsaking
by not injecting the dependencies explicitly.

But parameters!

Yeah, parameters are also handled by the wrapper, though they don't really benefit
from the lazy loading argument all that much, but I guess once a developer has gone
the path of darkness, he might just keep using the DI container instead of explicitly
injecting the parameters, so yeah, probably parameter support should be added too. Evil
is just so resourceful at being evil.

Copyright (c) 2010-2011 Liip

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
liip_contrainer_wrapper:
services:

# Prototype
services: []
parameters:

# Prototype
parameters: []
disable_optimization: %kernel.debug%
  • Merge pull request #4 from jrobeson/patch-1
    By lsmith77, 2 years ago
  • Merge pull request #5 from jrobeson/patch-2
    By lsmith77, 2 years ago
  • update readme to use composer
    By jrobeson, 2 years ago
  • use psr-4 autoloader
    By jrobeson, 2 years ago
  • typo fix
    By lsmith77, 3 years ago
  • refactored code
    By lsmith77, 3 years ago
  • cs fixes
    By lsmith77, 3 years ago
  • cs fixes
    By lsmith77, 3 years ago
  • cs fixes
    By lsmith77, 3 years ago
  • cs fixes
    By lsmith77, 3 years ago
  • 2.3 compatibility
    By lsmith77, 4 years ago
  • also allow 2.2
    By lsmith77, 4 years ago
  • fixed phpdoc
    By lsmith77, 4 years ago
  • added missing property definition
    By lsmith77, 4 years ago
  • fixed framework/di bundle dependency
    By lsmith77, 5 years ago
  • depends on framework-bundle
    By lsmith77, 5 years ago
  • added composer.json
    By lsmith77, 5 years ago
  • Merge pull request #2 from igorw/patch-1
    By lsmith77, 5 years ago
  • Add a more sane explanation of what the bundle does to README.
    By igorw, 5 years ago
  • added LICENSE file
    By lsmith77, 5 years ago
  • updated repo url
    By lsmith77, 6 years ago
  • removed outdated comment
    By lsmith77, 6 years ago
  • enabled optimizations
    By lsmith77, 6 years ago
  • moved the ContainerWrapper into the Bundle to make installation easier
    By lsmith77, 6 years ago
  • disabled aliasing code until https://github.com/symfony/symfony/pull/532 is pulled, some general code tweaks
    By lsmith77, 6 years ago
  • expanded documentation
    By lsmith77, 6 years ago
  • fixed comments
    By lsmith77, 6 years ago
  • expanded explanations
    By lsmith77, 6 years ago
  • fixed optimization pass
    By lsmith77, 6 years ago
  • renamed remove_unmapped to disable_optimization
    By lsmith77, 6 years ago