From a0ad2e1b727dff615d9360b366b77dab757954e5 Mon Sep 17 00:00:00 2001 From: Camilo Ernesto Escobar Bedoya <escobar@urbaninsight.com> Date: Thu, 1 Jun 2023 17:50:24 -0500 Subject: [PATCH] Issue #3362297 New Queue Worker to send Email Notifications --- .../recurring_events_reminders.module | 4 +- .../recurring_events_registration.module | 60 +++++++++----- ...recurring_events_registration.services.yml | 4 +- .../src/NotificationService.php | 83 ++++++++++++++++--- .../EmailNotificationsQueueWorker.php | 80 ++++++++++++++++++ 5 files changed, 196 insertions(+), 35 deletions(-) create mode 100644 modules/recurring_events_registration/src/Plugin/QueueWorker/EmailNotificationsQueueWorker.php diff --git a/modules/recurring_events_registration/modules/recurring_events_reminders/recurring_events_reminders.module b/modules/recurring_events_registration/modules/recurring_events_reminders/recurring_events_reminders.module index 8ce06b97..3e5b246f 100644 --- a/modules/recurring_events_registration/modules/recurring_events_reminders/recurring_events_reminders.module +++ b/modules/recurring_events_registration/modules/recurring_events_reminders/recurring_events_reminders.module @@ -154,6 +154,7 @@ function recurring_events_reminders_cron() { $registration_creation_service->setEventInstance($instance); $registrants = $registration_creation_service->retrieveRegisteredParties(); + if (empty($registrants)) { return; } @@ -162,7 +163,8 @@ function recurring_events_reminders_cron() { // Send an email to all registrants. foreach ($registrants as $registrant) { - recurring_events_registration_send_notification($key, $registrant); + // Add each notification to be sent to the queue. + \Drupal::service('recurring_events_registration.notification_service')->addEmailNotificationToQueue($key, $registrant); } } } diff --git a/modules/recurring_events_registration/recurring_events_registration.module b/modules/recurring_events_registration/recurring_events_registration.module index 41ceb8f5..2b082efa 100644 --- a/modules/recurring_events_registration/recurring_events_registration.module +++ b/modules/recurring_events_registration/recurring_events_registration.module @@ -143,26 +143,44 @@ function template_preprocess_registrant(array &$variables) { * Implements hook_mail(). */ function recurring_events_registration_mail($key, &$message, $params) { - /** @var \Drupal\recurring_events_registration\NotificationService */ - $service = \Drupal::service('recurring_events_registration.notification_service'); - $service->setKey($key)->setEntity($params['registrant']); + if ((empty($params['subject']) || empty($params['body']) || empty($params['from'])) + && !empty($params['registrant']) + && $params['registrant'] instanceof Registrant) { + /** @var \Drupal\recurring_events_registration\NotificationService */ + $service = \Drupal::service('recurring_events_registration.notification_service'); + $service->setKey($key)->setEntity($params['registrant']); + } - if ($service->isEnabled()) { - if (!empty($params['subject'])) { - $service->setSubject($params['subject']); - } - if (!empty($params['body'])) { - $service->setMessage($params['body']); - } - if (!empty($params['from'])) { - $service->setFrom($params['from']); - } + if (!empty($params['from'])) { + $message['from'] = $params['from']; + } + elseif (isset($service)) { $message['from'] = $service->getFrom(); + } + + if (!empty($params['subject'])) { + $message['subject'] = $params['subject']; + } + elseif (isset($service)) { $message['subject'] = $service->getSubject(); + } + + if (!empty($params['body'])) { + $message['body'][] = $params['body']; + } + elseif (isset($service)) { $message['body'][] = $service->getMessage(); } - return FALSE; + + // echo 'params::' . PHP_EOL; + // print_r($params); + // echo 'message::' . PHP_EOL; + // print_r($message); + + // $message['from'] = $params['from'] ?? isset($service) ? $service->getFrom() : ''; + // $message['subject'] = $params['subject'] ?? isset($service) ? $service->getSubject() : ''; + // $message['body'][] = $params['body'] ?? isset($service) ? $service->getMessage() : ''; } /** @@ -218,7 +236,8 @@ function recurring_events_registration_recurring_events_save_pre_instances_delet // Send an email to all registrants. foreach ($registrants as $registrant) { - recurring_events_registration_send_notification($key, $registrant); + // Add each notification to be sent to the queue. + \Drupal::service('recurring_events_registration.notification_service')->addEmailNotificationToQueue($key, $registrant); $registrant->delete(); } } @@ -250,7 +269,8 @@ function recurring_events_registration_entity_update(EntityInterface $entity) { // Send an email to all registrants. foreach ($registrants as $registrant) { - recurring_events_registration_send_notification($key, $registrant); + // Add each notification to be sent to the queue. + \Drupal::service('recurring_events_registration.notification_service')->addEmailNotificationToQueue($key, $registrant); } } } @@ -274,7 +294,8 @@ function recurring_events_registration_recurring_events_pre_delete_instance(Even foreach ($registrants as $registrant) { // Only send email notifications if this event instance is in the future. if ($registration_creation_service->eventInstanceIsInFuture()) { - recurring_events_registration_send_notification($key, $registrant); + // Add each notification to be sent to the queue. + \Drupal::service('recurring_events_registration.notification_service')->addEmailNotificationToQueue($key, $registrant); } $registrant->delete(); } @@ -296,7 +317,8 @@ function recurring_events_registration_recurring_events_pre_delete_instances(Eve // Send an email to the future registrants. foreach ($future_registrants as $registrant) { - recurring_events_registration_send_notification($key, $registrant); + // Add each notification to be sent to the queue. + \Drupal::service('recurring_events_registration.notification_service')->addEmailNotificationToQueue($key, $registrant); } } @@ -317,7 +339,7 @@ function recurring_events_registration_recurring_events_pre_delete_instances(Eve * * @param string $key * The mail key used to determine the message and subject. - * @param \Drupal\recurring_events_registration\Entity\RegistrantInterface $registrant + * @param \Drupal\recurring_events_registration\Entity\RegistrantInterface|bool $registrant * The registrant this email relates to. */ function recurring_events_registration_send_notification($key, RegistrantInterface $registrant) { diff --git a/modules/recurring_events_registration/recurring_events_registration.services.yml b/modules/recurring_events_registration/recurring_events_registration.services.yml index d5dd368e..75728207 100644 --- a/modules/recurring_events_registration/recurring_events_registration.services.yml +++ b/modules/recurring_events_registration/recurring_events_registration.services.yml @@ -4,7 +4,7 @@ services: arguments: ['@string_translation', '@database', '@logger.factory', '@messenger', '@entity_type.manager', '@module_handler', '@token'] recurring_events_registration.notification_service: class: Drupal\recurring_events_registration\NotificationService - arguments: ['@string_translation', '@config.factory', '@logger.factory', '@messenger', '@token', '@module_handler', '@recurring_events_registration.creation_service'] + arguments: ['@string_translation', '@config.factory', '@logger.factory', '@messenger', '@token', '@module_handler', '@recurring_events_registration.creation_service', '@queue'] recurring_events_registration.access_handler: class: Drupal\recurring_events_registration\AccessHandler arguments: ['@string_translation', '@recurring_events_registration.creation_service', '@current_route_match', '@entity_type.manager'] @@ -12,4 +12,4 @@ services: class: Drupal\recurring_events_registration\Routing\RouteSubscriber arguments: [ '@config.factory' ] tags: - - { name: event_subscriber } + - { name: event_subscriber } \ No newline at end of file diff --git a/modules/recurring_events_registration/src/NotificationService.php b/modules/recurring_events_registration/src/NotificationService.php index ac303818..91123003 100644 --- a/modules/recurring_events_registration/src/NotificationService.php +++ b/modules/recurring_events_registration/src/NotificationService.php @@ -10,6 +10,7 @@ use Drupal\Core\Utility\Token; use Drupal\recurring_events_registration\Entity\RegistrantInterface; use Drupal\Core\Extension\ModuleHandler; use Symfony\Component\DependencyInjection\ContainerInterface; +use Drupal\Core\Queue\QueueFactory; /** * Provides a service with helper functions to facilitate notifications. @@ -114,6 +115,13 @@ class NotificationService { */ protected $custom = FALSE; + /** + * The update fetch queue. + * + * @var \Drupal\Core\Queue\QueueFactory + */ + protected $queueFactory; + /** * Class constructor. * @@ -131,8 +139,10 @@ class NotificationService { * The module handler service. * @param \Drupal\recurring_events_registration\RegistrationCreationService $creation_service * The registration creation service. + * @param \Drupal\Core\Queue\QueueFactory $queue_factory + * The queue factory. */ - public function __construct(TranslationInterface $translation, ConfigFactory $config_factory, LoggerChannelFactoryInterface $logger, Messenger $messenger, Token $token, ModuleHandler $module_handler, RegistrationCreationService $creation_service) { + public function __construct(TranslationInterface $translation, ConfigFactory $config_factory, LoggerChannelFactoryInterface $logger, Messenger $messenger, Token $token, ModuleHandler $module_handler, RegistrationCreationService $creation_service, QueueFactory $queue_factory) { $this->translation = $translation; $this->configFactory = $config_factory; $this->loggerFactory = $logger->get('recurring_events_registration'); @@ -141,6 +151,7 @@ class NotificationService { $this->moduleHandler = $module_handler; $this->creationService = $creation_service; $this->configName = 'recurring_events_registration.registrant.config'; + $this->queueFactory = $queue_factory; } /** @@ -154,7 +165,8 @@ class NotificationService { $container->get('messenger'), $container->get('token'), $container->get('module_handler'), - $container->get('recurring_events_registration.creation_service') + $container->get('recurring_events_registration.creation_service'), + $container->get('queue') ); } @@ -246,7 +258,7 @@ class NotificationService { * @return string|bool * The key, or FALSE if not set. */ - protected function getKey() { + public function getKey() { if (empty($this->key)) { $this->messenger->addError($this->translation->translate('No key defined for @module notifications.', [ '@module' => 'recurring_events_registration', @@ -352,11 +364,7 @@ class NotificationService { public function getSubject($parse_tokens = TRUE) { $key = $this->getKey(); if ($key) { - $subject = $this->subject; - if (empty($subject)) { - $subject = $this->getConfigValue('subject'); - $this->setSubject($subject); - } + $subject = $this->getConfigValue('subject'); if (empty($subject)) { $this->messenger->addError($this->translation->translate('No default subject configured for @key emails in @config_name.', [ @@ -386,11 +394,7 @@ class NotificationService { public function getMessage($parse_tokens = TRUE) { $key = $this->getKey(); if ($key) { - $message = $this->message; - if (empty($message)) { - $message = $this->getConfigValue('body'); - $this->setMessage($message); - } + $message = $this->getConfigValue('body'); if (empty($message)) { $this->messenger->addError($this->translation->translate('No default body configured for @key emails in @config_name.', [ @@ -450,4 +454,57 @@ class NotificationService { return $this->creationService->getAvailableTokens($relevant_tokens); } + /** + * Adds an email notification to be sent later by the Queue Worker. + */ + public function addEmailNotificationToQueue($key, RegistrantInterface $registrant) { + $config = $this->configFactory->get('recurring_events_registration.registrant.config'); + $send_email = $config->get('email_notifications'); + $send_email_key = $config->get('notifications' . '.' . $key . '.enabled'); + + // Modify $send_email if necessary. + if ($registrant instanceof RegistrantInterface) { + $this->moduleHandler->alter('recurring_events_registration_send_notification', $send_email, $registrant); + } + + if ($send_email && $send_email_key) { + // We need to get the parsed email subject and message (after token + // replacement) to add them to the `$item` that will be queued. We are + // not adding the `$registrant` to the `$item`, since in the queue worker + // we cannot rely on operations over the `$registrant` or its parent + // instance or series, since at that point those entities might have been + // deleted. There are some operations and notification types that require + // the `$registrant`to be deleted, for example: the notifications + // corresponding to the keys 'series_modification_notification' and + // 'instance_deletion_notification'. + // @see recurring_events_registration_recurring_events_save_pre_instances_deletion() + // @see recurring_events_registration_recurring_events_pre_delete_instance() + $this->setKey($key)->setEntity($registrant); + $subject = $this->getSubject(); + $message = $this->getMessage(); + $from = $this->getFrom(); + + // Create the item to be added to the queue. + $item = new \stdClass(); + $item->key = $key; + $item->to = $registrant->email->value; + + $params = [ + 'subject' => $subject, + 'body' => $message, + 'from' => $from, + ]; + // Allow modules to add data to the `$params`. They can get the data from + // `$registrant`. Those `$params` are used later as the + // `$message['params']` in mail hooks. + $this->moduleHandler->alter('recurring_events_registration_message_params_alter', $params, $registrant); + + $item->params = $params; + + // Add the item to the queue. + $queue = $this->queueFactory->get('recurring_events_registration_email_notifications_queue_worker'); + $queue->createItem($item); + } + } + } diff --git a/modules/recurring_events_registration/src/Plugin/QueueWorker/EmailNotificationsQueueWorker.php b/modules/recurring_events_registration/src/Plugin/QueueWorker/EmailNotificationsQueueWorker.php new file mode 100644 index 00000000..a5c4590f --- /dev/null +++ b/modules/recurring_events_registration/src/Plugin/QueueWorker/EmailNotificationsQueueWorker.php @@ -0,0 +1,80 @@ +<?php + +namespace Drupal\recurring_events_registration\Plugin\QueueWorker; + +use Drupal\Core\Queue\QueueWorkerBase; +use Drupal\Core\Plugin\ContainerFactoryPluginInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Drupal\Core\Mail\MailManagerInterface; +use Drupal\Core\Language\LanguageManagerInterface; + +/** + * Defines 'recurring_events_registration_email_notifications_queue_worker' queue worker. + * + * @QueueWorker( + * id = "recurring_events_registration_email_notifications_queue_worker", + * title = @Translation("Email Notifications Queue Worker"), + * cron = {"time" = 6} + * ) + */ +class EmailNotificationsQueueWorker extends QueueWorkerBase implements ContainerFactoryPluginInterface { + + /** + * The mail manager. + * + * @var \Drupal\Core\Mail\MailManagerInterface + */ + protected $mailManager; + + /** + * The language manager. + * + * @var \Drupal\Core\Language\LanguageManagerInterface + */ + protected $languageManager; + + /** + * Constructs a new LocaleTranslation object. + * + * @param array $configuration + * A configuration array containing information about the plugin instance. + * @param string $plugin_id + * The plugin_id for the plugin instance. + * @param array $plugin_definition + * @param \Drupal\Core\Mail\MailManagerInterface $mail_manager + * The mail manager. + * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager + * The language manager. + */ + public function __construct(array $configuration, $plugin_id, array $plugin_definition, MailManagerInterface $mail_manager, LanguageManagerInterface $language_manager) { + parent::__construct($configuration, $plugin_id, $plugin_definition); + $this->mailManager = $mail_manager; + $this->languageManager = $language_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('plugin.manager.mail'), + $container->get('language_manager') + ); + } + + /** + * {@inheritdoc} + */ + public function processItem($item) { + if (empty($item->key) || empty($item->to) || (empty($item->params['subject']) && empty($item->params['body']))) { + return; + } + // All this worker has to do is to send the email. + // The Subject and Body already have to be included in the `$item`. + $this->mailManager->mail('recurring_events_registration', $item->key, $item->to, $this->languageManager->getDefaultLanguage()->getId(), $item->params); + } + +} -- GitLab