nette/nette — pull request #638 by juzna (2012-05-02 21:17:37+00:00)
Title: DI Container: Support for @inject

As we discussed on last #posobota, it may be useful to declare class dependencies also by `@inject` annotation.

### TL;DR

Standardized way to declare which setter/property injectors are required by your class + *Dependency Injection Container* enhancement.
See [examples](https://gist.github.com/2423666).

### Motivation

*Dependency Injection* pattern wants each class to **declare** its **dependencies**.

*DI Container* somehow understands these *declarations* and can help us with creating objects and managing dependencies, so that we don't have to do all the boring work manually. At the moment, *DIC* understands two types of dependency declarations:

- *constructor arguments* - always automatically autowired;
- *arguments of explicitly stated methods* - we have to *externally* declare which methods (usually in config.neon) and DIC can autowire their arguments.

The former is commonly known as *constructor injection* and **enforces** the dependencies, i.e. you cannot create an instance without passing all dependencies. The latter is *setter injection* and is not so strict, i.e. it allows you to create possibly "faulty" objects (which doesn't mean it's useless; because not all the dependencies may be needed every time).

When we use *setter injection*, we **should** somehow **declare** that these setters should be invoked for proper function of newly created object. We can either write a comment above the class saying "dont forget to inject EntityManager by calling setEntityManager", or we can just write `@inject` annotation above the `setEntityManager(EntityManager $em)` method. The latter says the same by different words and it's easily readable by humans and computers as well. Therefore it's a better way of declaring your dependencies (than a plain text comment).

If we agree on this way of declaring dependencies, we can ask the *DIC* to work a little bit harder. When creating a new *service* or *object*, it will look for `@inject` annotations above methods and properties as well, in addition to looking at *constructor* definition and explicitly stated *setters*.

It should be stated, that *DIC* will inject only into *public* methods or properties, so that the *DIC* can be completely omitted and all the objects created manually (it wouldn't be possible to set private/protected members).

### Usage

See the [examples](https://gist.github.com/2423666). *DIC* will automatically wire all the dependencies declared by `@inject` annotation, for all the *services*/*objects* it creates.

In case you create an object manually (e.g. `$frm = new Form;`) and want DIC to help you with filling it, use `$container->inject($frm);`.

### The ugly but useful part

Though it goes against DI principles, it may be useful to *inject* also into *private*/*protected* members of a class, especially during rapid development. Therefore I added an option `Container::$allowNonPublicInjection` which allows such hack. Though it's ugly, I like using this hack.