Wie verwende ich Dependency Injection unter \ Drupal :: moduleHandler () für einen Controller?

14

Ich verwende die folgende Zeile in einer Controller-Klasse.

    \Drupal::moduleHandler()->alter('mymodule_myfunction', $plugin_items);

Pareview.sh gibt mir diese Fehlermeldung.

\ Drupal-Aufrufe sollten in Klassen vermieden werden. Verwenden Sie stattdessen die Abhängigkeitsinjektion.

Wie soll ich das erreichen? Muss ich einen Konstruktor, eine Methode oder einen Service erstellen? Wenn ja, welchen Code sollte der Dienst benötigen? Ich fand ein Beispiel zu "Drupal-Aufrufe sollten in Klassen vermieden werden, verwenden Sie stattdessen die Abhängigkeitsinjektion" für einen Fall, in dem ein Dienst bereits vorhanden ist.

Kevin Nowaczyk
quelle
createwird die übergeordnete Methode überlasten - hier können Sie die Dienste einfügen, die Sie benötigen. Der Konstruktor lässt Sie diese dann Instanzvariablen in der Klasse zuweisen, damit Sie sie verwenden können$this->fooInjectedClass->methodName()
Kevin
Haben wir dazu schon eine Frage? Wenn nicht, sollten wir das wirklich kanonisch machen.
mpdonadio

Antworten:

20

In einem Controller injizieren Sie Services mithilfe des Service-Containers. Zum Beispiel ModuleHandler:

namespace Drupal\mymodule\Controller;

use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;

class MyController extends ControllerBase {

  /**
   * The module handler service.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  protected $moduleHandler;

  /**
   * Constructs a MyController object
   *
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   The module handler service.
   */
  public function __construct(ModuleHandlerInterface $module_handler) {
    $this->moduleHandler = $module_handler;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('module_handler')
    );  
  }

Dann können Sie \DrupalAnrufe vermeiden, indem Sie den injizierten Dienst verwenden:

$this->moduleHandler->alter('mymodule_myfunction', $plugin_items);

Sie können jeden Dienst, vorhandene Dienste aus Core / Contrib oder Dienste, die Sie im benutzerdefinierten Code definiert haben, in eine *.services.ymlDatei einfügen .

Um einen Kerndienstnamen zu finden, schaue ich normalerweise nach core.services.yml, da dies der schnellste Weg ist, wenn Sie in Ihrer IDE an einem Drupal-Projekt arbeiten.

Sie können Drupal Console verwenden, um alle Dienste aufzulisten , nicht nur vom Kern:

drupal debug:container

Sie können auch das Devel-Modul verwenden , mit dem Sie nach einem Namen suchen können:

/devel/container/service
4k4
quelle
1
Diese Art von Frage / Antwort sollte erweitert werden, wenn ich damit einverstanden bin, und zurück zu drupal.org-Dokumenten beigetragen werden. Es gibt einige , aber ich glaube, dass Beispiele aus der Praxis wie diese immer helfen.
Kevin
4
Die ControllerBaseKlasse implementiert die ContainerInjectionInterfaceSchnittstelle bereits. Es ist nicht erforderlich implements ContainerInjectionInterface, eine Klasse zu erweitern ControllerBase.
kiamlaluno
Richtig, habe gerade das Gleiche bemerkt wie @kiamlaluno; wäre toll die antwort zu aktualisieren!
Stefanos Petrakis