Elgg  Version master
NotificationsService.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg\Notifications;
4 
8 use Elgg\Traits\Loggable;
9 
17 
18  use Loggable;
19 
21  protected array $events = [];
22 
24  protected array $methods = [];
25 
33  public function __construct(
34  protected Queue $queue,
35  protected \ElggSession $session,
36  protected EventsService $elgg_events
37  ) {
38  }
39 
53  public function registerEvent(string $type, string $subtype, string $action = 'create', string $handler = NotificationEventHandler::class): void {
54  if (!is_a($handler, NotificationEventHandler::class, true)) {
55  throw new InvalidArgumentException('$handler needs to be a ' . NotificationEventHandler::class . ' classname');
56  }
57 
58  if (!isset($this->events[$type])) {
59  $this->events[$type] = [];
60  }
61 
62  if (!isset($this->events[$type][$subtype])) {
63  $this->events[$type][$subtype] = [];
64  }
65 
66  if (!isset($this->events[$type][$subtype][$action])) {
67  $this->events[$type][$subtype][$action] = [];
68  }
69 
70  if (in_array($handler, $this->events[$type][$subtype][$action])) {
71  return;
72  }
73 
74  $this->events[$type][$subtype][$action][] = $handler;
75  }
76 
88  public function unregisterEvent(string $type, string $subtype, string $action = 'create', string $handler = NotificationEventHandler::class): void {
89  if (!isset($this->events[$type][$subtype][$action])) {
90  return;
91  }
92 
93  $key = array_search($handler, $this->events[$type][$subtype][$action]);
94  if ($key !== false) {
95  unset($this->events[$type][$subtype][$action][$key]);
96  }
97 
98  if (empty($this->events[$type][$subtype][$action])) {
99  unset($this->events[$type][$subtype][$action]);
100  }
101 
102  if (empty($this->events[$type][$subtype])) {
103  unset($this->events[$type][$subtype]);
104  }
105 
106  if (empty($this->events[$type])) {
107  unset($this->events[$type]);
108  }
109  }
110 
116  public function getEvents(): array {
117  return $this->events;
118  }
119 
128  public function registerMethod(string $name): void {
129  $this->methods[$name] = $name;
130  }
131 
140  public function unregisterMethod(string $name): void {
141  if (!$this->isRegisteredMethod($name)) {
142  return;
143  }
144 
145  unset($this->methods[$name]);
146  }
147 
154  public function getMethods(): array {
155  return $this->methods;
156  }
157 
165  public function isRegisteredMethod(string $method): bool {
166  return in_array($method, $this->methods);
167  }
168 
178  public function enqueueEvent(string $action, \ElggData $object, ?\ElggEntity $actor = null): void {
179  $object_type = $object->getType();
180  $object_subtype = $object->getSubtype();
181  $actor = $actor ?? elgg_get_logged_in_user_entity(); // default to logged in user
182  if (!isset($actor) && ($object instanceof \ElggEntity || $object instanceof \ElggExtender)) {
183  // still not set, default to the owner of $object
184  $actor = $object->getOwnerEntity() ?: null;
185  }
186 
187  $handlers = $this->getSubscriptionHandlers($object_type, $object_subtype, $action);
188  if (empty($handlers)) {
189  return;
190  }
191 
192  $params = [
193  'action' => $action,
194  'object' => $object,
195  'actor' => $actor,
196  ];
197  $registered = (bool) $this->elgg_events->triggerResults('enqueue', 'notification', $params, true);
198  if (!$registered) {
199  return;
200  }
201 
202  $this->elgg_events->trigger('enqueue', 'notifications', $object);
203  $this->queue->enqueue(new SubscriptionNotificationEvent($object, $action, $actor));
204  }
205 
215  protected function getSubscriptionHandlers(string $type, string $subtype, string $action): array {
216  if (!isset($this->events[$type][$subtype][$action])) {
217  return [];
218  }
219 
220  $result = [];
221  foreach ($this->events[$type][$subtype][$action] as $handler) {
222  if (is_a($handler, InstantNotificationEventHandler::class, true)) {
223  continue;
224  }
225 
226  $result[] = $handler;
227  }
228 
229  return $result;
230  }
231 
241  protected function getInstantHandlers(string $type, string $subtype, string $action): array {
242  if (!isset($this->events[$type][$subtype][$action])) {
243  return [
244  InstantNotificationEventHandler::class,
245  ];
246  }
247 
248  $result = [];
249  foreach ($this->events[$type][$subtype][$action] as $handler) {
250  if (!is_a($handler, InstantNotificationEventHandler::class, true)) {
251  continue;
252  }
253 
254  $result[] = $handler;
255  }
256 
257  if (empty($result)) {
258  return [
259  InstantNotificationEventHandler::class,
260  ];
261  }
262 
263  return $result;
264  }
265 
273  public function processQueue(int $stopTime): int {
274  return elgg_call(ELGG_IGNORE_ACCESS, function() use ($stopTime) {
275  $count = 0;
276 
277  while (time() < $stopTime) {
278  // dequeue notification event
279  $event = elgg_call(ELGG_SHOW_DISABLED_ENTITIES, function () {
280  // showing disabled entities for deserialization
281  return $this->queue->dequeue();
282  });
283 
284  if (!$event instanceof NotificationEvent) {
285  // queue is empty
286  break;
287  }
288 
289  $object = $event->getObject();
290  if (!$object instanceof \ElggData || !$event->getActor()) {
291  // event object or actor have been deleted since the event was enqueued
292  continue;
293  }
294 
295  $this->elgg_events->trigger('dequeue', 'notifications', $object);
296 
297  $handlers = $this->getSubscriptionHandlers($object->getType(), $object->getSubtype(), $event->getAction());
298  if (empty($handlers)) {
299  continue;
300  }
301 
302  foreach ($handlers as $handler_class) {
303  $handler = new $handler_class($event, $this);
304 
305  try {
306  $handler->send();
307  $count++;
308  } catch (\Throwable $t) {
309  $this->getLogger()->error($t);
310  }
311  }
312  }
313 
314  return $count;
315  });
316  }
317 
354  public function sendInstantNotifications(\ElggEntity $sender, array $recipients = [], array $params = []): array {
355  if (empty($this->methods)) {
356  return [];
357  }
358 
359  $object = elgg_extract('object', $params);
360  $action = elgg_extract('action', $params);
361 
362  $event = new InstantNotificationEvent($object, $action, $sender);
363 
364  $handler = new InstantNotificationEventHandler($event, $this, $params);
365  $handler->setRecipients($recipients);
366 
367  return $handler->send();
368  }
369 
383  public function sendInstantNotification(\ElggUser $recipient, string $action, \ElggData $subject, array $params = [], ?\ElggEntity $from = null): array {
384  if (empty($this->methods)) {
385  return [];
386  }
387 
388  $handlers = $this->getInstantHandlers($subject->getType(), $subject->getSubtype(), $action);
389  if (empty($handlers)) {
390  return [];
391  }
392 
393  $from = $from ?? elgg_get_site_entity();
394 
395  $event = new InstantNotificationEvent($subject, $action, $from);
396 
397  $result = [];
398 
399  foreach ($handlers as $handler_class) {
400  $handler = new $handler_class($event, $this, $params);
401  $handler->setRecipients([$recipient]);
402 
403  try {
404  $handler_result = $handler->send();
405 
406  $result = $result + $handler_result;
407  } catch (\Throwable $t) {
408  $this->getLogger()->error($t);
409  }
410  }
411 
412  return $result;
413  }
414 }
if(! $user||! $user->canDelete()) $name
Definition: delete.php:22
$subtype
Definition: delete.php:22
$type
Definition: delete.php:21
$recipient
Definition: mute.php:8
$params
Saves global plugin settings.
Definition: save.php:13
$handler
Definition: add.php:7
return[ 'admin/delete_admin_notices'=>['access'=> 'admin'], 'admin/menu/save'=>['access'=> 'admin'], 'admin/plugins/activate'=>['access'=> 'admin'], 'admin/plugins/activate_all'=>['access'=> 'admin'], 'admin/plugins/deactivate'=>['access'=> 'admin'], 'admin/plugins/deactivate_all'=>['access'=> 'admin'], 'admin/plugins/set_priority'=>['access'=> 'admin'], 'admin/security/security_txt'=>['access'=> 'admin'], 'admin/security/settings'=>['access'=> 'admin'], 'admin/security/regenerate_site_secret'=>['access'=> 'admin'], 'admin/site/cache/clear'=>['access'=> 'admin'], 'admin/site/cache/invalidate'=>['access'=> 'admin'], 'admin/site/icons'=>['access'=> 'admin'], 'admin/site/set_maintenance_mode'=>['access'=> 'admin'], 'admin/site/set_robots'=>['access'=> 'admin'], 'admin/site/theme'=>['access'=> 'admin'], 'admin/site/unlock_upgrade'=>['access'=> 'admin'], 'admin/site/settings'=>['access'=> 'admin'], 'admin/upgrade'=>['access'=> 'admin'], 'admin/upgrade/reset'=>['access'=> 'admin'], 'admin/user/ban'=>['access'=> 'admin'], 'admin/user/bulk/ban'=>['access'=> 'admin'], 'admin/user/bulk/delete'=>['access'=> 'admin'], 'admin/user/bulk/unban'=>['access'=> 'admin'], 'admin/user/bulk/validate'=>['access'=> 'admin'], 'admin/user/change_email'=>['access'=> 'admin'], 'admin/user/delete'=>['access'=> 'admin'], 'admin/user/login_as'=>['access'=> 'admin'], 'admin/user/logout_as'=>[], 'admin/user/makeadmin'=>['access'=> 'admin'], 'admin/user/resetpassword'=>['access'=> 'admin'], 'admin/user/removeadmin'=>['access'=> 'admin'], 'admin/user/unban'=>['access'=> 'admin'], 'admin/user/validate'=>['access'=> 'admin'], 'annotation/delete'=>[], 'avatar/upload'=>[], 'comment/save'=>[], 'diagnostics/download'=>['access'=> 'admin', 'controller'=> \Elgg\Diagnostics\DownloadController::class,], 'entity/chooserestoredestination'=>[], 'entity/delete'=>[], 'entity/mute'=>[], 'entity/restore'=>[], 'entity/subscribe'=>[], 'entity/trash'=>[], 'entity/unmute'=>[], 'entity/unsubscribe'=>[], 'login'=>['access'=> 'logged_out'], 'logout'=>[], 'notifications/mute'=>['access'=> 'public'], 'plugins/settings/remove'=>['access'=> 'admin'], 'plugins/settings/save'=>['access'=> 'admin'], 'plugins/usersettings/save'=>[], 'register'=>['access'=> 'logged_out', 'middleware'=>[\Elgg\Router\Middleware\RegistrationAllowedGatekeeper::class,],], 'river/delete'=>[], 'settings/notifications'=>[], 'settings/notifications/subscriptions'=>[], 'user/changepassword'=>['access'=> 'public'], 'user/requestnewpassword'=>['access'=> 'public'], 'useradd'=>['access'=> 'admin'], 'usersettings/save'=>[], 'widgets/add'=>[], 'widgets/delete'=>[], 'widgets/move'=>[], 'widgets/save'=>[],]
Definition: actions.php:76
$count
Definition: ban.php:24
A generic class that contains shared code among \ElggExtender, \ElggEntity, and \ElggRelationship.
Definition: ElggData.php:12
Elgg Session Management.
Definition: ElggSession.php:19
Events service.
Exception thrown if an argument is not of the expected type.
Notification Event Handler for instant notifications.
Notification Event Handler handles preparation of a notification.
enqueueEvent(string $action, \ElggData $object, ?\ElggEntity $actor=null)
Add a notification event to the queue.
sendInstantNotifications(\ElggEntity $sender, array $recipients=[], array $params=[])
Notify a user via their preferences.
unregisterMethod(string $name)
Unregister a delivery method for notifications.
getEvents()
Return the notification events.
sendInstantNotification(\ElggUser $recipient, string $action, \ElggData $subject, array $params=[], ?\ElggEntity $from=null)
Send an instant notification to a user.
unregisterEvent(string $type, string $subtype, string $action='create', string $handler=NotificationEventHandler::class)
Unregister a notification event.
getSubscriptionHandlers(string $type, string $subtype, string $action)
Get the subscription notification handlers.
processQueue(int $stopTime)
Pull notification events from queue until stop time is reached.
isRegisteredMethod(string $method)
Check if a notification method is registed.
registerMethod(string $name)
Register a delivery method for notifications.
__construct(protected Queue $queue, protected \ElggSession $session, protected EventsService $elgg_events)
Constructor.
getInstantHandlers(string $type, string $subtype, string $action)
Get the instant notification handlers.
registerEvent(string $type, string $subtype, string $action='create', string $handler=NotificationEventHandler::class)
Register a notification event.
getMethods()
Returns registered delivery methods for notifications.
const ELGG_IGNORE_ACCESS
elgg_call() flags
Definition: constants.php:121
const ELGG_SHOW_DISABLED_ENTITIES
Definition: constants.php:123
if($email instanceof \Elgg\Email) $object
Definition: body.php:24
$subject
HTML body of an email.
Definition: body.php:11
elgg_call(int $flags, Closure $closure)
Calls a callable autowiring the arguments using public DI services and applying logic based on flags.
Definition: elgglib.php:296
elgg_extract($key, $array, $default=null, bool $strict=true)
Checks for $array[$key] and returns its value if it exists, else returns $default.
Definition: elgglib.php:246
Notification event interface.
Queue interface.
Definition: Queue.php:11
elgg_get_site_entity()
Get the current site entity.
Definition: entities.php:99
if(isset($_COOKIE['elggperm'])) $session
Definition: login_as.php:29
if($container instanceof ElggGroup && $container->guid !=elgg_get_page_owner_guid()) $key
Definition: summary.php:44
if(parse_url(elgg_get_site_url(), PHP_URL_PATH) !=='/') if(file_exists(elgg_get_root_path() . 'robots.txt'))
Set robots.txt.
Definition: robots.php:10
elgg_get_logged_in_user_entity()
Return the current logged in user, or null if no user is logged in.
Definition: sessions.php:24
$action
Definition: subscribe.php:11
if(($owner instanceof \ElggGroup|| $owner instanceof \ElggUser) &&!in_array($owner->guid, $mute_guids)) $actor
Definition: mute.php:78