nette/nette — pull request #672 by jakes (2012-06-02 12:53:43+00:00)
Title: First step to addons support

**This is a minimalistic first step to add some addons support to Nette, no BC breaks.**

It solves the definition, naming and installation of addons and we can have access to it's directory (for resources, etc.).

Next steps should be:
- routing to addon's Presenters, loading addon's templates
- some 'sugar' like addons.neon and some automatic behaviour following suggested conventions

How does it work now?
=====
Every addon is a subclass of `Nette\Addons\Addon`. It has some methods to resolve it's name and path. The compile() function is used to register compiler extensions. The basic approach is similar to Kdyby, but simplified a lot. I think the first step can be really basic and then we can improve it.

1. Installation (in bootstrap.php)
-----
$configurator->registerAddons(array(
new TestAddonPack\ConsoleAddon\ConsoleAddon
));

Addon can be also named by user:

$configurator->registerAddons(array(
'myConsole' => new TestAddonPack\ConsoleAddon\ConsoleAddon
));

If addon is not named by user, it can have a default name given by it's creator. If there is no one, the addon will take the name from the class name (ConsoleAddon will be "console").

2. Compiler extensions
-----
Compiler extension can be registered in the addon class in a function compile(). The suggested convention is using the addon name as a prefix:

public function compile(Configurator $configurator, Compiler $compiler)
{
$compiler->addExtension($this->name, new ConsoleExtension);
$compiler->addExtension("$this->name.other", new AnyOtherExtension);
}

All the service definitions should be named with $this->prefix().

3. Things to discuss, problems
-----
1. In the current implementation every addon is instantiated before container is built just to resolve it's name and register compiler extensions. Then every addon is registered as a service and will be instantiated when it's used. It might seem a bit weird but I don't think there's any performance problem. As far as I know the same approach is used in Kdyby Framework. (A solution could be using some static elements in the Addon class, but it seems to me even ugiler.)
2. If we use recommended naming of compiler extension and it's services, the user can actually change the name (prefix) of all the addon services. This is good, but there's a problem how to refer to another addon's services. (The $containerBuilder->getByType() doesn't work in a compile phase, because the class list is not yet prepared by $containerBuilder->prepareClassList()). Solutions?
3. AddonManager in this first impementation is just a simple container. It seems that we don't even need it, if every addon is registered also as a service "addons.addonName". But maybe later the AddonManager might do much more work than this, what do you think?