{"id":1362,"date":"2015-02-06T14:29:04","date_gmt":"2015-02-06T14:29:04","guid":{"rendered":"https:\/\/www.zensations.at\/?p=1362"},"modified":"2023-08-09T00:31:48","modified_gmt":"2023-08-09T00:31:48","slug":"drupal-8-basics-modulentwicklung","status":"publish","type":"post","link":"https:\/\/www.zensations.at\/blog\/drupal-8-basics-modulentwicklung\/","title":{"rendered":"Drupal 8 Basics: Modulentwicklung"},"content":{"rendered":"

Drupal 8 steht kurz vor der Ver\u00f6ffentlichung der offiziellen Version, laut der\u00a0Drupal8Hivemind<\/a>\u00a0sind 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\u00dfe \u00c4nderungen in den API’s werden nicht mehr stattfinden. F\u00fcr uns ein Grund unsere Bekanntschaft mit den (durchaus starken) \u00c4nderungen der neuen Version nach aussen zu kommunizieren.<\/p>\n

Das Ziel dieses Artikels ist es, uns mit den Basics der Modulentwicklung f\u00fcr Drupal 8 zu befassen. Wir werden ein Modul entwickeln, welches auf ein von uns registrierten Pfad in Drupal eine einfache Ausgabe t\u00e4tigen soll. Sp\u00e4ter werden wir eine Service anbinden, der uns Twitter Feeds auf dem von uns registrierten Pfad anzeigt.<\/p>\n

\u00c4nderungen im Dateisystem<\/h2>\n

Die erste wesentliche \u00c4nderung, die uns auff\u00e4llt, ist die stark ver\u00e4nderte 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\u00e4re, eigene Module usw. k\u00f6nnen dann direkt im „modules“-Subordner installiert werden. Das gilt analog f\u00fcr Themes, die man entsprechend im „themes“-Subordner platztieren kann. F\u00fcr Multisite-Installationen ist der „sites“-Ordner immer noch vorhanden. Das macht die Ordnerstruktur viel intiutiver, besonders Drupal-Newbies werden damit besser zurechtkommen.<\/p>\n

YAML-Syntax everywhere<\/h2>\n

Unser Modul (genannt „mymodule“) werden wir somit im „modules“-Subordner erstellen. Im Gegensatz von Drupal 7 brauchen wir, um das Modul aktivieren zu k\u00f6nnen, lediglich eine *.info-Datei. Die *.module Datei kann auch exisieren, um die in Drupal 8 \u00fcberbleibende Hooks zu enthalten, ist aber nurmehr optional. Die *.info-Datei ist die einzige, die wir brauchen und diese soll in\u00a0Symfony’s YAML Syntax<\/a>\u00a0geschrieben sein, damit bekommt sie zus\u00e4tzlich eine „.yml“-Endung. In unserem Fall also „mymodule.info.yml“. Der Inhalt der Datei ist wie folgt:<\/p>\n

\r\nname: MyModule\r\ntype: module\r\ndescription: 'Drupal8 Module Sandbox'\r\npackage: Custom\r\ncore: 8.x\r\n<\/code><\/pre>\n

Das einzige, was eine \u00c4nderung zu Drupal 7 darstellt ist der Key „type“ mit dem Wert „module“, welcher unsere Erweiterung als Modul im System registriert. Analog dazu w\u00fcrden z.B. Themes den Wert „theme“ haben. Damit k\u00f6nnen wir schon in unser Drupal 8-Backend das Modul aktivieren, indem wir es im Hauptmen\u00fc unter „Manage -> Extend“ ausw\u00e4hlen und auf Speichern dr\u00fccken. Oder mit Drush „drush en mymodule“.<\/p>\n

Routing wird anders<\/h2>\n

Als n\u00e4chsten 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\u00fcr 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\u00fchrt werden soll. Der Inhalt unserer mymodule.routing.yml-Datei sieht somit so aus:<\/p>\n

\r\nmymodule.hello_world:\r\n  path: '\/mymodule\/hello-world\/{username}'\r\n  defaults:\r\n    _controller: '\\Drupal\\mymodule\\Controller\\HelloWorldController::feed'\r\n    _title: 'Hello World'\r\n    username: 'foo'\r\n  requirements:\r\n    _access: 'TRUE'\r\n<\/code><\/pre>\n

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\u00f6nnte. Der „path“-Key gibt die URL bekannt, auf der ist auch ein Placeholder f\u00fcr den Benutzernamen in geschwungenen Klammern definiert. Im „defaults“-Array steht die Information \u00fcber Pfad zum Controller, der aufgerufen werden soll, der Seitentitel, der \u00fcbrigens automatisch vom Translation-System registriert wird und ein default-Wert f\u00fcr den Benutzernamen. Der Placeholder-Wert wird unserer Methode als Variable \u00fcbergeben, 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\u00fcr den Moment machen wir es und leicht und lassen allen den Zutritt auf der URL zu.<\/p>\n

Namespacing<\/h2>\n

Ein Paar Worte sollten noch zum „_controller“-Key. Der Pfad zum Controller ist im von Drupal 8 aufgenommenen\u00a0PSR-4-Standard<\/a>. 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\u00e4tzlichen Ordner nach dem Modul-Namespace genauso in der Datei und Ordnerstruktur des „src“-Ordners abgebildet. F\u00fcr 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\u00fcgen folgenden Code hinzu:<\/p>\n

namespace Drupal\\mymodule\\Controller;<\/code><\/p>\n

use Drupal\\Core\\Controller\\ControllerBase;<\/p>\n

class HelloWorldController extends ControllerBase {<\/p>\n

public function feed($username) { $content = array( ‚#markup‘ => t(‚Hello ‚ . $username), );<\/p>\n

return $content;\r\n<\/code><\/pre>\n

} }<\/p>\n

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\u00e4lt f\u00fcr den Anfang nur eine sehr einfache „feed“-Methode, die den username-Teil in der URL als Variable bekommt. F\u00fcr das einfache Beispiel k\u00f6nnen wir durchaus eine einfache Klasse definieren, die nicht ControllerBase erweitert. Der Grund, warum wir das tun ist aber, dass wir \u00fcber „ControllerBase“ automatisch Utilities in unserem Controller zur Verf\u00fcgung gestellt bekommen (wir z.B. die t()-Funktion), die wir sonst selbst bei Bedarf reinholen m\u00fcssten. Mehr Infos zum ControllerBase Klasse gist es auf\u00a0api.drupal.org<\/a>.<\/p>\n

Um die \u00c4nderungen in unserem Code im System zu registrieren, m\u00fcssen 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.<\/p>\n

In dem n\u00e4chsten 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.<\/p>\n

Fazit<\/h2>\n

Wenn man sich Drupal 8 installiert hat und man einen Blick auf das neue Bartik wirft, wird man noch nicht ahnen, wie viele \u00c4nderungen das System beinhaltet. Sp\u00e4testens 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 \u00fcberw\u00e4ltigend, aber die Bekanntschaft mit der objektorientreirten Welt macht schnell Spa\u00df, denn die neuen Konzepte sind ausgereift und zukunftsf\u00e4hig. Wichtig ist, die grundliegende Softwarestruktur ist erhalten, der Weg ist anders.<\/p>\n","protected":false},"excerpt":{"rendered":"

Drupal 8 steht kurz vor der Ver\u00f6ffentlichung der offiziellen Version, laut der\u00a0Drupal8Hivemind\u00a0sind 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\u00dfe \u00c4nderungen in den API’s werden nicht mehr stattfinden. F\u00fcr uns ein Grund unsere […]<\/p>\n","protected":false},"author":23,"featured_media":1349,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[78],"tags":[211],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.zensations.at\/wp-json\/wp\/v2\/posts\/1362"}],"collection":[{"href":"https:\/\/www.zensations.at\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.zensations.at\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.zensations.at\/wp-json\/wp\/v2\/users\/23"}],"replies":[{"embeddable":true,"href":"https:\/\/www.zensations.at\/wp-json\/wp\/v2\/comments?post=1362"}],"version-history":[{"count":1,"href":"https:\/\/www.zensations.at\/wp-json\/wp\/v2\/posts\/1362\/revisions"}],"predecessor-version":[{"id":1363,"href":"https:\/\/www.zensations.at\/wp-json\/wp\/v2\/posts\/1362\/revisions\/1363"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.zensations.at\/wp-json\/wp\/v2\/media\/1349"}],"wp:attachment":[{"href":"https:\/\/www.zensations.at\/wp-json\/wp\/v2\/media?parent=1362"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.zensations.at\/wp-json\/wp\/v2\/categories?post=1362"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.zensations.at\/wp-json\/wp\/v2\/tags?post=1362"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}