As the ServiceLocatorAwareInterface will likely be removed from the AbstractController in ZF3, dependencies should instead be passed via the constructor or via setter methods.
With this in mind, consider the use case of a user or site controller with actions such as register, activate account, login, logout, etc. At a minimum, this would require a UserService and 2 forms. Add a few more related actions (remote authentication, linking of accounts, etc.) and you end up with 4 or 5 forms.
Passing all these dependencies via the constructor would be messy at best, and more importantly, only 1 form is usually required per action.
Which one of the following techniques do you think is better, and why?
Create separate controllers for each action, so that each controller will only require a single form (in addition to a service). For example RegistrationController, LoginController, LinkAccountController, etc.
- You end up with lots of controllers this way.
In the factory for the controller, supply different forms based on which action is being requested.
- Construction of the controller becomes dependent on this factory, and more specifically the request environment (routing, etc.) You could construct the controller directly (for testing or whatever), but then you would need to ensure that the dependencies were available and throw exceptions if not.
Use the event manager, trigger an event in the controller when a form is required, and let an event handler supply the dependency on demand.
- This technique is described here.
- Your controller would then be dependent on an EventManager as opposed to a ServiceLocator, which is probably not much better.
Pass the FormElementManager to the controller, and request forms from it.
- No better than the SL itself most likely.
Directly construct forms inside controllers.
- How does this affect testibility?
- The same question would then apply to handling a controller with multiple services (instead of forms).
Other?
See also:
First, ServiceLocator won't be removed. Maybe just the ServiceLocatorAwareInterface.
As you said, passing the FormElementManager is a solution and it's indeed better than passing the service locator. I'm personally using more and more plugin managers and they are a nice way to solving that kind of problem. A plugin manager is different that a service locator because it allows to retrieve only ONE type of objects (forms, hydrators, input filters...). Of course, as the parent service locator is injected into plugin managers, some people will do the trick of retrieving the service locator from plugin manager (taht's why I'd like to remove in ZF3 the service locator in plugin managers, and instead having a specific factory where the parent locator is passed for injections, although it would complicate a bit the factory interface :/...).
This, with splitting controllers into smaller controllers, should make your code cleaner.
By the way, you are talking about authentication, but imo if you correctly inject an authentication service (or inject the authentication service into a user service or something like that), it reduces significantly the dependencies into the controller.
You need to think about the problem you're trying to solve as a domain. In the User domain, there are many forms. So, aggregate them into a repository. The form repository would be passed into the user service, along with other repos like an entity repository. Then the User service would be passed into the controller.
// UserService
public function getForm($name, $id = null)
{
$form = $this->formRepository->find($name);
if ($id !== null) {
$entity = $this->entityRepository->find($id);
$form->bind($entity);
}
return $form;
}
来源:https://stackoverflow.com/questions/19478603/dependency-management-in-zend-framework-2-mvc-applications