Dependency management in Zend Framework 2 MVC applications
Asked Answered
A

2

4

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?

  1. 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.
  2. 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.
  3. 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.
  4. Pass the FormElementManager to the controller, and request forms from it.

    • No better than the SL itself most likely.
  5. 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).
  6. Other?

See also:

Aldine answered 20/10, 2013 at 14:33 Comment(1)
I won't post this as an answer, but: 1) I don't see many controllers as a problem. 2) would never do this. A factory is scrap logic. Don't try to overhaul it. 3) maaaaagic - try to debug that! 4) the form element manager IS a ServiceLocator 5) no, we moved away from thatElstan
P
0

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.

Pocket answered 20/10, 2013 at 17:48 Comment(1)
Sorry, I meant the ServiceLocatorAwareInterface, I've updated the question. WRT authentication, I have two adapters, one for local, and one for remote authentication, so I need two services and therefore two controllers as well.Aldine
B
0

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;
}
Boris answered 20/10, 2013 at 22:35 Comment(2)
How does a form repository differ from the FormElementManager? (just by limiting which forms can be returned?) Also, what exactly is a form repository, and how does it instantiate or access forms? I haven't seen this pattern before.Aldine
@darkangel I am using this pattern as well often. A form repository is different from the form element manager as you can create your own User\Repository\FormRepository class which only instantiates the 2 or 3 forms. This provides a very specific scope for your form repository and gives the flexibility in your controller. BTW. Usually I call the "repository" a "form factory" so you'll get a User\Factory\FormFactory or something.Medieval

© 2022 - 2024 — McMap. All rights reserved.