Struttura di base di un modulo Drupal
Parte II della guida pratica alla creazione di moduli base in Drupal 8
Dallo .info ai test, solo le basi
Struttura di base
loremipsum.info.yml
name: Lorem ipsum type: module description: 'Generatore di Lorem ipsum per Drupal' package: Development core: 8.x configure: loremipsum.form
I file info sono ora formattati come YML, e c’è differenza tra moduli e temi, che deve essere chiara tramite la dichiarazione del tipo. La dichiarazione config punta a una rotta (ne parleremo più avanti), ma a parte questo non c’è nient’altro. In effetti, questo è l’unico file di cui avrai bisogno per il tuo modulo. Dopo averlo salvato (nella cartella root/modules) puoi attivare il tuo modulo in /admin/modules senza rompere il tuo sito. Ma, come vedrai dopo, non è sufficiente.
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>Generatore di Lorem ipsum per Drupal.</h2> <h3>Istruzioni</h3> <p>Lorem ipsum dolor sit amet... <strong>Scherzo!</strong></p> <p>Estrai nella cartella <em>modules</em> (attualmente nella root della tua installazione Drupal 8) e abilita in <strong>/admin/modules</strong>.</p> <p>Poi, visita <strong>/admin/config/development/loremipsum</strong> ed inserisci il tuo set di frasi per costruire testo generato casualmente (oppure utilizza il Lorem ipsum predefinito).</p> <p>Infine, visita <strong>www.example.com/loremipsum/generate/P/S</strong> dove:</p> <ul> <li><em>P</em> è il numero di <em>paragrafi</em></li> <li><em>S</em> è il numero massimo di <em>frasi</em></li> </ul> <p>C’è anche un blocco generatore in cui puoi scegliere quanti paragrafi e frasi generare e farà il resto.</p> <p>Se necessario, esiste anche un permesso specifico <em>generate lorem ipsum</em>.</p> <h3>Attenzione</h3> <p>La maggior parte dei bug è stata risolta, le falle coperte, nuove funzioni aggiunte. Ma questo modulo è ancora in lavorazione. Per favore segnala bug e suggerimenti, ok?</p> '); } }
È buona pratica inserire qui almeno una chiamata a hook_help(). Nota anche l’istruzione use che punta alla classe RouteMatchInterface. Questo principalmente perché hook_menu() non esiste più.
... E man mano che andrai avanti, noterai che il file .module verrà usato anche per memorizzare informazioni di theming. Quindi tienilo.
loremipsum.install
<?php /** * @file * Funzioni di installazione per il modulo Lorem ipsum. */ use Drupal\user\RoleInterface; /** * Implements hook_install(). */ function loremipsum_install() { user_role_change_permissions(RoleInterface::ANONYMOUS_ID, array( 'generate lorem ipsum' => TRUE, )); }
Qui usiamo un’altra classe: RoleInterface. In sostanza, questo file dice a Drupal: «non appena questo modulo è abilitato, trova il permesso per generare lorem ipsum e attivalo».
Ma dove viene definito questo permesso?
loremipsum.permissions.yml
generate lorem ipsum: title: 'Generate Lorem ipsum'
Come puoi vedere, è molto più semplice della chiamata a hook_permission(). La sintassi completa si trova nella documentazione di 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: 'Impostazioni Lorem ipsum' requirements: _permission: 'administer site configuration'
Il file di routing sostituisce la chiamata a hook_menu(). Ogni voce (senza rientro) punta a una rotta, con le linee successive indentate che dettagliano impostazioni specifiche.
La rotta loremipsum.generate punta a una pagina che accetta due argomenti tra {}; essa corrisponde a un controller (ne parleremo più avanti), al contrario di loremipsum.form, che punta a un form (di configurazione) con un titolo.
Entrambe le rotte richiedono permessi, ma puoi sostituirli con _access: 'TRUE' per accesso illimitato.
loremipsum.services.yml
Permette di dichiarare un servizio personalizzato.
loremipsum.links.menu.yml
loremipsum.form: title: 'Impostazioni Lorem Ipsum' description: 'Configura le impostazioni per il modulo Lorem Ipsum.' route_name: loremipsum.form parent: 'system.admin_config_development'
Se il file di routing crea la pagina in /admin/config/development/loremipsum, queste definizioni sono necessarie per aggiungere le pagine nel menu di Amministrazione.
loremipsum.links.task.yml
Definizioni per creare ulteriori attività locali (schede) per una determinata rotta.
loremipsum.links.action.yml
Definizioni per creare ulteriori azioni locali (bottoni) per una determinata rotta.
loremipsum.links.contextual.yml
Definizioni per creare ulteriori azioni contestuali per un determinato elemento dell’interfaccia utente.
loremipsum.libraries.yml
Usato per dichiarare dipendenze per librerie CSS e Javascript. Maggiori dettagli nella sezione corrispondente.
README.md
Estrai nella cartella *modules* (attualmente nella root della tua installazione di Drupal 8) e abilita in `/admin/modules`.
Poi vai su `/admin/config/development/loremipsum` e inserisci il tuo set di
frasi per costruire testo generato casualmente (o usa il Lorem ipsum predefinito).
Infine, visita `www.example.com/loremipsum/generate/P/S`, dove:
- *P* è il numero di *paragrafi*
- *S* è il numero massimo di *frasi*
C’è anche un blocco generatore, in cui puoi scegliere quanti paragrafi e
frasi generare, e farà tutto il resto.
Se necessario, esiste anche un permesso specifico *generate lorem ipsum*.
Attenzione
---------
La maggior parte degli errori è stata corretta, le falle chiuse, nuove funzionalità aggiunte. Ma questo modulo è ancora in fase di sviluppo. Per favore segnala bug e suggerimenti, va bene?
Sì, i file README ora sono scritti in formato Markdown. Abbastanza figo, se me lo chiedi.
Ora addentriamoci nelle cartelle per un’analisi più dettagliata dei singoli elementi.
LICENSE.TXT
Non includere il file LICENSE.txt (o simile). Lo script di packaging lo aggiungerà automaticamente.
/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 rappresentazione in curl velit esse cillum dolore eu fugiat nulla pariatur. \nExcepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est labour."
Questo file memorizza le impostazioni predefinite che vengono assegnate ai campi corretti tramite il file seguente:
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. "
Questo file memorizza le impostazioni predefinite che vengono assegnate ai campi corretti tramite il file seguente:
/config/schema/loremipsum.schema.yml
loremipsum.settings: type: config_object label: 'Impostazioni Lorem Ipsum' mapping: loremipsum: type: mapping mapping: page_title: type: text label: 'Titolo della pagina del generatore Lorem ipsum:' source_text: type: text label: 'Testo sorgente per la generazione di lorem ipsum:' block.settings.loremipsum_block: type: block_settings label: 'Blocco Lorem ipsum' mapping: loremipsum_block_settings: type: text label: 'Impostazioni del blocco Lorem ipsum'
Il file di schema viene usato anche se non definisci una tabella personalizzata per il tuo modulo – qui puoi vedere i valori predefiniti assegnati ai campi del form di configurazione.
Durante lo sviluppo di questo codice ho scoperto che il popolamento dei campi “out of the box” era una delle attività più difficili. Ma fortunatamente c’è un modulo per questo: Config Inspector per Drupal 8, che ti aiuterà a fare debug delle impostazioni predefinite.
Inoltre, il file di schema YML è molto utile in molti modi.
/src/Controller/LoremIpsumController.php
<?php namespace Drupal\loremipsum\Controller; // Cambiamenti seguendo https://www.drupal.org/node/2457593 // Vedi https://www.drupal.org/node/2549395 per informazioni sui metodi deprecati // use Drupal\Component\Utility\SafeMarkup; use Drupal\Component\Utility\Html; // usa Html invece di SafeMarkup /** * Routine di controller per le pagine Lorem ipsum. */ class LoremIpsumController { /** * Costruisce testo Lorem ipsum con argomenti. * Questo callback è mappato al percorso * 'loremipsum/generate/{paragraphs}/{phrases}'. * * @param string $paragraphs * Il numero di paragrafi che devono essere generati. * @param string $phrases * Il numero massimo di frasi che possono essere generate in un paragrafo. */ public function generate($paragraphs, $phrases) {
Siamo arrivati al cuore di questo modulo, una classe con un unico metodo che genera testo segnaposto. Come puoi vedere, il metodo generato all’interno della classe LoremIpsumController corrisponde a una voce nel file di routing YML:
Nella cornice bianca è mostrato il codice del file: loremipsum.routing.yml e sullo sfondo il file con cui stiamo lavorando.
Ora proseguiamo: il frammento di codice seguente ottiene le impostazioni del modulo e le memorizza per un uso successivo:
// Impostazioni predefinite. $config = \Drupal::config('loremipsum.settings'); // Titolo pagina e testo sorgente. $page_title = $config->get('loremipsum.page_title'); $source_text = $config->get('loremipsum.source_text');
I parametri sopra (loremipsum.page_title e loremipsum.source_text) sono presi dal file di configurazione YAML:
Poi dividiamo le frasi da $source_text in un array:
$repertory = explode(PHP_EOL, $source_text);
E usiamo questo array per costruire paragrafi di testo:
$element['#source_text'] = array(); // Genera X paragrafi con fino a Y frasi ciascuno. for ($i = 1; $i <= $paragraphs; $i++) { $this_paragraph = ''; // Quando diciamo "fino a Y frasi", non possiamo intendere "da 1 a Y". // Quindi andiamo da metà fino a Y. $random_phrases = mt_rand(round($phrases / 2), $phrases); // Inoltre non ripetere l’ultima frase. $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); }
Nota che ['#source_text'] è un array di rendering passato al template, e che ogni elemento in questo array passa attraverso Html::escape() per sicurezza.
Infine, diamo al nostro array di rendering un titolo, assegniamo la funzione di tema e lo restituiamo:
//$element['#title'] = SafeMarkup::checkPlain($page_title); $element['#title'] = Html::escape($page_title); // Funzione di tema. $element['#theme'] = 'loremipsum'; return $element; } }
Ma prima di passare questa variabile al nostro template, dobbiamo occuparcene.
Prossimo passo:
Theming del modulo.
A seguire:
Aggiungere un form di configurazione.
Definire un blocco per questo modulo.
Scrivere test per questo modulo.