Använda och förlänga Drupal 8 Mail API Del 2

I den föregående artikeln såg vi på hur vi kan skicka e-postprogrammatiskt i Drupal 8. Vi såg också hur andra moduler kan ändra dessa utgående mail. Idag ska vi titta på hur vi kan använda Mail API för att förlänga detta standardbeteende. Syftet är att använda en extern tjänst som ett medel för leverans av e-post. 

För detta kommer vi att använda Mandrill, även om artikelns fokus inte kommer att vara dess API eller hur man arbetar med det, utan snarare Drupals sida av saker. Och kom ihåg att arbetsmodulen finns i det här Git-arkivet.

Som vi har sett i den föregående artikeln sker skicka ett e-postmeddelande i Drupal 8 genom att be om brevhanteraren, och överföra några parametrar till dess post() metod och konfigurera en mall inuti a hook_mail () genomförande. Vad posthanteraren internt laddar upp det lämpliga mailprogrammet, konstruera e-postmeddelandet och delegera sedan till post() metod för vilken plugin som helst laddades.

Men vem deltar det faktiskt i?

Plugin Selection

En viktig sak att förstå innan du skriver vårt eget plugin är urvalsprocessen för posthanteraren för laddning av plugins. Med andra ord, hur vet vi vilket plugin det kommer att ladda, och hur kan vi få det att ladda våra egna?

De system.mail.interface konfigurationsmatrisen innehåller alla svaren. Den innehåller idsen för de tillgängliga pluginsna, inskriven av det sammanhang de används i. Som standard är allt vi har inom denna konfiguration default => phpmail. Det betyder att plugin med id phpmail (PHPMail-klassen) används som fallback för alla sammanhang som inte anges på annat sätt, dvs standardvärdet.

Om vi ​​vill skriva ett eget plugin måste vi lägga till ett annat element i den arrayen med plugin-id som dess värde. Nyckeln till detta värde kan vara en av två saker: maskinens namn på vår modul (för att ladda plugin när vår modul skickar e-postmeddelanden) eller en kombination av modulnamn och e-post mall nyckel (för att ladda plugin när vår modul skickar ett mail med den specifika nyckeln). 

Ett exempel på den senare konstruktionen är d8mail_node_insert, var d8mail är vårt modulnamn vi började bygga i föregående artikel och node_insert är e-posten mall nyckel vi definierade.

Så nu när vi vet hur valet av e-postinpluggar händer, måste vi se till att denna konfigurationsgrupp innehåller nödvändig information så att e-postmeddelanden som skickas med vår d8mail modul använda det nya plugin vi ska bygga. Vi kan göra detta inom en hook_install () implementering som utlöses en gång när modulen installeras:

d8mail.install:

/ ** * Implementerar hook_install (). * / funktion d8mail_install () $ config = \ Drupal :: configFactory () -> getEditable ('system.mail'); $ mail_plugins = $ config-> get ('interface'); om (in_array ('d8mail', array_keys ($ mail_plugins))) return;  $ mail_plugins ['d8mail'] = 'mandrill_mail'; $ config-> set ('interface', $ mail_plugins) -> spara ();  

Inte super komplicerat vad som händer ovan. Vi laddar det redigerbara konfigurationsobjektet som representerar system.mail konfiguration och lägg till ett nytt element i gränssnitt array: d8mail => mandrill_mail. Vi kommer snart att skapa ett mail-plugin med ID-numret mandrill_mail som kommer att användas för alla e-postmeddelanden som skickas av d8mail modul. Och det är allt.

Men innan vi går vidare måste vi se till att denna ändring återställs när modulen avinstalleras. För detta kan vi använda motparten hook_uninstall () som heter när en modul avinstalleras (det går inte att stänga av modulen i Drupal 8).

Inne i samma fil:

/ ** * Implementerar hook_uninstall (). * / funktion d8mail_uninstall () $ config = \ Drupal :: configFactory () -> getEditable ('system.mail'); $ mail_plugins = $ config-> get ('interface'); om (! in_array ('d8mail', array_keys ($ mail_plugins))) return;  unset ($ mail_plugins ['d8mail']); $ config-> set ('interface', $ mail_plugins) -> spara ();  

Med hook_uninstall () genomförande vi gör motsatt av tidigare: vi tar bort vårt plugin-id om det är inställt.

Installations- / avinstallationsscenariot är bara ett sätt att gå. Du kan också skapa en administrationsblankett som låter användarna välja det plugin de vill ha och under vilket sammanhang. Men du måste fortfarande se till att när du inaktiverar modulen som definierar ett visst plugin, kommer konfigurationen inte längre att innehålla en hänvisning till det plugin. Annars kan posthanteraren försöka använda en obefintlig klass och kasta alla typer av fel.

Mandrill

Som jag nämnde tidigare kommer vi att arbeta med Mandrill API för att illustrera vår uppgift. Så låt oss ladda upp Mandrills PHP-bibliotek och göra det tillgängligt i vår miljö. Det finns tre steg vi behöver göra för detta.

Först måste vi faktiskt få biblioteket inuti Drupal. I skrivande stund betyder detta i grunden att du lägger till "mandrill / mandrill": "1.0. *" beroende av roten composer.json fil och körning kompositör installera. Tänk på att detta också kommer att rensa Drupal-installationen inifrån kärna/ mapp och hämta den senaste stabila versionen istället. Då måste du redigera roten index.php fil och ändra sökvägen till autoloader enligt dessa instruktioner. Förhoppningsvis kommer den här sista åtgärden inte att vara nödvändig snart, och jag uppmanar dig att följa diskussionerna om kompositörens framtid i Drupal 8 för att hantera externa bibliotek.

För det andra måste vi få en API-nyckel från Mandrill. Lyckligtvis kan vi enkelt generera från deras administrationssidor. När vi har det kan vi lagra det inuti en ny fil som skapats på vår server, på endera platsen:

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

Vi kan också skicka nyckeln som en konstruktorparameter till huvudet Mandrill klass, men på så vis behöver vi inte koda det i vår kod. 

För det tredje måste vi skapa en tjänst så att vi kan använda beroendeinsprutning för att passera Mandrill klass i vårt plugin:

d8mail.services.yml:

tjänster: d8mail.mandrill: klass: Mandrill 

Beroende på hur du har laddat in Mandrill klass i din ansökan, måste du ändra värdet efter klass. Genom att använda composer.json tillvägagångssätt, detta kommer att räcka.

Postprogrammet

Det är äntligen dags att skapa vårt plugin. I Drupal 8 går pluginklasser inuti src / Plugin mapp på vår modul. Beroende på deras typ placeras de dock längre ner i andra kataloger (i vårt fall Post). Låt oss skriva vår klass som beror på Mandrill API-biblioteket för att skicka e-postmeddelanden:

src / Plugin / Mail / MandrillMail.php:

mandrill = $ mandrill;  / ** * @inheritdoc * / offentlig statisk funktion skapa (ContainerInterface $ container, array $ konfiguration, $ plugin_id, $ plugin_definition) returnera nya statiska ($ container-> get ('d8mail.mandrill'));  / ** * @inheritdoc * / public function format (array $ message) // Anslut kroppsuppsättningen till en sträng. $ meddelande ['body'] = implode ("\ n \ n", $ meddelande ['body']); // Konvertera HTML till vanlig text. $ meddelande ['body'] = MailFormatHelper :: htmlToText ($ message ['body']); // Vik postkroppen för att skicka. $ meddelande ['body'] = MailFormatHelper :: wrapMail ($ message ['body']); returnera $ message;  / ** * @inheritdoc * / public function mail (array $ message) försök $ vars = ['html' => $ meddelande ['body'], 'subject' => $ message ['subject' ], 'from_email' => $ meddelande ['från'], 'till' => array (array ('email' => $ meddelande ['till'])))]; $ result = $ this-> mandrill-> messages-> send ($ vars); om ($ resultat [0] ['status']! == 'skickat') return false;  returnera $ resultat;  fångst (Mandrill_Error $ e) return false;  

Det finns ett par saker att notera innan du kommer in i vad klassen gör.

Först, anteckningarna ovanför klassen. Detta är bara den vanligaste plugin upptäcktsmekanismen för Drupal 8. The id nyckeln matchar det värde vi lagt till i system.mail.interface konfigurationsmatris tidigare, medan resten är grundläggande plugin-definitionelement.

För det andra genomförandet av ContainerFactoryPluginInterface gränssnitt som vi definierar skapa() metod. Det senare är en del av beredskapsprocessen, genom vilken vi kan ladda upp den Mandrill-tjänst som vi definierade i services.yml filen tidigare. Detta gör testningen mycket enklare och det anses vara bästa praxis.

Som jag nämnde måste postprogrammen implementera MailInterface gränssnitt som styrker förekomsten av formatera() och post() metoder. I vårt fall gör den första precis samma sak som PHPMail plugin: lite behandling av meddelandekroppen. Så du kan lägga till din egen logik här om du vill. Den senare metoden är å andra sidan ansvarig för att skicka ut mailen, i vårt fall, genom att använda Mandrill API själv.

Som Mandrill dokumentation instruerar, konstruerar vi ett e-postmeddelande inuti $ Vars array med värden som skickas från posthanteraren via $ message parameter. Dessa kommer redan att filtreras genom hook_mail (), hook_mail_alter () och pluginets egna formatera() metod. Allt som är kvar är att faktiskt skicka e-postmeddelandet. Jag kommer inte att gå in i detaljerna om att använda Mandrill API eftersom du kan konsultera dokumentationen för alla alternativ du kan använda.

Efter att ha skickat e-postmeddelandet och kommer tillbaka från Mandrill a skickat status returnerar vi hela responsmatrisen, som innehåller lite mer information. Denna matris läggs sedan till av posthanteraren till sin egen returmatris som är markerad som resultat. Om Mandrill har problem, avvisar e-postmeddelandet eller kastar ett undantag, återkommer vi falsk. Detta gör att posthanteraren hanterar denna situation genom att logga in händelsen och skriva ut ett statusmeddelande.

Och det är ganska mycket det. Vi kan rensa cacheminnet och försöka skapa en annan artikelnod. Den här gången bör anmälningsemail skickas av Mandrill istället för PHP post(). Med detta på plats, men hook_mail_alter () genomförandet har blivit överflödigt eftersom det inte finns några rubriker skickar vi faktiskt till Mandrill (och texten är HTML redan). Och för den delen används ganska mycket av postchefens arbete inte, eftersom vi inte går vidare till Mandrill. Men det här är bara tänkt att illustrera processen med hur du kan gå om att ställa in det här. Detaljerna i genomförandet förblir upp till dig och dina behov.

Slutsats

Och där har vi det. Vi har implementerat vårt eget mailprogram för att användas av d8module vi började i föregående artikel. Och på grund av Drupal 8s töjbara natur tog det inte ens för mycket ansträngning. 

Vad som är kvar för dig att göra är att perfektera loggens skick och anpassa det till dina omständigheter. Detta kan innebära ytterligare integration mellan Mandrill och din Drupal-instans, bygga trevliga mallar eller vad har du. Dessutom skriver en viktig återstående uppgift automatiska tester för denna funktionalitet. Och Drupal 8 erbjuder också ganska verktygslåda för det också.