Utilizzo ed estensione dell'API Drupal 8 Mail parte 2

Nel precedente articolo abbiamo visto come possiamo inviare e-mail in modo programmatico in Drupal 8. Abbiamo anche visto come altri moduli possono alterare questi messaggi in uscita. Oggi esamineremo come utilizzare l'API Mail per estendere questo comportamento predefinito. Lo scopo è utilizzare un servizio esterno come mezzo per l'invio di e-mail. 

Per questo, useremo Mandrill, sebbene il focus dell'articolo non sia la sua API o il modo di lavorarci, ma piuttosto il lato Drupal delle cose. E ricorda, il modulo di lavoro può essere trovato in questo repository Git.

Come abbiamo visto nel precedente articolo, l'invio di una email in Drupal 8 avviene richiedendo al gestore della posta, passando alcuni parametri al suo mail () metodo e impostazione a modello dentro a hook_mail () implementazione. Ciò che il gestore di posta esegue internamente è caricare il plugin di posta appropriato, costruire l'email e quindi delegare a mail () metodo di qualunque plugin è stato caricato.

Ma a chi in realtà delegano?

Selezione del plugin

Una cosa importante da capire prima di scrivere il nostro plugin è il processo di selezione del mail manager per il caricamento dei plugin. In altre parole, come facciamo a sapere quale plug-in caricherà e come possiamo caricarlo da soli?

Il system.mail.interface l'array di configurazione contiene tutte le risposte. Contiene gli ID dei plug-in disponibili, immessi nel contesto in cui sono utilizzati. Per impostazione predefinita, tutto ciò che abbiamo all'interno di questa configurazione è default => phpmail. Ciò significa che il plugin con l'id phpmail (la classe PHPMail) viene utilizzata come fallback per tutti i contesti che non sono specificati altrimenti, ovvero il valore predefinito.

Se vogliamo scrivere il nostro plugin, dobbiamo aggiungere un altro elemento a quell'array con l'id del plugin come valore. La chiave per questo valore può essere una delle due cose: il nome della macchina del nostro modulo (per caricare il plugin ogni volta che il nostro modulo invia e-mail) o una combinazione di nome del modulo ed e-mail modello chiave (per caricare il plugin ogni volta che il nostro modulo invia un'email usando quella chiave specifica). 

Un esempio di quest'ultimo costrutto è d8mail_node_insert, dove d8mail è il nome del nostro modulo che abbiamo iniziato a costruire nell'articolo precedente, e node_insert è l'email modello chiave che abbiamo definito.

Quindi, ora che sappiamo come avviene la selezione del plug-in di posta, dobbiamo assicurarci che questo array di config contenga le informazioni necessarie in modo che le e-mail inviate con il nostro d8mail modulo usa il nuovo plugin che costruiremo. Possiamo farlo all'interno di un'implementazione hook_install () che viene attivata una sola volta quando viene installato il modulo:

d8mail.install:

/ ** * Implementa hook_install (). * / function d8mail_install () $ config = \ Drupal :: configFactory () -> getEditable ('system.mail'); $ mail_plugins = $ config-> get ('interfaccia'); if (in_array ('d8mail', array_keys ($ mail_plugins))) return;  $ mail_plugins ['d8mail'] = 'mandrill_mail'; $ config-> set ('interfaccia', $ mail_plugins) -> save ();  

Non è super complicato quello che succede sopra. Carichiamo l'oggetto di configurazione modificabile che rappresenta il system.mail configurazione e aggiungere un nuovo elemento al interfaccia array: d8mail => mandrill_mail. Presto creeremo un plugin per la posta con l'id di mandrill_mail che verrà utilizzato per tutte le e-mail inviate da d8mail modulo. E questo è tutto.

Ma prima di andare avanti, dobbiamo assicurarci che questa modifica venga ripristinata quando il modulo viene disinstallato. Per questo, possiamo usare la controparte hook_uninstall () che viene chiamata quando un modulo viene disinstallato (non c'è più disattivazione del modulo in Drupal 8).

All'interno dello stesso file:

/ ** * Implementa hook_uninstall (). * / function d8mail_uninstall () $ config = \ Drupal :: configFactory () -> getEditable ('system.mail'); $ mail_plugins = $ config-> get ('interfaccia'); if (! in_array ('d8mail', array_keys ($ mail_plugins))) return;  unset ($ mail_plugins ['d8mail']); $ config-> set ('interfaccia', $ mail_plugins) -> save ();  

Con il hook_uninstall () implementazione facciamo l'opposto di prima: rimuoviamo il nostro id del plugin se è impostato.

Lo scenario di installazione / disinstallazione è solo un modo per andare. È inoltre possibile creare un modulo di amministrazione che consente agli utenti di selezionare il plug-in desiderato e in quale contesto. Ma devi ancora assicurarti che quando disabiliti il ​​modulo che definisce un particolare plugin, la configurazione non manterrà più un riferimento a quel plugin. In caso contrario, il gestore della posta potrebbe tentare di utilizzare una classe inesistente e generare tutti i tipi di errori.

Mandrillo

Come ho detto prima, lavoreremo con l'API Mandrill per illustrare il nostro compito. Quindi cariciamo la libreria PHP di Mandrill e rendiamola disponibile nel nostro ambiente. Ci sono tre passaggi che dobbiamo fare per questo.

Per prima cosa, dobbiamo effettivamente ottenere la libreria all'interno di Drupal. Al momento della stesura di questo, in pratica significa aggiungere il "mandrill / mandrill": "1.0. *" dipendenza dalla radice composer.json file e in esecuzione installazione di compositore. Tieni presente, tuttavia, che questo eliminerà anche l'installazione di Drupal dall'interno nucleo/ cartella e scarica invece l'ultima versione stabile. Quindi, dovrai modificare la root index.php file e cambiare il percorso del caricatore automatico come da queste istruzioni. Speriamo che questa ultima azione non sia necessaria a breve, e ti incoraggio a seguire le discussioni sul futuro di Composer in Drupal 8 per la gestione delle librerie esterne.

Secondo, dobbiamo ottenere una chiave API da Mandrill. Fortunatamente, questo possiamo facilmente generare dalle loro pagine di amministrazione. Una volta ottenuto ciò, possiamo memorizzarlo all'interno di un nuovo file creato sul nostro server, in entrambe le posizioni:

~ / .mandrill.key /etc/mandrill.key 

Possiamo anche passare la chiave come parametro costruttore al main Mandrillo classe, ma in questo modo non dovremo hardcode nel nostro codice. 

In terzo luogo, dobbiamo creare un servizio in modo che possiamo usare l'iniezione di dipendenza per passare il Mandrillo classe nel nostro plugin:

d8mail.services.yml:

servizi: d8mail.mandrill: class: Mandrill 

A seconda di come hai caricato il file Mandrillo class nella tua applicazione, dovrai cambiare il valore dopo classe. Usando il composer.json approccio, questo sarà sufficiente.

Il plugin di posta

È finalmente il momento di creare il nostro plugin. In Drupal 8, le classi di plugin entrano nel src / Plugin cartella del nostro modulo. A seconda del tipo, tuttavia, sono collocati più in basso all'interno di altre directory (nel nostro caso posta). Scriviamo la nostra classe che dipenderà dalla libreria API Mandrill per inviare e-mail:

src / Plugin / Mail / MandrillMail.php:

mandrill = $ mandrill;  / ** * @inheritdoc * / public static function create (ContainerInterface $ container, array $ configuration, $ plugin_id, $ plugin_definition) return new static ($ container-> get ('d8mail.mandrill'));  / ** * @inheritdoc * / formato funzione pubblica (array $ message) // Unisci l'array body in una stringa. $ message ['body'] = implode ("\ n \ n", $ message ['body']); // Converti qualsiasi HTML in testo semplice. $ message ['body'] = MailFormatHelper :: htmlToText ($ message ['body']); // Avvolge il corpo della posta per l'invio. $ message ['body'] = MailFormatHelper :: wrapMail ($ message ['body']); return $ message;  / ** * @inheritdoc * / public function mail (array $ message) try $ vars = ['html' => $ message ['body'], 'subject' => $ message ['subject' ], 'from_email' => $ message ['from'], 'a' => array (array ('email' => $ message ['a'])),]; $ result = $ this-> mandrill-> messages-> send ($ vars); if ($ result [0] ['status']! == 'inviato') return false;  return $ result;  catch (Mandrill_Error $ e) return false;  

Ci sono un paio di cose da notare prima di entrare in quello che fa la classe.

Innanzitutto, le annotazioni sopra la classe. Questo è solo il meccanismo di scoperta dei plugin più comune per Drupal 8. Il id la chiave corrisponde al valore aggiunto al system.mail.interface array di configurazione in precedenza, mentre il resto sono elementi di definizione del plugin di base.

In secondo luogo, l'attuazione del ContainerFactoryPluginInterface interfaccia con cui definiamo il creare() metodo. Quest'ultimo fa parte del processo di iniezione delle dipendenze mediante il quale possiamo caricare il servizio Mandrill che abbiamo definito nel services.yml file precedente. Ciò rende il test molto più semplice ed è considerato una buona pratica.

Come ho già detto, i plugin di posta devono implementare il MailInterface interfaccia che rafforza l'esistenza del formato() e mail () metodi. Nel nostro caso, il primo fa esattamente la stessa cosa del PHPMail plugin: un po 'di elaborazione del corpo del messaggio. Quindi puoi aggiungere la tua logica qui se vuoi. Quest'ultimo metodo, d'altra parte, è responsabile dell'invio della posta, nel nostro caso, utilizzando l'API Mandrill stessa.

Come indicato dalla documentazione Mandrill, costruiamo un messaggio e-mail all'interno di $ vars array usando i valori passati dal gestore di posta attraverso il $ messaggio parametro. Questi saranno già filtrati hook_mail (), hook_mail_alter () e il plugin stesso formato() metodo. Tutto ciò che rimane è di inviare effettivamente l'email. Non entrerò nei dettagli dell'utilizzo dell'API Mandrill, poiché è possibile consultare la documentazione per tutte le opzioni che è possibile utilizzare.

Dopo aver inviato l'e-mail e tornare da Mandrill a inviato stato, restituiamo l'intero array di risposta, che contiene ulteriori informazioni. Questo array viene quindi aggiunto dal gestore di posta al proprio array di restituzione digitato come risultato. Se Mandrill ha un problema, rifiuta l'e-mail o genera un'eccezione, torniamo falso. Questo farà sì che il gestore della posta gestisca questa situazione registrando l'incidente e stampando un messaggio di stato.

E questo è praticamente tutto. Possiamo svuotare la cache e provare a creare un altro nodo dell'articolo. Questa volta, l'e-mail di notifica dovrebbe essere inviata da Mandrill anziché da PHP mail (). Con questo al posto, però, il hook_mail_alter () l'implementazione è diventata superflua in quanto non ci sono intestazioni che stiamo mandando a Mandrill (e il testo è già HTML). E per quel che riguarda il lavoro del gestore della posta non viene usato molto, dato che non lo passiamo a Mandrill. Ma questo è solo un modo per illustrare il processo di come si può fare per impostare questo. I dettagli dell'implementazione rimangono a te e alle tue esigenze.

Conclusione

E lì ce l'abbiamo. Abbiamo implementato il nostro plugin di posta per essere utilizzato da d8module abbiamo iniziato nel precedente articolo. E a causa della natura estensibile di Drupal 8, non ha nemmeno preso troppo impegno. 

Ciò che resta da fare è perfezionare la logica di invio della posta e adattarla alle circostanze. Questo può significare un'ulteriore integrazione tra Mandrill e l'istanza Drupal, costruendo simpatici modelli o cosa hai. Inoltre, un'importante attività rimanente è la scrittura di test automatici per questa funzionalità. E Drupal 8 offre abbastanza strumenti per questo.