Utilisation et extension de l'API Drupal 8 Mail Partie 2

Dans le précédent article, nous avions vu comment envoyer des emails de manière programmée dans Drupal 8. Nous avons également vu comment d'autres modules pouvaient modifier ces emails sortants. Aujourd'hui, nous allons voir comment nous pouvons utiliser l'API Mail pour étendre ce comportement par défaut. Le but est d’utiliser un service externe comme moyen de livraison par courrier électronique.. 

Pour cela, nous utiliserons Mandrill, bien que l’article ne soit pas axé sur son API ni sur la façon de travailler avec elle, mais plutôt sur le côté Drupal. Et rappelez-vous, le module de travail se trouve dans ce référentiel Git.

Comme nous l’avons vu dans l’article précédent, l’envoi d’un courrier électronique dans Drupal 8 se fait en demandant au gestionnaire de messagerie, en transmettant certains paramètres à son gestionnaire. courrier() méthode et mise en place d’un modèle à l'intérieur d'un hook_mail () la mise en oeuvre. Ce que le gestionnaire de messagerie fait en interne est de charger le plug-in de messagerie approprié, de construire le courrier électronique, puis de le déléguer à l'utilisateur. courrier() méthode de tout plugin a été chargé.

Mais qui délègue-t-il réellement?

Sélection du plugin

Avant de rédiger notre propre plugin, il est important de comprendre le processus de sélection du gestionnaire de messagerie pour le chargement des plugins. En d’autres termes, comment savoir quel plugin il va charger et comment pouvons-nous le charger nous-mêmes??

le system.mail.interface Le tableau de configuration contient toutes les réponses. Il contient les identifiants des plugins disponibles, en fonction du contexte dans lequel ils sont utilisés. Par défaut, tout ce que nous avons dans cette configuration est défaut => phpmail. Cela signifie que le plugin avec l'id phpmail (la classe PHPMail) est utilisé comme solution de secours pour tous les contextes non spécifiés par ailleurs, c’est-à-dire le paramètre par défaut..

Si nous voulons écrire notre propre plugin, nous devons ajouter un autre élément dans ce tableau avec l'identifiant du plugin comme valeur. La clé de cette valeur peut être l’une des deux choses suivantes: le nom de la machine de notre module (pour charger le plug-in chaque fois que notre module envoie des emails) ou une combinaison de nom de module et d’e-mail. modèle key (pour charger le plugin chaque fois que notre module envoie un email en utilisant cette clé spécifique). 

Un exemple de cette dernière construction est d8mail_node_insert, où d8mail est le nom de notre module que nous avons commencé à construire dans l'article précédent, et node_insert est l'e-mail modèle clé nous avons défini.

Alors maintenant que nous savons comment se passe la sélection du plug-in de messagerie, nous devons nous assurer que ce tableau de configuration contient les informations nécessaires pour que les emails envoyés avec nos d8mail module utilise le nouveau plugin que nous allons construire. Nous pouvons faire cela dans une implémentation de hook_install () qui ne se déclenche qu'une seule fois lorsque le module est installé:

d8mail.install:

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

Pas super compliqué ce qui se passe ci-dessus. Nous chargeons l’objet de configuration modifiable représentant le system.mail configuration, et ajouter un nouvel élément à la interface tableau: d8mail => mandrill_mail. Nous allons bientôt créer un plugin mail avec l'id de mandrill_mail qui sera utilisé pour tous les emails envoyés par le d8mail module. Et c'est tout.

Mais avant de poursuivre, nous devons nous assurer que cette modification est annulée lors de la désinstallation du module. Pour cela, nous pouvons utiliser la contrepartie hook_uninstall () qui est appelée lorsqu'un module est désinstallé (il n'y a plus de module désactivant dans Drupal 8).

Dans le même fichier:

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

Avec le hook_uninstall () nous faisons l’opposé d’avant: nous supprimons notre identifiant de plugin s’il est défini.

Le scénario d'installation / de désinstallation n'est qu'un moyen parmi d'autres. Vous pouvez également créer un formulaire d’administration permettant aux utilisateurs de sélectionner le plug-in qu’ils souhaitent et dans quel contexte. Mais vous devez toujours vous assurer que lorsque vous désactivez le module définissant un plug-in particulier, la configuration ne conservera plus aucune référence à ce plug-in. Sinon, le gestionnaire de messagerie peut essayer d'utiliser une classe non existante et renvoyer toutes sortes d'erreurs.

Mandrill

Comme je l'ai mentionné précédemment, nous allons travailler avec l'API Mandrill afin d'illustrer notre tâche. Nous allons donc charger la bibliothèque PHP de Mandrill et la rendre disponible dans notre environnement. Il y a trois étapes à faire pour cela.

Premièrement, nous devons réellement intégrer la bibliothèque dans Drupal. Au moment de la rédaction de cet article, cela revient essentiellement à ajouter le "mandrill / mandrill": "1.0. *" dépendance à la racine composer.json fichier et en cours d'exécution compositeur installer. Gardez à l’esprit, cependant, que cela effacera également l’installation de Drupal de l’intérieur du coeur/ dossier et téléchargez la dernière version stable à la place. Ensuite, vous devrez modifier la racine index.php fichier et changer le chemin d'accès à l'autoloader selon ces instructions. Espérons que cette dernière action ne sera pas nécessaire bientôt, et je vous encourage à suivre les discussions sur l'avenir de Composer dans Drupal 8 pour la gestion de bibliothèques externes..

Deuxièmement, nous devons obtenir une clé API de Mandrill. Heureusement, nous pouvons facilement générer ceci à partir de leurs pages d’administration. Une fois que nous avons cela, nous pouvons le stocker dans un nouveau fichier créé sur notre serveur, à l’emplacement suivant:

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

Nous pouvons également passer la clé en tant que paramètre constructeur à la commande principale. Mandrill classe, mais de cette façon nous n'aurons pas à le coder en dur dans notre code. 

Troisièmement, nous devons créer un service afin de pouvoir utiliser l’injection de dépendance pour passer le message. Mandrill classe dans notre plugin:

d8mail.services.yml:

services: d8mail.mandrill: classe: Mandrill 

En fonction de la manière dont vous avez chargé le Mandrill classe dans votre application, vous devrez modifier la valeur après classe. En utilisant le composer.json approche, cela suffira.

Le plugin mail

Il est enfin temps de créer notre plugin. Dans Drupal 8, les classes de plug-in entrent dans le src / plugin dossier de notre module. Cependant, selon leur type, ils sont placés plus bas dans d’autres répertoires (dans notre cas, Courrier). Écrivons notre classe qui dépendra de la bibliothèque de l'API Mandrill pour envoyer des emails:

src / Plugin / Mail / MandrillMail.php:

mandrill = $ mandrill;  / ** * @inheritdoc * / public static function create (ContainerInterface $ conteneur, tableau $ configuration, $ plugin_id, $ plugin_definition) retourne new static ($ conteneur-> get ('d8mail.mandrill'));  / ** * @inheritdoc * / format de fonction public (array $ message) // Joignez le tableau de corps en une chaîne. $ message ['body'] = imploser ("\ n \ n", $ message ['body']); // Convertit n'importe quel HTML en texte brut. $ message ['body'] = MailFormatHelper :: htmlToText ($ message ['body']); // Enveloppe le corps du courrier pour l'envoi. $ 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 ['de'], 'à' => array (array ('email' => $ message ['à'])),]; $ resultat = $ this-> mandrill-> messages-> send ($ vars); if ($ result [0] ['status']!! == 'envoyé') return false;  return $ result;  catch (Mandrill_Error $ e) return false;  

Il y a plusieurs choses à noter avant de se lancer dans ce que la classe fait.

Tout d'abord, les annotations au-dessus de la classe. C’est le mécanisme de découverte de plugins le plus courant pour Drupal 8. Le identifiant la clé correspond à la valeur que nous avons ajoutée à la system.mail.interface tableau de configuration plus tôt, tandis que le reste sont des éléments de définition de plugin de base.

Deuxièmement, la mise en œuvre de la ContainerFactoryPluginInterface interface par laquelle nous définissons la créer() méthode. Ce dernier fait partie du processus d’injection de dépendance par lequel nous pouvons charger le service Mandrill défini dans le services.yml déposer plus tôt. Cela facilite les tests et est considéré comme une pratique exemplaire..

Comme je le disais, les plugins mail doivent implémenter la MailInterface interface qui impose l'existence de la format() et courrier() méthodes. Dans notre cas, le premier fait exactement la même chose que le PHPMail plugin: un peu de traitement du corps du message. Vous pouvez donc ajouter votre propre logique ici si vous le souhaitez. Cette dernière méthode, en revanche, est responsable de l'envoi du courrier, dans notre cas, à l'aide de l'API Mandrill elle-même..

Selon les instructions de la documentation Mandrill, nous construisons un message électronique à l’intérieur du $ vars tableau en utilisant les valeurs transmises par le gestionnaire de messagerie à travers le $ message paramètre. Ceux-ci seront déjà filtrés à travers hook_mail (), hook_mail_alter () et du plugin format() méthode. Il ne reste plus qu'à envoyer le courrier électronique. Je n'entrerai pas dans les détails d'utilisation de l'API Mandrill, car vous pouvez consulter la documentation pour connaître toutes les options que vous pouvez utiliser..

Après avoir envoyé le courrier électronique et reçu de Mandrill un envoyé état, nous retournons le tableau de réponse entier, qui contient quelques informations supplémentaires. Ce tableau est ensuite ajouté par le gestionnaire de messagerie à son propre tableau de retour résultat. Si Mandrill a un problème, rejette le courrier électronique ou lève une exception, nous retournons faux. Cela obligera le gestionnaire de messagerie à gérer cette situation en enregistrant l'incident et en imprimant un message d'état..

Et c'est à peu près tout. Nous pouvons vider le cache et essayer de créer un autre nœud d'article. Cette fois, le courrier électronique de notification devrait être envoyé par Mandrill au lieu de celui de PHP. courrier(). Avec cela en place, cependant, le hook_mail_alter () l'implémentation est devenue superflue car il n'y a aucun en-tête que nous envoyons via Mandrill (et le texte est déjà HTML). Et d'ailleurs, une grande partie du travail du gestionnaire de messagerie n'est pas utilisée, car nous ne la transmettons pas à Mandrill. Mais ceci est simplement destiné à illustrer le processus de la façon dont vous pouvez vous y prendre pour le mettre en place. Les détails de la mise en œuvre restent à votre charge et à vos besoins.

Conclusion

Et là nous l'avons. Nous avons mis en place notre propre plugin mail à utiliser par le d8module nous avons commencé dans l'article précédent. Et en raison de la nature extensible de Drupal 8, il n'a même pas fallu trop d'effort. 

Il vous reste à perfectionner la logique d’envoi de courrier et à l’adapter à votre situation. Cela peut signifier une intégration plus poussée entre Mandrill et votre instance Drupal, la construction de jolis modèles ou ce que vous avez. En outre, une tâche importante restante consiste à rédiger des tests automatisés pour cette fonctionnalité. Et Drupal 8 offre tout à fait la boîte à outils pour cela aussi.