piwik/piwik — pull request #6453 by mnapoli (2014-10-16 05:00:07+00:00)
Title: Refactored the EventDispatcher into a component based on interfaces and dependency injection

This is an attempt at refactoring the `EventDispatcher` class towards dependency injection.

Since we want dependency injection, we need to get rid of singletons. The `EventDispatcher` is one.

For this refactoring, I've started by simply creating a new `Piwik\EventDispatcher\EventDispatcher` class that is not a singleton and moving all the logic inside.
Then the old `Piwik\EventDispatcher` is just a *singleton proxy* (i.e. a singleton whose `getInstance()` returns an instance of the new class).

I also took the opportunity for a refactoring:

- I added `EventDispatcherInterface` so that later, when injecting the dispatcher, we can type-hint against interfaces and thus easily replace the implementation (e.g. if we want to use a 3rd party library instead, of even for injecting mocks in tests)

- I tried to have the EventDispatcher component completely separated from the rest of the Piwik codebase and that wasn't too hard. The only coupling is to the plugins: plugins declare events they want to subscribe too.

This reminded me a lot of how Symfony's event dispatcher works, so I went a similar way.
The event dispatcher was handling **plugins** and **observers** (callbacks), now it handles **subscribers** and **observers**.

A **subscriber** is a class that declares which events it wants to subscribe to. And hey, that's just exactly what plugins do ;) cool!

```php
interface SubscriberInterface
{
public function getListHooksRegistered();
}
// ...
class Plugin implements SubscriberInterface
{
public function getListHooksRegistered()
{
return array();
}
}
```

So now the base Plugin class implements that interface, and plugins are already compatibles. The only thing I wish we could do is rename that method to something more consistent, like `getSubscribedEvents()` but that would totally break BC so let's do that in 3.0 or something. We could also write adapters but is that worth it?

So now that plugins implement that interface, we want the event dispatcher to know about them without directly using the PluginManager.

That's where there's a new concept of **event subscribers provider** (i.e. it provides event subscribers). Yes the name is long :/, maybe we can find better. So there's one implementation of `SubscriberProviderInterface` which is in the `Piwik\Plugin` namespace and which uses the plugin manager to find all the plugins. All that is easy code, it just takes a bit of time to visualize how it all fits together.

**TL/DR:** It works like before, except now there's no singleton, the event dispatcher is totally decoupled from Piwik and there's a bit more interfaces. Maybe I've gone too far and it's too abstract, let me know honestly what you think.

We could also move those classes to a separate component/repository, but in that case it would be better to rename some methods and change their signatures and that would break BC.

PS: why not using Symfony's dispatcher? Because we would need to write one object per event, which is not cool.

TODO:

- [ ] write unit tests (which didn't exist previously because of the singleton)