Elgg  Version 4.3
NotificationEventHandler.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg\Notifications;
4 
7 
14 
16  protected $event;
17 
19  protected $service;
20 
22  protected $params = [];
23 
31  public function __construct(
34  array $params = []
35  ) {
36  $this->event = $event;
37  $this->service = $service;
38  $this->params = $params;
39  }
40 
46  final public function send(): array {
47  $deliveries = [];
48 
50  $params['handler'] = $this;
51  $params['event'] = $this->event;
52  $params['subscriptions'] = $this->prepareSubscriptions();
53 
54  // return false to stop the default notification sender
55  if (_elgg_services()->hooks->trigger('send:before', 'notifications', $params, true)) {
56  $deliveries = $this->sendNotifications($params['subscriptions'], $params);
57  }
58 
59  $params['deliveries'] = $deliveries;
60  _elgg_services()->hooks->trigger('send:after', 'notifications', $params);
61 
62  return $deliveries;
63  }
64 
70  final protected function prepareSubscriptions(): array {
72 
73  $params = [
74  'event' => $this->event,
75  'methods' => $this->getMethods(),
76  'methods_override' => (array) elgg_extract('methods_override', $this->params, []),
77  ];
78  $subscriptions = _elgg_services()->hooks->trigger('get', 'subscriptions', $params, $subscriptions);
79 
80  return _elgg_services()->subscriptions->filterSubscriptions($subscriptions, $this->event, $this->filterMutedSubscriptions());
81  }
82 
89  protected function filterMutedSubscriptions(): bool {
90  return (bool) elgg_extract('apply_muting', $this->params, true);
91  }
92 
98  public function getSubscriptions(): array {
99  return _elgg_services()->subscriptions->getNotificationEventSubscriptions($this->event, $this->getMethods(), $this->getNotificationSubsciptionExclusionGUIDs());
100  }
101 
107  final protected function getNotificationSubsciptionExclusionGUIDs(): array {
108  $object = $this->event->getObject();
109  if (!$object instanceof \ElggEntity) {
110  return [];
111  }
112 
113  $exclude = [];
114  if ($this->excludeOwnerSubscribers()) {
115  $exclude[] = $object->owner_guid;
116  }
117 
118  if ($this->excludeContainerSubscribers()) {
119  $exclude[] = $object->container_guid;
120  }
121 
122  if ($this->excludeEntitySubscribers()) {
123  $exclude[] = $object->guid;
124  }
125 
126  return $exclude;
127  }
128 
135  protected function excludeOwnerSubscribers(): bool {
136  return false;
137  }
138 
145  protected function excludeContainerSubscribers(): bool {
146  return false;
147  }
148 
155  protected function excludeEntitySubscribers(): bool {
156  return false;
157  }
158 
164  final public function getMethods(): array {
165  return $this->service->getMethods();
166  }
167 
187  final protected function sendNotifications($subscriptions, array $params = []) {
188  if (empty($this->getMethods())) {
189  return [];
190  }
191 
192  $result = [];
193  foreach ($subscriptions as $guid => $methods) {
194  foreach ($methods as $method) {
195  $result[$guid][$method] = false;
196 
197  if ($this->service->isRegisteredMethod($method)) {
198  $result[$guid][$method] = $this->sendNotification($guid, $method, $params);
199  }
200  }
201  }
202 
203  _elgg_services()->logger->info("Results for the notification event {$this->event->getDescription()}: " . print_r($result, true));
204  return $result;
205  }
206 
216  final protected function sendNotification(int $guid, string $method, array $params = []): bool {
217  if (!_elgg_services()->hooks->hasHandler('send', "notification:{$method}")) {
218  // no way to deliver given the current method, so quitting early
219  return false;
220  }
221 
222  $actor = $this->event->getActor();
223  $object = $this->event->getObject();
224 
225  if ($this->event instanceof InstantNotificationEvent) {
226  $recipient = _elgg_services()->entityTable->get($guid);
227  /* @var \ElggEntity $recipient */
228  $subject = elgg_extract('subject', $params, '');
229  $body = elgg_extract('body', $params, '');
230  $summary = elgg_extract('summary', $params, '');
231  } else {
232  $recipient = _elgg_services()->entityTable->get($guid, 'user');
233  if (!$recipient instanceof \ElggUser || $recipient->isBanned()) {
234  return false;
235  }
236 
237  if (!$actor || !$object) {
238  return false;
239  }
240 
241  if ($object instanceof \ElggEntity && !$object->hasAccess($recipient->guid)) {
242  // Recipient does not have access to the notification object
243  // The access level may have changed since the event was enqueued
244  return false;
245  }
246 
247  $subject = $this->getNotificationSubject($recipient, $method);
248  $body = $this->getNotificationBody($recipient, $method);
249  $summary = $this->getNotificationSummary($recipient, $method);
250 
251  if (!isset($params['url'])) {
252  $params['url'] = $this->getNotificationURL($recipient, $method) ?: null;
253  }
254  }
255 
256  $params['subject'] = $subject;
257  $params['body'] = $body;
258  $params['summary'] = $summary;
259  $params['event'] = $this->event;
260  $params['method'] = $method;
261  $params['sender'] = $actor;
262  $params['recipient'] = $recipient;
263  $params['language'] = $recipient->getLanguage();
264  $params['object'] = $object;
265  $params['action'] = $this->event->getAction();
266  $params['add_salutation'] = elgg_extract('add_salutation', $params, true);
267  $params['add_mute_link'] = elgg_extract('add_mute_link', $params, $this->addMuteLink());
268 
270  return $this->deliverNotification($notification, $method);
271  }
272 
281  final protected function deliverNotification(Notification $notification, string $method): bool {
282  // return true to indicate the notification has been sent
283  $params = [
284  'notification' => $notification,
285  'event' => $this->event,
286  ];
287 
288  $result = _elgg_services()->hooks->trigger('send', "notification:{$method}", $params, false);
289 
290  if (_elgg_services()->logger->isLoggable(LogLevel::INFO)) {
291  $logger_data = print_r((array) $notification->toObject(), true);
292  if ($result) {
293  _elgg_services()->logger->info('Notification sent: ' . $logger_data);
294  } else {
295  _elgg_services()->logger->info('Notification was not sent: ' . $logger_data);
296  }
297  }
298 
299  return $result;
300  }
301 
310  final protected function prepareNotification(array $params): Notification {
311  $notification = new Notification($params['sender'], $params['recipient'], $params['language'], $params['subject'], $params['body'], $params['summary'], $params);
312 
313  $notification = _elgg_services()->hooks->trigger('prepare', 'notification', $params, $notification);
314  if (!$notification instanceof Notification) {
315  throw new RuntimeException("'prepare','notification' hook must return an instance of " . Notification::class);
316  }
317 
318  $type = 'notification:' . $this->event->getDescription();
319  $notification = _elgg_services()->hooks->trigger('prepare', $type, $params, $notification);
320  if (!$notification instanceof Notification) {
321  throw new RuntimeException("'prepare','{$type}' hook must return an instance of " . Notification::class);
322  }
323 
324  if (elgg_extract('add_salutation', $notification->params) === true) {
325  $viewtype = elgg_view_exists('notifications/body') ? '' : 'default';
326  $notification->body = _elgg_view_under_viewtype('notifications/body', ['notification' => $notification], $viewtype);
327  }
328 
329  $notification = _elgg_services()->hooks->trigger('format', "notification:{$params['method']}", [], $notification);
330  if (!$notification instanceof Notification) {
331  throw new RuntimeException("'format','notification:{$params['method']}' hook must return an instance of " . Notification::class);
332  }
333 
334  return $notification;
335  }
336 
348  protected function getNotificationSubject(\ElggUser $recipient, string $method): string {
349  $actor = $this->event->getActor();
350  $object = $this->event->getObject();
351 
352  $language = $recipient->getLanguage();
353 
354  // Check custom notification subject for the action/type/subtype combination
355  $subject_key = "notification:{$this->event->getDescription()}:subject";
356  if (_elgg_services()->translator->languageKeyExists($subject_key, $language)) {
357  $display_name = '';
358  if ($object instanceof \ElggEntity) {
359  $display_name = $object->getDisplayName();
360  }
361 
362  return _elgg_services()->translator->translate($subject_key, [
365  ], $language);
366  }
367 
368  // Fall back to default subject
369  return _elgg_services()->translator->translate('notification:subject', [$actor->getDisplayName()], $language);
370  }
371 
394  protected function getNotificationBody(\ElggUser $recipient, string $method): string {
395  $actor = $this->event->getActor();
396  $object = $this->event->getObject();
397  /* @var \ElggObject $object */
398  $language = $recipient->getLanguage();
399 
400  // Check custom notification body for the action/type/subtype combination
401  $body_key = "notification:{$this->event->getDescription()}:body";
402  if (_elgg_services()->translator->languageKeyExists($body_key, $language)) {
403  if ($object instanceof \ElggEntity) {
404  $display_name = $object->getDisplayName();
405  $container_name = '';
406  $container = $object->getContainerEntity();
407  if ($container) {
408  $container_name = $container->getDisplayName();
409  }
410  } else {
411  $display_name = '';
412  $container_name = '';
413  }
414 
415  return _elgg_services()->translator->translate($body_key, [
418  $container_name,
419  $object->description,
420  $object->getURL(),
421  ], $language);
422  }
423 
424  // Fall back to default body
425  return _elgg_services()->translator->translate('notification:body', [$object->getURL()], $language);
426  }
427 
436  protected function getNotificationSummary(\ElggUser $recipient, string $method): string {
437  return '';
438  }
439 
448  protected function getNotificationURL(\ElggUser $recipient, string $method): string {
449  $object = $this->event->getObject();
450 
451  return $object instanceof \ElggData ? $object->getURL() : '';
452  }
453 
459  public static function isConfigurableByUser(): bool {
460  return true;
461  }
462 
473  final public static function isConfigurableForEntity(\ElggEntity $entity): bool {
474 
475  if ($entity instanceof \ElggUser) {
476  return static::isConfigurableForUser($entity);
477  } elseif ($entity instanceof \ElggGroup) {
478  return static::isConfigurableForGroup($entity);
479  }
480 
481  return true;
482  }
483 
492  protected static function isConfigurableForUser(\ElggUser $user): bool {
493  return true;
494  }
495 
506  protected static function isConfigurableForGroup(\ElggGroup $group): bool {
507  return true;
508  }
509 
515  protected function addMuteLink(): bool {
516  return true;
517  }
518 }
$display_name
Definition: delete.php:19
static isConfigurableByUser()
Is this event configurable by the user on the notification settings page.
elgg_view_exists($view, $viewtype= '', $recurse=true)
Returns whether the specified view exists.
Definition: views.php:152
static isConfigurableForEntity(\ElggEntity $entity)
Can this event be configured for a specific entity.
toObject()
Export notification.
getLanguage($fallback=null)
Get user language or default to site language.
Definition: ElggUser.php:73
Exception thrown if an error which can only be found on runtime occurs.
static isConfigurableForUser(\ElggUser $user)
Can this event be configured for a specific user.
prepareNotification(array $params)
Prepares a notification for delivery.
if(($owner instanceof\ElggGroup||$owner instanceof\ElggUser)&&!in_array($owner->guid, $mute_guids)) $actor
Definition: mute.php:86
excludeOwnerSubscribers()
Exclude the NotificationEvent object owner_guid when fetching the subscription records for this notif...
getMethods()
Returns methods to be used for this notification.
getNotificationURL(\ElggUser $recipient, string $method)
Returns the url related to this notification.
$type
Definition: delete.php:21
getNotificationSubject(\ElggUser $recipient, string $method)
Get subject for the notification.
Notification container.
sendNotification(int $guid, string $method, array $params=[])
Send a notification to a subscriber.
getSubscriptions()
Returns subscriptions for the event.
sendNotifications($subscriptions, array $params=[])
Sends the notifications based on subscriptions.
Notification Event Handler handles preparation of a notification.
deliverNotification(Notification $notification, string $method)
Deliver a notification.
filterMutedSubscriptions()
Should muted subscribers be filtered.
$entity
Definition: reset.php:8
excludeContainerSubscribers()
Exclude the NotificationEvent object container_guid when fetching the subscription records for this n...
$language
Definition: useradd.php:19
$notification
Definition: body.php:13
$user
Definition: ban.php:7
$container
Definition: delete.php:23
addMuteLink()
Add a mute link in the email notification.
$viewtype
Definition: default.php:11
getNotificationBody(\ElggUser $recipient, string $method)
Get body for the notification.
$body
Definition: useradd.php:59
elgg_extract($key, $array, $default=null, $strict=true)
Checks for $array[$key] and returns its value if it exists, else returns $default.
Definition: elgglib.php:547
getNotificationSubsciptionExclusionGUIDs()
Get an array of GUIDs to not get the subscription records for.
if($email instanceof\Elgg\Email) $object
Definition: body.php:24
getNotificationSummary(\ElggUser $recipient, string $method)
Return the summary for a notification.
Notification event interface.
if($item instanceof\ElggEntity) elseif($item instanceof\ElggRiverItem) elseif($item instanceof ElggRelationship) elseif(is_callable([$item, 'getType']))
Definition: item.php:48
excludeEntitySubscribers()
Exclude the NotificationEvent object guid when fetching the subscription records for this notificatio...
if(!$owner instanceof ElggEntity) $summary
Definition: summary.php:33
_elgg_services()
Get the global service provider.
Definition: elgglib.php:638
static isConfigurableForGroup(\ElggGroup $group)
Can this event be configured for a specific group.
if(empty($methods)) $subscriptions
_elgg_view_under_viewtype($view, $vars, $viewtype)
Render a view while the global viewtype is temporarily changed.
Definition: views.php:1487
$methods
Definition: subscribe.php:8
$recipient
Definition: mute.php:8
$subject
Definition: useradd.php:58
__construct(NotificationEvent $event, NotificationsService $service, array $params=[])
Constructor.
getDisplayName()
Get the entity&#39;s display name.
Definition: ElggEntity.php:318
$guid
Reset an ElggUpgrade.
Definition: reset.php:6