Skip to main content

Drupal 8 Basics: Modulentwicklung

Drupal 8 steht kurz vor der Veröffentlichung der offiziellen Version, laut der Drupal8Hivemind sind es nur mehr knappe 5 Monate bis dorthin! So oder so, mittlerweile ist die 8-er Version in der beta6 und die Basis steht, es geht nunmehr nur um Bugfixing, große Änderungen in den API's werden nicht mehr stattfinden. Für uns ein Grund unsere Bekanntschaft mit den (durchaus starken) Änderungen der neuen Version nach aussen zu kommunizieren.

Das Ziel dieses Artikels ist es, uns mit den Basics der Modulentwicklung für Drupal 8 zu befassen. Wir werden ein Modul entwickeln, welches auf ein von uns registrierten Pfad in Drupal eine einfache Ausgabe tätigen soll. Später werden wir eine Service anbinden, der uns Twitter Feeds auf dem von uns registrierten Pfad anzeigt.

Änderungen im Dateisystem

Die erste wesentliche Änderung, die uns auffällt, ist die stark veränderte Dateistruktur von Drupal 8. Alle Core-Dateien finden nun Platz im "core"-Subordner der Installation und sind so sauber abgetrennt vom Rest. Module aus der Contrib-Sphäre, eigene Module usw. können dann direkt im "modules"-Subordner installiert werden. Das gilt analog für Themes, die man entsprechend im "themes"-Subordner platztieren kann. Für Multisite-Installationen ist der "sites"-Ordner immer noch vorhanden. Das macht die Ordnerstruktur viel intiutiver, besonders Drupal-Newbies werden damit besser zurechtkommen.

YAML-Syntax everywhere

Unser Modul (genannt "mymodule") werden wir somit im "modules"-Subordner erstellen. Im Gegensatz von Drupal 7 brauchen wir, um das Modul aktivieren zu können, lediglich eine *.info-Datei. Die *.module Datei kann auch exisieren, um die in Drupal 8 überbleibende Hooks zu enthalten, ist aber nurmehr optional. Die *.info-Datei ist die einzige, die wir brauchen und diese soll in Symfony's YAML Syntax geschrieben sein, damit bekommt sie zusätzlich eine ".yml"-Endung. In unserem Fall also "mymodule.info.yml". Der Inhalt der Datei ist wie folgt:


name: MyModule
type: module
description: 'Drupal8 Module Sandbox'
package: Custom
core: 8.x

Das einzige, was eine Änderung zu Drupal 7 darstellt ist der Key "type" mit dem Wert "module", welcher unsere Erweiterung als Modul im System registriert. Analog dazu würden z.B. Themes den Wert "theme" haben. Damit können wir schon in unser Drupal 8-Backend das Modul aktivieren, indem wir es im Hauptmenü unter "Manage -> Extend" auswählen und auf Speichern drücken. Oder mit Drush "drush en mymodule".

Routing wird anders

Als nächsten Schritt wollen wir die Route definieren, wo der Output von unserem Modul dargestellt wird. In Drupal 7 konnten wir das mit einer Implementierung von hook_menu() in unserer *.module-Datei erledigen. Drupal 8 hat für das Routing ein separates System, welches auf Symfony-Komponenten basiert. Im Wesentlichen definiert man in einer *.routing.yml-Datei die URL und weist ihr einen Controller zu, der auf dieser URL ausgeführt werden soll. Der Inhalt unserer mymodule.routing.yml-Datei sieht somit so aus:


mymodule.hello_world:
  path: '/mymodule/hello-world/{username}'
  defaults:
    _controller: '\Drupal\mymodule\Controller\HelloWorldController::feed'
    _title: 'Hello World'
    username: 'foo'
  requirements:
    _access: 'TRUE'

Unser Modul darf durchaus mehrere Routes registrieren, damit besteht der Hauptkey aus dem Modul- und den Routenamen, getrennt mit einem Punkt. Es kann also auch eine weitere Route registriert werden, die z.B. "mymodule.facebook_feed" heissen könnte. Der "path"-Key gibt die URL bekannt, auf der ist auch ein Placeholder für den Benutzernamen in geschwungenen Klammern definiert. Im "defaults"-Array steht die Information über Pfad zum Controller, der aufgerufen werden soll, der Seitentitel, der übrigens automatisch vom Translation-System registriert wird und ein default-Wert für den Benutzernamen. Der Placeholder-Wert wird unserer Methode als Variable übergeben, im defaults-Array kann man einen default-Wert festsetzen. Im "requirements"-Array kann man z.B. Berechtigungen definieren, die diese Seite aufrufbar machen (z.B. _permissions: 'access content'). Für den Moment machen wir es und leicht und lassen allen den Zutritt auf der URL zu.

Namespacing

Ein Paar Worte sollten noch zum "_controller"-Key. Der Pfad zum Controller ist im von Drupal 8 aufgenommenen PSR-4-Standard. Jedes Modul hat ein Namespace, welches seinem Modulnamen entspricht, in unserem Fall ist es "Drupal\mymodule\". Dieser Namespace ist dem "src"-Ordner im Root-Verzeichnis zugewiesen, sprich "modules/mymodule/src/". Damit werden alle zusätzlichen Ordner nach dem Modul-Namespace genauso in der Datei und Ordnerstruktur des "src"-Ordners abgebildet. Für uns bedeutet das, dass "\Drupal\mymodule\Controller\HelloWorldController" bedingt, dass unser Controller in der Datei mit dem Pfad "modules/mymodule/src/Controller/HelloWorldController.php" liegen soll. Wir erstellen diese Datei und fügen folgenden Code hinzu:

namespace Drupal\mymodule\Controller;

use Drupal\Core\Controller\ControllerBase;

class HelloWorldController extends ControllerBase {

public function feed($username) { $content = array( '#markup' => t('Hello ' . $username), );

return $content;

} }

Als erstes definieren wir in welchem Namespace unser Controller liegt. Danach erstellen wir unsere Klasse "HelloWorldController", die die "ControllerBase"-Klasse erweitert und referenzieren den virtuellen Pfad zu dieser Klasse (mit "use Drupal\Core\Controller\ControllerBase;"). Unser Controller enthält für den Anfang nur eine sehr einfache "feed"-Methode, die den username-Teil in der URL als Variable bekommt. Für das einfache Beispiel können wir durchaus eine einfache Klasse definieren, die nicht ControllerBase erweitert. Der Grund, warum wir das tun ist aber, dass wir über "ControllerBase" automatisch Utilities in unserem Controller zur Verfügung gestellt bekommen (wir z.B. die t()-Funktion), die wir sonst selbst bei Bedarf reinholen müssten. Mehr Infos zum ControllerBase Klasse gist es auf api.drupal.org.

Um die Änderungen in unserem Code im System zu registrieren, müssen wir noch den Cache leeren (in Drupal 8 unter "admin/config/development/performance" oder mit Drush "drush cr"). Danach sollte uns der Output der feed-"Methode" auf der registriertem Pfad ("mymodule/hello-world" oder "mymodule/hello-world/bar") angezeigt werden. Und schon hat man den ersten Meilenstand in der Drupal 8 Entwicklung hinter sich.

In dem nächsten Blogbeitrag der Serie werden wir einen Schritt weiter gehen und dann unser Modul mit dem Konzept von Services und Dependency Injection befassen, um eine Dienst in unserem Modul zu implementieren, der dann auch Twitter-Feeds auf unsere definierte URL anzeigt.

Fazit

Wenn man sich Drupal 8 installiert hat und man einen Blick auf das neue Bartik wirft, wird man noch nicht ahnen, wie viele Änderungen das System beinhaltet. Spätestens dann, wenn man sich mit dem Code auseinandersetzt, wird einem klar, wie viel Arbeit in die neue Version gesteckt wurde. Am Anfang ist das sicherlich ein wenig überwältigend, aber die Bekanntschaft mit der objektorientreirten Welt macht schnell Spaß, denn die neuen Konzepte sind ausgereift und zukunftsfähig. Wichtig ist, die grundliegende Softwarestruktur ist erhalten, der Weg ist anders.

Wird nicht veröffentlicht