9.3. Een aangepaste Drupal-module maken. Pagina programmatisch weergeven.
Laten we beginnen met het maken van onze module met een beetje structuur. We gaan verder met het scheiden van aangepaste (custom) en bijgedragen (contrib) modules. In Drupal bevinden modules zich in de map /modules. Nu hoeven we ze niet meer diep in /sites/all/modules te plaatsen; hoewel de readme zegt dat dit zou moeten werken, gebruik toch de map /modules. Binnen de map /modules maken we twee mappen aan: custom en contrib. De map contrib zal extra modules van drupal.org bevatten, en onze eigen modules zullen in de map custom worden opgeslagen.
Engelse ondertiteling:
Codevoorbeelden kunnen worden bekeken op github:
https://github.com/levmyshkin/drupalbook8
Zo’n kleinigheid als het verdelen van modules in de mappen contrib en custom lijkt onnodig, maar geloof me, wanneer er 200 externe modules en 30 aangepaste modules op je site staan, zul je begrijpen hoe moeilijk het is om al je eigen modules en alle aangepaste code terug te vinden. Ook, als je wat code wijzigt in een bijgedragen module (wat alleen moet worden gedaan als het absoluut noodzakelijk is), is het verstandig deze te verplaatsen naar de custom-map, zodat je de wijzigingen niet per ongeluk overschrijft tijdens een update (of een andere ontwikkelaar jouw wijzigingen overschrijft, of jij per ongeluk de wijzigingen van iemand anders overschrijft).
Laten we dus onze aangepaste module maken. Maak de map /modules/custom/drupalbook aan. In deze map maken we het bestand drupalbook.info.yml aan:
name: DrupalBook
description: Aangepaste module voor het leren van Drupal 8
type: module
core: 8.x
core_version_requirement: ^8 || ^9
package: DrupalBook
Het *.info.yml-bestand is verantwoordelijk voor de beschrijving van de module. De informatie die daarin is opgenomen, wordt weergegeven op de pagina “Uitbreiden” (Extend). De bestandsnaam zelf bestaat uit de modulenaam + .info.yml.
Drupal YML-bestanden zijn een standaardformaat voor configuraties en instellingen. Velden en waarden in YML-bestanden worden gescheiden door een dubbele punt, en nieuwe regels beginnen met een inspringing van twee spaties. Opmaak is erg belangrijk voor een YML-bestand — als er een fout zit in de opmaak, bijvoorbeeld een extra spatie of een ontbrekende dubbele punt, dan kan Drupal een foutmelding geven of het bestand niet correct lezen.
Ga naar de pagina “Uitbreiden” en schakel je module in:
Nu we de module hebben ingeschakeld, kunnen we functionaliteit toevoegen en zal deze op onze site werken. Om te beginnen zullen we gewone tekst op de pagina weergeven. Hiervoor moeten we nog een YML-bestand aanmaken: drupalbook.routing.yml:
drupalbook.first_page:
path: '/first-page'
defaults:
_controller: '\Drupal\drupalbook\Controller\FirstPageController::content'
_title: 'Hello World!'
requirements:
_permission: 'access content'
Laten we wat beter kijken naar wat er in dit YML-bestand staat.
drupalbook.first_page: — dit is de naam van onze route, het pad waarmee Drupal een lijst van alle routes samenstelt. Deze naam moet uniek zijn. Het is het beste om de notatie module_naam.route_naam te gebruiken, omdat je meerdere routes in één module kunt hebben, zoals drupalbook.first_page, drupalbook.second_page enzovoort.
path: '/first-page' — het pad naar je route. Let op de inspringing van twee spaties, dit is verplicht. Als je een teksteditor gebruikt die tabs invoegt met de Tab-toets, verander dan deze instelling naar twee spaties.
defaults: — bepaalt de standaardinstellingen van de route en hoe deze wordt aangemaakt. Er zijn verschillende manieren om een route te maken, een daarvan is via de Controller-klasse, maar het is ook mogelijk via andere klassen dynamisch routes te genereren. Misschien bespreken we later alle mogelijkheden van routing, maar voorlopig bekijken we een eenvoudig voorbeeld via de Controller-klasse. Drupal-routing is overgenomen van Symfony en maakt gebruik van Symfony-bibliotheken. Symfony is een MVC-framework, netjes gestructureerd, en wordt ook gebruikt in andere projecten, zoals Laravel, een ander populair MVC-framework. MVC gebruikt Model, View, Controller (waarbij View hier geen Views-module is, maar gewoon een template voor het tonen van informatie; Model — entiteitsklassen waarmee informatie aan de database kan worden toegevoegd, vergelijkbaar met de Entity API in Drupal). De Controller in MVC is bedoeld voor routing — en dat is precies wat we in deze les doen.
_controller: '\Drupal\drupalbook\Controller\FirstPageController::content' — In deze parameter geven we aan welke PHP-klasse onze pagina zal weergeven. Na de klassenaam gebruiken we :: om de specifieke methode binnen de klasse te specificeren die de pagina moet renderen. De vele backslashes zijn nodig zodat Drupal begrijpt in welke map je PHP-klasse zich bevindt.
_title: 'Hello World!' — De titel van onze pagina.
_permission: 'access content' — Rechten om deze pagina te bekijken. De gebruiker moet een rol hebben met deze rechten om toegang te krijgen.
Na het toevoegen van het YML-bestand voor routing, moeten we de PHP-klasse toevoegen die onze pagina zal weergeven. Hiervoor moeten we eerst begrijpen hoe automatische klassekoppeling werkt binnen onze modules. In Drupal zijn er veel klassen, maar niet allemaal zijn nodig voor elke specifieke pagina, dus worden alleen de benodigde klassen geladen. Drupal gebruikt PHP’s PSR-4 autoloading-mechanisme:
https://www.php-fig.org/psr/psr-4/
Laten we kijken naar de regel in de route waar we de PHP-klasse hebben aangegeven:
\Drupal\drupalbook\Controller\FirstPageController
\Drupal — betekent dat de klasse wordt geladen via de Drupal-bibliotheek. Drupal is tegenwoordig ook een aparte bibliotheek (vrij groot) die via Packagist kan worden gekoppeld:
https://packagist.org/packages/drupal/drupal
Vervolgens geven we aan welke module we willen gebruiken:
\drupalbook
Daarna geven we ofwel direct de klassenaam in de map van onze module aan, of verdere submappen. Alle mappen zullen zich binnen de map src bevinden, dus als we de Controller-map hebben opgegeven, ligt deze hier:
/modules/custom/drupalbook/src/Controller
Let op hoofdletters, PHP maakt onderscheid tussen hoofd- en kleine letters, dus controller en Controller zijn verschillende mappen.
Tot slot geven we de bestandsnaam aan, en voegen we .php toe:
/modules/custom/drupalbook/src/Controller/FirstPageController.php
Laten we dit bestand aanmaken:
/**
* @return
* Bevat \Drupal\drupalbook\Controller\FirstPageController.
*/
namespace Drupal\drupalbook\Controller;
/**
* Biedt route-antwoorden voor de DrupalBook-module.
*/
class FirstPageController {
/**
* Retourneert een eenvoudige pagina.
*
* @return array
* Een eenvoudige renderbare array.
*/
public function content() {
$element = array(
'#markup' => 'Hello World!',
);
return $element;
}
}
Dit zou de structuur van de bestanden moeten zijn:
Nu moeten we de cache leegmaken zodat onze nieuwe route wordt herkend. De pagina zou nu beschikbaar moeten zijn op http://drupalbook/first-page
Laten we nu de PHP-klasse bekijken die deze pagina weergeeft.
/**
* @return
* Bevat \Drupal\drupalbook\Controller\FirstPageController.
*/
Hier geven we het pad aan, hetzelfde als in het routing-YML-bestand; dit vertelt Drupal waar deze klasse moet worden geladen.
namespace Drupal\drupalbook\Controller;
Namespace geeft het pad aan naar je klassebestand. Wees voorzichtig bij het kopiëren van code van andere sites — als je de namespace kopieert, moet je de naam van de module wijzigen naar jouw eigen naam. In mijn geval is dat drupalbook, maar bij jou kan het iets anders zijn.
class FirstPageController {
/**
* Retourneert een eenvoudige pagina.
*
* @return array
* Een eenvoudige renderbare array.
*/
public function content() {
$element = array(
'#markup' => 'Hello World!',
);
return $element;
}
}
En dit is onze klasse die de pagina weergeeft. Deze bevat de methode content(), die we in drupalbook.routing.yml hebben opgegeven. In deze methode retourneren we een array met het #markup-element waarin we de HTML-uitvoer plaatsen. We retourneren een array in plaats van een string, omdat we via een route niet alleen HTML kunnen weergeven, maar ook een JSON-endpoint voor een API, of een XML- of CSV-bestand.
De modulecode kan worden bekeken op github:
https://github.com/levmyshkin/drupalbook8
Dat is alles — in de volgende les zullen we de mogelijkheden van onze module verder uitbreiden.