Elgg  Version master
DelayedEmailService.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg\Email;
4 
6 use Elgg\Email;
11 use Elgg\Invoker;
15 
23 
24  use Loggable;
25 
26  protected const NOTIFICATIONS_BATCH_SIZE = 500;
27 
37  public function __construct(
38  protected DelayedEmailQueueTable $queue_table,
39  protected EmailService $email,
40  protected ViewsService $views,
41  protected Translator $translator,
42  protected Invoker $invoker
43  ) {
44  }
45 
54  $recipient = $notification->getRecipient();
55 
56  $delivery_interval = $recipient->delayed_email_interval ?: 'daily';
57 
58  try {
59  return $this->queue_table->queueEmail($recipient->guid, $delivery_interval, $notification);
60  } catch (DatabaseException $e) {
61  $this->getLogger()->error($e);
62  }
63 
64  return false;
65  }
66 
75  public function processQueuedNotifications(string $delivery_interval, int $timestamp): int {
76  // processing could take a while
77  set_time_limit(0);
78 
79  return ($this->invoker->call(ELGG_IGNORE_ACCESS, function() use ($delivery_interval, $timestamp) {
80  $count = 0;
81 
82  // process one recipient
83  $processRecipient = function(int $recipient_guid, array $notifications, int $max_id) use ($delivery_interval, $timestamp) {
84  try {
85  $this->processRecipientNotifications($recipient_guid, $notifications, $delivery_interval);
86  } catch (\Throwable $t) {
87  $this->getLogger()->error($t);
88  }
89 
90  // cleanup the queue for this recipient
91  return $this->queue_table->deleteRecipientRows($recipient_guid, $delivery_interval, $timestamp, $max_id);
92  };
93 
94  // get the next recipient to process
95  $recipient_guid = $this->queue_table->getNextRecipientGUID($delivery_interval, $timestamp);
96  while ($recipient_guid > 0) {
97  // get a notification batch to process for this recipient
98  $rows = $this->queue_table->getRecipientRows($recipient_guid, $delivery_interval, $timestamp, self::NOTIFICATIONS_BATCH_SIZE);
99  while (!empty($rows)) {
100  $notifications = [];
101  $max_id = 0;
102  foreach ($rows as $row) {
103  $max_id = max($max_id, $row->id);
104 
105  $notification = $row->getNotification();
106  if (!$notification instanceof Notification) {
107  continue;
108  }
109 
110  $notifications[] = $notification;
111  }
112 
113  // send all notifications in this batch
114  $count += $processRecipient($recipient_guid, $notifications, $max_id);
115 
116  // get next batch
117  $rows = $this->queue_table->getRecipientRows($recipient_guid, $delivery_interval, $timestamp, static::NOTIFICATIONS_BATCH_SIZE);
118  }
119 
120  // get next recipient to process
121  $recipient_guid = $this->queue_table->getNextRecipientGUID($delivery_interval, $timestamp);
122  }
123 
124  return $count;
125  }));
126  }
127 
137  protected function processRecipientNotifications(int $recipient_guid, array $notifications, string $delivery_interval): bool {
138  $recipient = get_entity($recipient_guid);
139  if (!$recipient instanceof \ElggEntity || !isset($recipient->email)) {
140  return false;
141  }
142 
143  $view_vars = [
144  'recipient' => $recipient,
145  'notifications' => $notifications,
146  'delivery_interval' => $delivery_interval,
147  ];
148 
149  $body = $this->views->renderView('email/delayed_email/plaintext', $view_vars);
150  if (empty($body)) {
151  return true;
152  }
153 
154  $html_body = $this->views->renderView('email/delayed_email/html', $view_vars);
155 
157  'to' => $recipient,
158  'subject' => $this->translator->translate("notifications:delayed_email:subject:{$delivery_interval}", [], (string) $recipient->language),
159  'body' => $body,
160  'params' => [
161  'html_body' => $html_body,
162  ],
163  ]);
164 
165  return $this->email->send($email);
166  }
167 }
getRecipient()
Get the recipient entity.
$notifications
Definition: html.php:12
processQueuedNotifications(string $delivery_interval, int $timestamp)
Send out notifications for the given delivery_interval.
$rows
Definition: redis.php:25
$email
Definition: change_email.php:7
static factory(array $options=[])
Create an email instance form an array of options.
Definition: Email.php:80
Notification container.
$timestamp
Definition: date.php:34
trait Loggable
Enables adding a logger.
Definition: Loggable.php:14
const ELGG_IGNORE_ACCESS
elgg_call() flags
Definition: constants.php:130
enqueueNotification(Notification $notification)
Queue a notification for delayed email delivery.
get_entity(int $guid)
Loads and returns an entity object from a guid.
Definition: entities.php:70
$notification
Definition: body.php:13
$site email
Definition: settings.php:16
A generic parent class for database exceptions.
Views service.
$count
Definition: ban.php:24
processRecipientNotifications(int $recipient_guid, array $notifications, string $delivery_interval)
Send out the combined email notification for a given recipient.
Interfaces with the database to perform operations on the delayed_email_queue table.
getLogger()
Returns logger.
Definition: Loggable.php:37
__construct(protected DelayedEmailQueueTable $queue_table, protected EmailService $email, protected ViewsService $views, protected Translator $translator, protected Invoker $invoker)
Create a new service.
$recipient_guid
Definition: mute.php:7
Email service.
$recipient
Definition: mute.php:8
$views
Definition: item.php:17
Handle storing and processing delayed emails.
Invocation service.
Definition: Invoker.php:10