Rainer Feike IT Berater

Seit 15 Jahren Freelancer / Freiberufler in der EDV um München. Speziell C/C++, JAVA, PHP, Bank, Wertpapier. Projekt Profil.

Drupal 8 Dependency Injection im Controller

Drupal Organisational Member Ich entwickle Drupal Projekte seit 2007 und biete kommerzielle Dienstleistungen im Enterprise Bereich an.

Zuletzt hatte ich beschrieben, wie Services und Dependency Injection in Drupal 8 funktionieren. Heute zeige ich, wie man eigene Services in Controllern verwendet.

Motivation: Wenn wir uns schon zugunsten Wartbarkeit und Testbarkeit den ganzen Heckmeck mit DI aufhalsen, dann sollen auch Controller davon profitieren. Und bei Symfonie 2 sind Controller keine Services und können daher nicht mit Constructor-Injection versorgt werden.

Controller verwenden wir in Drupal 8 in erster Linie, um unsere Routings darzustellen (früher hook_menu).

Ein Beispiel aus proreos.routing.yml:

proreos.verzeichnis.kanzlei:
  path: '/verzeichnis/{kanzleinode}'
  defaults:
    _content: '\Drupal\proreos\Controller\VerzeichnisController::kanzleiView'
    _title_callback: '\Drupal\proreos\Controller\VerzeichnisController::kanzleiViewTitle'
  requirements:
    _permission: 'access content'



Diese Route - Deklaration sagt Drupal, das der Output für http:://bla/verzeichnis/xx durch den Aufruf der Methode kanzleiView() in der Klasse proreos\Controller\VerzeichnisController gerendert werden soll. Wie kann ich aber nun in VerzeichnisController Services verwenden?

Dazu muss man wissen, dass Drupal 8 den Controller (Request scoped) erzeugt indem das Framework create(ContainerInterface $container) aufruft. Wir müssen also create() in unserem Controller überschreiben (geerbet von Drupal\Core\Controller\ControllerBase was auch eine Basisklasse unseres Controllers sei). Und damit sich ein einheitliches Bild zur Constructor-Injection der Services ergibt hat sich folgende Notation eingebürgert:

  /**
   * Hold the proreos super manager.
   *
   * @var \Drupal\proreos\ProreosSuperManager
   */
  protected $proreosSuperManager;
	
  /**
   * Constructs the VerzeichnisController.
   *
   * @param \Drupal\proreos\ProreosSuperManager $super_manager
   *   The proreos super manager.
   */
  public function __construct(ProreosSuperManager $super_manager) {
    $this->proreosSuperManager= $super_manager;
  }
  
  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
	  $container->get('proreos.supermanager')
    );
  }



Die Methode create() ruft also unseren Constructor mit dem gewünschten Argument auf und holt vorher den Service beim Container ab.
Das sollte man sich übrigens nicht einfacher machen, indem man die Methode container() aus dem BaseController nimmt. Die verwendet nämlich deprecated den statischen Context (Drupal::getContainer()).
Aber jetzt sieht alles wieder aus wie Constructor-Injection bei Symfonie 2. Wegen der ganzen Type Hints und Annotationen ist es auch in Eclipse PDT recht komfortabel zu benutzen.

Geschrieben am 10.11.2014, zuletzt bearbeitet am 10.11.2014, wie folgt kategorisiert:
Fachbereiche Technische Umgebung Stichworte
Rainer Feike: "Ich arbeite seit 1994 als Freelancer bzw. Freiberufler in der EDV Branche um München. Ich bin Softwareentwickler für Projekte in C/C++, JAVA und PHP. Ich bin Analyst und Berater im Fachbereich Bank und Börse. Ich konzipiere, entwickle und betreibe anspruchsvolle Web 2.0 Projekte. " Powered by Drupal

Skillset

C, C++, JAVA, PHP, Linux, Unix, SQL, mySQL, Oracle, JBF, Drupal, CSS, JavaScript, HTML, tomcat, XML, XSD - A highly efficient exceptional awesome software engineer :-)

Template design and technology by proxiss web20 technology