Basisstructuur van een Drupal-module
Deel II van de praktische handleiding voor het maken van basis Drupal 8-modules
Van .info tot tests, alleen de basis
Basisstructuur
loremipsum.info.yml
name: Lorem ipsum type: module description: 'Lorem ipsum generator for Drupal' package: Development core: 8.x configure: loremipsum.form
Info-bestanden zijn nu geformatteerd als YML, en er is een verschil tussen modules en thema’s dat duidelijk moet zijn via de type-aanduiding. De aanduiding configure
verwijst naar een route (meer hierover later), maar verder is er niets bijzonders. In feite is dit het enige bestand dat je nodig hebt voor je module. Nadat je dit hebt opgeslagen (in de map root/modules), kun je je module inschakelen in /admin/modules
zonder dat je site kapot gaat. Maar, zoals je verder zult zien, is dit niet genoeg.
loremipsum.module
<?php use Drupal\Core\Routing\RouteMatchInterface; /** * Implements hook_help(). */ function loremipsum_help($route_name, RouteMatchInterface $route_match) { switch ($route_name) { case 'help.page.loremipsum': return t(' <h2>Lorem ipsum generator for Drupal.</h2> <h3>Instructions</h3> <p>Lorem ipsum dolor sit amet... <strong>Just kidding!</strong></p> <p>Unpack in the <em>modules</em> folder (currently in the root of your Drupal 8 installation) and enable in <strong>/admin/modules</strong>.</p> <p>Then, visit <strong>/admin/config/development/loremipsum</strong> and enter your own set of phrases to build random-generated text (or go with the default Lorem ipsum).</p> <p>Last, visit <strong>www.example.com/loremipsum/generate/P/S</strong> where:</p> <ul> <li><em>P</em> is the number of <em>paragraphs</em></li> <li><em>S</em> is the maximum number of <em>sentences</em></li> </ul> <p>There is also a generator block in which you can choose how many paragraphs and phrases and it\'ll do the rest.</p> <p>If you need, there\'s also a specific <em>generate lorem ipsum</em> permission.</p> <h3>Attention</h3> <p>Most bugs have been ironed out, holes covered, features added. But this module is a work in progress. Please report bugs and suggestions, ok?</p> '); } }
Een goede gewoonte is om hier ten minste een aanroep van hook_help() neer te zetten. Let ook op de use-verklaring die naar de klasse RouteMatchInterface
verwijst. Dit is voornamelijk omdat hook_menu() niet langer bestaat.
... En naarmate je verder gaat, zul je merken dat het .module-bestand ook gebruikt zal worden om thematische informatie op te slaan. Dus hou dat bestand.
loremipsum.install
<?php /** * @file * Installation functions for Lorem ipsum module. */ use Drupal\user\RoleInterface; /** * Implements hook_install(). */ function loremipsum_install() { user_role_change_permissions(RoleInterface::ANONYMOUS_ID, array( 'generate lorem ipsum' => TRUE, )); }
Hier gebruiken we een andere klasse: RoleInterface. In wezen vertelt dit bestand Drupal: “zodra deze module is ingeschakeld, zoek de permissie om lorem ipsum te genereren en zet die aan.”
Maar waar is die permissie gedefinieerd?
loremipsum.permissions.yml
generate lorem ipsum: title: 'Generate Lorem ipsum'
Zoals je ziet, is dit veel eenvoudiger dan een aanroep naar hook_permission(). De volledige syntaxis staat in de documentatie van PermissionHandler.
loremipsum.routing.yml
loremipsum.generate: path: '/loremipsum/generate/{paragraphs}/{phrases}' defaults: _controller: '\Drupal\loremipsum\Controller\LoremIpsumController::generate' requirements: _permission: 'generate lorem ipsum' loremipsum.form: path: '/admin/config/development/loremipsum' defaults: _form: '\Drupal\loremipsum\Form\LoremIpsumForm' _title: 'Lorem ipsum settings' requirements: _permission: 'administer site configuration'
Het routingbestand vervangt de aanroep naar hook_menu(). Elke invoer (zonder inspringing) verwijst naar een route, met de regels eronder (ingesprongen) die de specifieke instellingen detailleren.
De route loremipsum.generate
verwijst naar een pagina die twee argumenten tussen {}
accepteert; deze komt overeen met een controller (meer hierover later), in tegenstelling tot loremipsum.form
, die naar een (instellingen) formulier met titel verwijst.
Voor beide routes zijn permissies vereist, maar je kunt ze vervangen door _access: 'TRUE'
voor onbeperkte toegang.
loremipsum.services.yml
Hiermee kun je een eigen service declareren.
loremipsum.links.menu.yml
loremipsum.form: title: 'Lorem Ipsum settings' description: 'Configure settings for the Lorem Ipsum module.' route_name: loremipsum.form parent: 'system.admin_config_development'
Terwijl het routingbestand de pagina aanmaakt in /admin/config/development/loremipsum
, zijn deze definities nodig om pagina’s aan het menu Beheer toe te voegen.
loremipsum.links.task.yml
Definities om extra lokale taken (tabs) aan te maken voor een specifieke route.
loremipsum.links.action.yml
Definities om extra lokale acties (knoppen) aan te maken voor een specifieke route.
loremipsum.links.contextual.yml
Definities om extra contextuele acties aan te maken voor een specifiek UI-element.
loremipsum.libraries.yml
Wordt gebruikt om afhankelijkheden voor CSS- en Javascript-bibliotheken vast te leggen. Meer details in de betreffende sectie.
README.md
Plaats in de map *modules* (momenteel in de root van je Drupal 8-installatie) en schakel in via /admin/modules
.
Ga daarna naar /admin/config/development/loremipsum
en voer je eigen set
zinnen in om willekeurig gegenereerde tekst te maken (of gebruik de standaard Lorem ipsum).
Bezoek tenslotte www.example.com/loremipsum/generate/P/S
, waar:
- *P* = aantal *paragrafen*
- *S* = maximaal aantal *zinnen*
Er is ook een generatorblok waarin je kunt kiezen hoeveel paragrafen en
zinnen, en het doet de rest.
Indien nodig is er ook een specifieke permissie *generate lorem ipsum*.
Let op
---------
De meeste bugs zijn opgelost, gaten gedicht, functies toegevoegd. Maar deze module is nog in ontwikkeling. Meld bugs en suggesties, oké?
Ja, README-bestanden worden nu geschreven in Markdown. Best gaaf, als je het mij vraagt.
Laten we nu dieper ingaan op de mappen om specifieke details nader te bekijken.
LICENSE.TXT
Neem het bestand LICENSE.txt (of iets dergelijks) niet op. Het verpakkingsscript voegt dit zelf toe.
/config/install/loremipsum.settings.yml
loremipsum:
page_title: 'Lorem ipsum'
source_text: "Lorem ipsum dolor sit amet, consitteur adipisci elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua". in view in curl vel esse cillum dolore eu fugiat nulla pariatur. \ nExcepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est labour. "
In dit bestand worden de standaardinstellingen opgeslagen, die aan de juiste velden worden toegewezen via het volgende bestand:
loremipsum: page_title: 'Lorem ipsum' source_text: "Lorem ipsum dolor sit amet, consectetur adipisci elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. \nUt enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. \nDuis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. \nExcepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. "
In dit bestand worden de standaardinstellingen opgeslagen, die aan de juiste velden worden toegewezen via het volgende bestand:
/config/schema/loremipsum.schema.yml
loremipsum.settings: type: config_object label: 'Lorem Ipsum settings' mapping: loremipsum: type: mapping mapping: page_title: type: text label: 'Lorem ipsum generator page title:' source_text: type: text label: 'Source text for lorem ipsum generation:' block.settings.loremipsum_block: type: block_settings label: 'Lorem ipsum block' mapping: loremipsum_block_settings: type: text label: 'Lorem ipsum block settings'
Het schema-bestand wordt gebruikt, zelfs als je geen aangepaste tabel voor je module definieert – hier kun je de standaardwaarden zien die aan de configuratieformuliervelden worden toegewezen.
Toen ik deze code ontwikkelde, ontdekte ik dat het vooraf invullen van velden “out of the box” een van de moeilijkste taken was. Maar gelukkig is er een module voor: Config Inspector voor Drupal 8, die je helpt bij het debuggen van de standaardinstellingen.
Bovendien is het YML-schema-bestand erg handig op veel manieren.
/src/Controller/LoremIpsumController.php
<?php namespace Drupal\loremipsum\Controller; // Change following https://www.drupal.org/node/2457593 // See https://www.drupal.org/node/2549395 for deprecate methods information // use Drupal\Component\Utility\SafeMarkup; use Drupal\Component\Utility\Html; // use Html instead SAfeMarkup /** * Controller routines for Lorem ipsum pages. */ class LoremIpsumController { /** * Constructs Lorem ipsum text with arguments. * This callback is mapped to the path * 'loremipsum/generate/{paragraphs}/{phrases}'. * * @param string $paragraphs * The amount of paragraphs that need to be generated. * @param string $phrases * The maximum amount of phrases that can be generated inside a paragraph. */ public function generate($paragraphs, $phrases) {
We zijn nu bij de kern van deze module, de klasse met een enkele methode die de placeholdertekst genereert. Zoals je ziet, verwijst de methode die binnen de klasse LoremIpsumController
wordt gegenereerd naar de vermelding in het YML-routingbestand:
In het witte kader staat de code van het bestand: loremipsum.routing.yml
en de achtergrond is het bestand waar we mee werken.
Laten we nu doorgaan, het volgende codefragment haalt de instellingen van de module op en slaat ze op voor verder gebruik:
// Default settings. $config = \Drupal::config('loremipsum.settings'); // Page title and source text. $page_title = $config->get('loremipsum.page_title'); $source_text = $config->get('loremipsum.source_text');
De hierboven opgegeven parameters (loremipsum.page_title
en loremipsum.source_text
) worden gehaald uit het YAML-configuratiebestand:
Daarna splitsen we de zinnen uit $source_text
in een array:
$repertory = explode(PHP_EOL, $source_text);
En we gebruiken die array om paragrafen tekst te genereren:
$element['#source_text'] = array(); // Generate X paragraphs with up to Y phrases each. for ($i = 1; $i <= $paragraphs; $i++) { $this_paragraph = ''; // When we say "up to Y phrases each", we can't mean "from 1 to Y". // So we go from halfway up. $random_phrases = mt_rand(round($phrases / 2), $phrases); // Also don't repeat the last phrase. $last_number = 0; $next_number = 0; for ($j = 1; $j <= $random_phrases; $j++) { do { $next_number = floor(mt_rand(0, count($repertory) - 1)); } while ($next_number === $last_number && count($repertory) > 1); $this_paragraph .= $repertory[$next_number] . ' '; $last_number = $next_number; } //$element['#source_text'][] = SafeMarkup::checkPlain($this_paragraph); $element['#source_text'][] = Html::escape($this_paragraph); }
Merk op dat ['#source_text']
een render-array is die aan de template wordt doorgegeven, en dat elk element in die array door Html::escape()
gaat voor veiligheid.
Tot slot geven we onze render-array een titel, wijzen we een themfunctie toe en geven we deze terug:
//$element['#title'] = SafeMarkup::checkPlain($page_title); $element['#title'] = Html::escape($page_title); // Theme function. $element['#theme'] = 'loremipsum'; return $element; } }
Maar voordat we deze variabele aan onze template doorgeven, moeten we daar nog voor zorgen.
Volgende stap:
Theming van de module.
Daarna:
Een instellingenformulier toevoegen.
Een blok definiëren voor deze module.
Tests schrijven voor deze module.