6

when trying to use a service in drupal actually there is 3 ways , what is the preferred way to use a service and why :

  1. passing dependencies directly through the constructor:

    public function __construct(AccountProxyInterface $current_user) {
    
    }
    
  2. passing the dependencies through the create() method wich look to me the same as injecting it through the __construct(), with the only difference , an instance will be created eah time (no singleton design pattern - not same instance will be reused)

      public static function create(ContainerInterface $container)
  {
    //1.getting service from the service container.
    $Door = $container->get('custom_service.door');
    //2.create a new object of current class, and Inject the dependency  object into the constructor
    return new static($Door);
  }

  //constructor receive the dependency set by the create() method
  public function __construct(Door $Door)
  {
    kint($Door);
  }
  1. just get get the service from the service container and no need to inject it using :
    $Door = \Drupal::service('custom_service.door')
3
  • 4
    You should always inject your arguments and typehint them to their interface counterpart whenever possible. Assigning instance variables from the global container is not advised. \Drupal::service... is largely used from procedural code when not in an OOP context.
    – Kevin
    Jan 15, 2020 at 21:47
  • 5
    2. also has a specific context in Drupal, it is a factory method pattern used to instantiate controllers and plugins. So there is no preferred way, each one is used in a different context.
    – 4uk4
    Jan 15, 2020 at 22:09
  • @4k4 can you explain the diffent contexts, so that I know when to use create factory method and when to inject directly into the constructor. Jan 15, 2020 at 23:28

1 Answer 1

8
  1. The standard way to inject services in other services is passing dependencies directly through the constructor:

    mymodule.services.yml:

    services:
      mymodule.foo_service:
        class: Drupal\mymodule\FooService
        arguments: ['@current_user']
    
  2. While you can define a factory method in *.services.yml, see https://symfony.com/doc/current/service_container/factories.html, in Drupal the most common places for this are Controllers and Plugins which implement ContainerInjectionInterface::create or ContainerFactoryPluginInterface::create. See How do I use dependency injection on \Drupal::moduleHandler() to a Controller?

  3. \Drupal::service... is largely used from procedural code when not in an OOP context, like hooks or static callbacks. See the comment from @Kevin.

5
  • 1
    Also worth metion that you can inject dependencies (services or parameters) to a class that is not a service and will be used on procedural code like hooks by making your class implement \Drupal\Core\DependencyInjection\ContainerInjectionInterface and by calling it in your hook using $instance = \Drupal::classResolver('\Drupal\my_module\MyAwesomeClass');. Is not a service but will use services though.
    – d70rr3s
    Jan 16, 2020 at 9:07
  • Is the linked question 226997 still a recommended pattern? According to this blog post the constructor should be considered internal and subject to changes.
    – Hudri
    Jan 16, 2020 at 9:47
  • @Hudri, this is a good point, although it's not that you shouldn't use the design pattern anymore, it's about how you can extend existing controllers which are built with this design pattern.
    – 4uk4
    Jan 16, 2020 at 10:14
  • 1
    For my own understanding: If I'm writing my own standalone class -> __construct(Services...) OK. As soon as I'm extending from another class like e.g. ControllerBase or PluginBase -> better leave the constructor alone and $container->get() the service inside create()?
    – Hudri
    Jan 16, 2020 at 10:35
  • No, the linked blog post is not about writing a new controller or plugin by extending a base class in your own module, it's about extending existing core/contrib controllers and plugins.
    – 4uk4
    Jan 16, 2020 at 10:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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