Gebruik en uitbreiding van de Drupal 8 Mail API deel 2

In het vorige artikel hebben we gekeken hoe we e-mails programmatisch kunnen verzenden in Drupal 8. We hebben ook gezien hoe andere modules deze uitgaande e-mails kunnen wijzigen. Vandaag gaan we bekijken hoe we de Mail API kunnen gebruiken om dit standaardgedrag uit te breiden. Het doel is om een ​​externe service te gebruiken als middel voor e-mailbezorging. 

Hiervoor zullen we Mandrill gebruiken, hoewel de focus van het artikel niet de API zal zijn of hoe ermee te werken, maar eerder de Drupal-kant van de dingen. En vergeet niet dat de werkmodule te vinden is in deze Git-repository.

Zoals we in het vorige artikel hebben gezien, gebeurt het verzenden van een e-mail in Drupal 8 door de e-mailbeheerder te vragen, een aantal parameters door te geven aan de mail() methode, en opzetten van een sjabloon in een hook_mail () implementatie. Wat de mailmanager intern doet, is de juiste e-mailplug-in laden, de e-mail samenstellen en vervolgens delegeren naar de mail() methode van welke plug-in is geladen.

Maar aan wie delegeert het eigenlijk??

Selectie van plug-in

Belangrijk om te begrijpen voordat u onze eigen plug-in schrijft, is het selectieproces van de e-mailbeheerder voor het laden van plug-ins. Met andere woorden, hoe weten we welke plug-in het zal laden en hoe kunnen we het laten laden?

De system.mail.interface configuratie-array bevat alle antwoorden. Het bevat de id's van de beschikbare plug-ins, ingetoetst door de context waarin ze worden gebruikt. Standaard is alles wat we in deze configuratie hebben standaard => phpmail. Dit betekent dat de plug-in met de id phpmail (de PHPMail-klasse) wordt gebruikt als fallback voor alle contexten die niet op andere wijze zijn opgegeven, d.w.z. de standaard.

Als we onze eigen plug-in willen schrijven, moeten we een ander element toevoegen aan die array met de plugin-id als waarde. De sleutel voor deze waarde kan een van twee dingen zijn: de machinenaam van onze module (om de plug-in te laden wanneer onze module e-mails verzendt) of een combinatie van modulenaam en e-mail sjabloon sleutel (om de plug-in te laden wanneer onze module een e-mail verzendt met die specifieke sleutel). 

Een voorbeeld van de laatstgenoemde constructie is d8mail_node_insert, waar d8mail is onze modulenaam die we begonnen te bouwen in het vorige artikel, en node_insert is de e-mail sjabloon sleutel die we hebben gedefinieerd.

Dus nu we weten hoe de selectie van mailpluggen gebeurt, moeten we ervoor zorgen dat deze configuratie-array de nodige informatie bevat zodat e-mails die met onze d8mail module gebruiken de nieuwe plugin die we zullen bouwen. We kunnen dit doen binnen een hook_install () -implementatie die maar één keer wordt geactiveerd wanneer de module wordt geïnstalleerd:

d8mail.install:

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

Niet super ingewikkeld wat hierboven gebeurt. We laden het bewerkbare configuratieobject dat de vertegenwoordigt system.mail configuratie en voeg een nieuw element toe aan de interface array: d8mail => mandrill_mail. Binnenkort maken we een e-mailplug-in met de id van mandrill_mail die zal worden gebruikt voor alle e-mails verzonden door de d8mail module. En dat is het.

Maar voordat we verder gaan, moeten we ervoor zorgen dat deze wijziging wordt teruggedraaid wanneer de module wordt verwijderd. Hiervoor kunnen we de counterpart hook_uninstall () gebruiken die wordt aangeroepen wanneer een module wordt verwijderd (er is geen module meer uitgeschakeld in Drupal 8).

Binnen hetzelfde bestand:

/ ** * Implementeert hook_uninstall (). * / function d8mail_uninstall () $ config = \ Drupal :: configFactory () -> getEditable ('system.mail'); $ mail_plugins = $ config-> get ('interface'); if (! in_array ('d8mail', array_keys ($ mail_plugins))) ga terug;  niet ingesteld ($ mail_plugins ['d8mail']); $ config-> set ('interface', $ mail_plugins) -> save ();  

Met de hook_uninstall () implementatie doen we het tegenovergestelde van voorheen: we verwijderen onze plugin-ID als deze is ingesteld.

Het scenario voor installeren / de-installeren is maar één manier. U kunt ook een beheerformulier maken waarmee gebruikers de gewenste plug-in en onder welke context kunnen selecteren. Maar u moet er nog steeds voor zorgen dat wanneer u de module uitschakelt die een bepaalde plug-in definieert, de configuratie niet langer een verwijzing naar die plug-in blijft houden. Anders probeert de mailbeheerder een niet-bestaande klasse te gebruiken en allerlei soorten fouten te gooien.

noordafrikaanse baviaan

Zoals ik eerder al zei, zullen we werken met de Mandrill API om onze taak te illustreren. Dus laten we de PHP-bibliotheek van Mandrill laden en beschikbaar maken in onze omgeving. Daar zijn drie stappen voor nodig.

Ten eerste moeten we de bibliotheek daadwerkelijk binnen Drupal krijgen. Op het moment van schrijven betekent dit in feite het toevoegen van de "mandrill / mandrill": "1.0. *" afhankelijkheid van de root composer.json bestand en actief componist installeren. Houd er echter rekening mee dat hiermee ook de Drupal-installatie wordt gewist vanuit de binnenkant van de kern/ map en download de nieuwste stabiele versie in plaats daarvan. Vervolgens moet u de root bewerken index.php bestand en verander het pad naar de autoloader volgens deze instructies. Hopelijk zal deze laatste actie niet snel nodig zijn en ik moedig je aan om de discussies over de toekomst van Composer in Drupal 8 te volgen voor het beheren van externe bibliotheken.

Ten tweede moeten we een API-sleutel van Mandrill krijgen. Gelukkig kunnen we dit eenvoudig genereren op hun administratiepagina's. Zodra we dat hebben, kunnen we het op te slaan in een nieuw bestand gemaakt op onze server, op beide locaties:

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

We kunnen de sleutel ook doorgeven als een constructorparameter naar de main noordafrikaanse baviaan klasse, maar op deze manier hoeven we het niet in onze code te coderen. 

Ten derde moeten we een service maken zodat we afhankelijkheidsinjectie kunnen gebruiken voor het doorgeven van de noordafrikaanse baviaan klasse in onze plug-in:

d8mail.services.yml:

services: d8mail.mandrill: class: Mandrill 

Afhankelijk van hoe u de noordafrikaanse baviaan klasse in uw toepassing, moet u de waarde daarna wijzigen klasse. Door de composer.json aanpak, dit is voldoende.

De Mail-plugin

Het is eindelijk tijd om onze plug-in te maken. In Drupal 8 gaan plugin classes naar de src / Plugin map van onze module. Afhankelijk van hun type worden ze echter verder naar beneden geplaatst in andere mappen (in ons geval Mail). Laten we onze klasse schrijven die afhankelijk is van de Mandrill API-bibliotheek om e-mails te verzenden:

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 * / openbare functie-indeling (array $ -bericht) // Voeg de body-array samen in één tekenreeks. $ message ['body'] = implode ("\ n \ n", $ message ['body']); // Converteer alle HTML naar platte tekst. $ message ['body'] = MailFormatHelper :: htmlToText ($ message ['body']); // Wikkel het poststuk voor verzending. $ message ['body'] = MailFormatHelper :: wrapMail ($ message ['body']); return $ bericht;  / ** * @inheritdoc * / public function mail (array $ message) try $ vars = ['html' => $ message ['body'], 'subject' => $ message ['subject' ], 'from_email' => $ message ['from'], 'to' => array (array ('email' => $ message ['to'])),]; $ result = $ this-> mandrill-> messages-> send ($ vars); if ($ result [0] ['status']! == 'sent') return false;  return $ resultaat;  catch (Mandrill_Error $ e) return false;  

Er zijn een paar dingen om op te letten voordat je ingaat op wat de klas doet.

Eerst de annotaties boven de klas. Dit is slechts het meest voorkomende mechanisme voor het ontdekken van plug-ins voor Drupal 8. Het ID kaart sleutel komt overeen met de waarde die we hebben toegevoegd aan de system.mail.interface configuratie-array eerder, terwijl de rest basisdefinitie-elementen voor plug-ins zijn.

Ten tweede, de implementatie van de ContainerFactoryPluginInterface interface waarmee we het definiëren create () methode. Dit laatste maakt deel uit van het injectieproces voor afhankelijkheid waarmee we de Mandrill-service kunnen laden die we hebben gedefinieerd in de services.yml bestand eerder. Dit maakt testen veel eenvoudiger en het wordt als de beste methode beschouwd.

Zoals ik al zei, moeten de mailplug-ins het MailInterface interface die het bestaan ​​van de formaat() en mail() methoden. In ons geval doet de eerste precies hetzelfde als de PHPMail plugin: een beetje verwerking van de berichttekst. Dus je kunt hier je eigen logica toevoegen als je wilt. De laatste methode is daarentegen verantwoordelijk voor het verzenden van de mail, in ons geval, met behulp van de Mandrill-API zelf.

Zoals de documentatie van Mandrill aangeeft, construeren we een e-mailbericht binnen de $ vars array met waarden die zijn doorgegeven vanuit de e-mailbeheerder via de $ message parameter. Deze worden al gefilterd hook_mail (), hook_mail_alter () en de plug-in's eigen formaat() methode. Het enige dat overblijft is om de e-mail daadwerkelijk te verzenden. Ik zal niet ingaan op de details van het gebruik van de Mandrill API, aangezien u de documentatie kunt raadplegen voor alle opties die u kunt gebruiken.

Na het verzenden van de e-mail en het terugkomen van Mandrill a verzonden status retourneren we de volledige responsarray, die wat meer informatie bevat. Deze array wordt vervolgens door de e-mailbeheerder toegevoegd aan zijn eigen retourarray die is gecodeerd als resultaat. Als Mandrill een probleem heeft, de e-mail weigert of een uitzondering genereert, keren we terug vals. Hierdoor zal de mailmanager deze situatie verwerken door het incident te loggen en een statusbericht af te drukken.

En dat is zo ongeveer het. We kunnen de cache leegmaken en proberen een ander artikelknooppunt te maken. Deze keer zou de notificatie-e-mail moeten worden verzonden door Mandrill in plaats van PHP's mail(). Met dit op zijn plaats echter, de hook_mail_alter () implementatie is overbodig geworden omdat er geen kopteksten zijn die we daadwerkelijk doorsturen naar Mandrill (en de tekst is al HTML). En trouwens, nogal wat werk van de mailmanager wordt niet gebruikt, omdat we dat niet doorgeven aan Mandrill. Maar dit is slechts bedoeld om het proces te illustreren van hoe u dit kunt regelen. De details van de implementatie blijven aan u en uw behoeften.

Conclusie

En daar hebben we het. We hebben onze eigen mail plug-in geïmplementeerd om te gebruiken door de d8module we zijn begonnen in het vorige artikel. En vanwege de uitbreidbaarheid van Drupal 8 kostte het niet eens veel moeite. 

Het enige dat u nog moet doen, is het perfectioneren van de logica voor het verzenden van e-mails en deze aanpassen aan uw omstandigheden. Dit kan een verdere integratie tussen Mandrill en uw Drupal-instantie betekenen, het bouwen van mooie sjablonen of wat heeft u. Bovendien is een belangrijke resterende taak het schrijven van geautomatiseerde tests voor deze functionaliteit. En Drupal 8 biedt daar ook de toolkit voor.