1

I've been looking at symfony's implementation of dependency injection, and it seems like a service locator pattern.

It appears, at first blush, that the service container is not entirely different from a global namespace, and that any of the objects located within could be requested and modified in unexpected ways by some other module. It seems like symfony has built in a way around these Action at a distance anti patterns by setting Scopes on the container, (addScope, enterScope, leaveScope), but I only see one example of addScope in CoreServiceProvider.php with a 'request' namespace.

Should module developers be encouraged to scope their interaction with the container if they plan on modifying services?

2
  • Try to clearly define your question and not pack everything into one. ... the text is just sort of related to the title – Daniel Wehner Apr 5 '14 at 4:38
  • The text was there to explain why Im asking the question. I think I was correct in my assessment that the service container is acting as a global store for services, and changing those services would be ill advised. – Mixologic Apr 6 '14 at 18:08
1

The general idea is to not use service location but define the dependencies directly in the container. There are edge cases where you need to pass along the full container, but really, try to avoid them. For objects like plugins and controllers we use a static factory pattern, on which you get the container to get your dependencies. Note: There aren't any objects which depend on those.

On top of that you also should avoid having to change services. As much as possible! Instead you should build a wrapper service which has a method like the \Drupal\Core\Session\AccountProxy ... you can set the current user on there using setAccount.

  public function __construct(AccountInterface $current_user) {
    $this->currentUser = $current_user;
  }

  public function doSomething() {
    $this->currentUser->setAccount(new UserSession(...));
  }
4
  • So we shouldn't alter the services during the life of the request. If we want to alter behavior of services, we should create a different class that swaps out the behavior we want to override. I'm still having a hard time understanding 'current_user' as a service - that seems to be one of the few exceptions that you would want to alter mid request - and is the only example of a Proxy wrapper I can find. It also seems that it would only change the account in the proxy, and not in the container - so if other services depend on 'current_user', they would still get the original, unchanged one. – Mixologic Apr 6 '14 at 18:24
  • 1
    If other code don't do horrible things and always call getAccount() they will get the new user next time they call it. I recommend to have a look at that class, it is not hard to understand. – Daniel Wehner Apr 7 '14 at 7:57
  • Ah, I think the missing link was that $container->get('current_user') is configured to return an accountProxy instance. So the static factories that are retrieving the 'current_user' service (NodeSearch/CommentFormController etc) would be getting a modified user if that user changes. It's still not really clear whether or not making changes to a user account via the AccountProxy will have a global effect on all services that depend on it, or if it will be a localized change. – Mixologic Apr 7 '14 at 8:56
  • 1
    this will be certainly a global effect, as long noone had the idea to for example stor the uid in a local var – Daniel Wehner Apr 7 '14 at 9:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.