Elgg  Version 2.2
 All Classes Namespaces Files Functions Variables Pages
NotificationsService.php
Go to the documentation of this file.
1 <?php
2 namespace Elgg\Notifications;
3 
4 use ElggEntity;
5 
16 
17  const QUEUE_NAME = 'notifications';
18 
20  protected $subscriptions;
21 
23  protected $queue;
24 
26  protected $hooks;
27 
29  protected $session;
30 
32  protected $translator;
33 
35  protected $entities;
36 
38  protected $events = array();
39 
41  protected $methods = array();
42 
44  protected $deprHandlers = array();
45 
47  protected $deprSubjects = array();
48 
59  public function __construct(
60  \Elgg\Notifications\SubscriptionsService $subscriptions,
61  \Elgg\Queue\Queue $queue,
64  \Elgg\I18n\Translator $translator,
66 
67  $this->subscriptions = $subscriptions;
68  $this->queue = $queue;
69  $this->hooks = $hooks;
70  $this->session = $session;
71  $this->translator = $translator;
72  $this->entities = $entities;
73  }
74 
79  public function registerEvent($type, $subtype, array $actions = array()) {
80 
81  if (!isset($this->events[$type])) {
82  $this->events[$type] = array();
83  }
84  if (!isset($this->events[$type][$subtype])) {
85  $this->events[$type][$subtype] = array();
86  }
87 
88  $action_list =& $this->events[$type][$subtype];
89  if ($actions) {
90  $action_list = array_unique(array_merge($action_list, $actions));
91  } elseif (!in_array('create', $action_list)) {
92  $action_list[] = 'create';
93  }
94  }
95 
100  public function unregisterEvent($type, $subtype) {
101 
102  if (!isset($this->events[$type]) || !isset($this->events[$type][$subtype])) {
103  return false;
104  }
105 
106  unset($this->events[$type][$subtype]);
107 
108  return true;
109  }
110 
114  public function getEvents() {
115  return $this->events;
116  }
117 
122  public function registerMethod($name) {
123  $this->methods[$name] = $name;
124  }
125 
130  public function unregisterMethod($name) {
131  if (isset($this->methods[$name])) {
132  unset($this->methods[$name]);
133  return true;
134  }
135  return false;
136  }
137 
141  public function getMethods() {
142  return $this->methods;
143  }
144 
154  public function enqueueEvent($action, $type, $object) {
155  if ($object instanceof \ElggData) {
156  $object_type = $object->getType();
157  $object_subtype = $object->getSubtype();
158 
159  $registered = false;
160  if (isset($this->events[$object_type])
161  && isset($this->events[$object_type][$object_subtype])
162  && in_array($action, $this->events[$object_type][$object_subtype])) {
163  $registered = true;
164  }
165 
166  if ($registered) {
167  $params = array(
168  'action' => $action,
169  'object' => $object,
170  );
171  $registered = $this->hooks->trigger('enqueue', 'notification', $params, $registered);
172  }
173 
174  if ($registered) {
175  $this->queue->enqueue(new \Elgg\Notifications\Event($object, $action));
176  }
177  }
178  }
179 
187  public function processQueue($stopTime) {
188 
189  $this->subscriptions->methods = $this->methods;
190 
191  $count = 0;
192 
193  // @todo grab mutex
194 
195  $ia = $this->session->setIgnoreAccess(true);
196 
197  while (time() < $stopTime) {
198  // dequeue notification event
199  $event = $this->queue->dequeue();
200  if (!$event) {
201  break;
202  }
203 
204  // test for usage of the deprecated override hook
205  if ($this->existsDeprecatedNotificationOverride($event)) {
206  continue;
207  }
208 
209  $subscriptions = $this->subscriptions->getSubscriptions($event);
210 
211  // return false to stop the default notification sender
212  $params = array('event' => $event, 'subscriptions' => $subscriptions);
213  if ($this->hooks->trigger('send:before', 'notifications', $params, true)) {
214  $this->sendNotifications($event, $subscriptions);
215  }
216  $this->hooks->trigger('send:after', 'notifications', $params);
217  $count++;
218  }
219 
220  // release mutex
221 
222  $this->session->setIgnoreAccess($ia);
223 
224  return $count;
225  }
226 
235  protected function sendNotifications($event, $subscriptions) {
236 
237  if (!$this->methods) {
238  return 0;
239  }
240 
241  $count = 0;
242  foreach ($subscriptions as $guid => $methods) {
243  foreach ($methods as $method) {
244  if (in_array($method, $this->methods)) {
245  if ($this->sendNotification($event, $guid, $method)) {
246  $count++;
247  }
248  }
249  }
250  }
251  return $count;
252  }
253 
263  protected function sendNotification(\Elgg\Notifications\Event $event, $guid, $method) {
264 
265  $recipient = $this->entities->get($guid, 'user');
266  /* @var \ElggUser $recipient */
267  if (!$recipient || $recipient->isBanned()) {
268  return false;
269  }
270 
271  // don't notify the creator of the content
272  if ($recipient->getGUID() == $event->getActorGUID()) {
273  return false;
274  }
275 
276  $actor = $event->getActor();
277  $object = $event->getObject();
278  if (!$actor || !$object) {
279  return false;
280  }
281 
282  if (($object instanceof ElggEntity) && !has_access_to_entity($object, $recipient)) {
283  return false;
284  }
285 
286  $language = $recipient->language;
287  $params = array(
288  'event' => $event,
289  'method' => $method,
290  'recipient' => $recipient,
291  'language' => $language,
292  'object' => $object,
293  );
294 
295  $subject = $this->getNotificationSubject($event, $recipient);
296  $body = $this->getNotificationBody($event, $recipient);
297 
298  $notification = new \Elgg\Notifications\Notification($event->getActor(), $recipient, $language, $subject, $body, '', $params);
299 
300  $type = 'notification:' . $event->getDescription();
301  if ($this->hooks->hasHandler('prepare', $type)) {
302  $notification = $this->hooks->trigger('prepare', $type, $params, $notification);
303  } else {
304  // pre Elgg 1.9 notification message generation
305  $notification = $this->getDeprecatedNotificationBody($notification, $event, $method);
306  }
307 
308  if ($this->hooks->hasHandler('send', "notification:$method")) {
309  // return true to indicate the notification has been sent
310  $params = array(
311  'notification' => $notification,
312  'event' => $event,
313  );
314  return $this->hooks->trigger('send', "notification:$method", $params, false);
315  } else {
316  // pre Elgg 1.9 notification handler
317  $userGuid = $notification->getRecipientGUID();
318  $senderGuid = $notification->getSenderGUID();
319  $subject = $notification->subject;
320  $body = $notification->body;
321  $params = $notification->params;
322  return (bool)_elgg_notify_user($userGuid, $senderGuid, $subject, $body, $params, array($method));
323  }
324  }
325 
340  private function getNotificationSubject(Event $event, \ElggUser $recipient) {
341  $actor = $event->getActor();
342  $object = $event->getObject();
343  /* @var \ElggObject $object */
344  $language = $recipient->language;
345 
346  // Check custom notification subject for the action/type/subtype combination
347  $subject_key = "notification:{$event->getDescription()}:subject";
348  if ($this->translator->languageKeyExists($subject_key, $language)) {
349  return $this->translator->translate($subject_key, array(
350  $actor->name,
351  $object->getDisplayName(),
352  ), $language);
353  }
354 
355  // Fall back to default subject
356  return $this->translator->translate('notification:subject', array($actor->name), $language);
357  }
358 
395  private function getNotificationBody(Event $event, \ElggUser $recipient) {
396  $actor = $event->getActor();
397  $object = $event->getObject();
398  /* @var \ElggObject $object */
399  $language = $recipient->language;
400 
401  // Check custom notification body for the action/type/subtype combination
402  $body_key = "notification:{$event->getDescription()}:body";
403  if ($this->translator->languageKeyExists($body_key, $language)) {
404  $container = $object->getContainerEntity();
405 
406  return $this->translator->translate($body_key, array(
407  $recipient->name,
408  $actor->name,
409  $object->getDisplayName(),
410  $container->getDisplayName(),
411  $object->description,
412  $object->getURL(),
413  ), $language);
414  }
415 
416  // Fall back to default body
417  return $this->translator->translate('notification:body', array($object->getURL()), $language);
418  }
419 
428  $this->deprHandlers[$method] = $handler;
429  }
430 
437  public function getDeprecatedHandler($method) {
438  if (isset($this->deprHandlers[$method])) {
439  return $this->deprHandlers[$method];
440  } else {
441  return null;
442  }
443  }
444 
451  public function getMethodsAsDeprecatedGlobal() {
452  $data = array();
453  foreach ($this->methods as $method) {
454  $data[$method] = 'empty';
455  }
456  return $data;
457  }
458 
467  protected function getDeprecatedNotificationBody(\Elgg\Notifications\Notification $notification, \Elgg\Notifications\Event $event, $method) {
468  $entity = $event->getObject();
469  $params = array(
470  'entity' => $entity,
471  'to_entity' => $notification->getRecipient(),
472  'method' => $method,
473  );
474  $subject = $this->getDeprecatedNotificationSubject($entity->getType(), $entity->getSubtype());
475  $string = $subject . ": " . $entity->getURL();
476  $body = $this->hooks->trigger('notify:entity:message', $entity->getType(), $params, $string);
477 
478  if ($subject) {
479  $notification->subject = $subject;
480  $notification->body = $body;
481  }
482 
483  return $notification;
484  }
485 
495  if ($type == '') {
496  $type = '__BLANK__';
497  }
498  if ($subtype == '') {
499  $subtype = '__BLANK__';
500  }
501 
502  if (!isset($this->deprSubjects[$type])) {
503  $this->deprSubjects[$type] = array();
504  }
505 
506  $this->deprSubjects[$type][$subtype] = $subject;
507  }
508 
517  if ($type == '') {
518  $type = '__BLANK__';
519  }
520  if ($subtype == '') {
521  $subtype = '__BLANK__';
522  }
523 
524  if (!isset($this->deprSubjects[$type])) {
525  return '';
526  }
527 
528  if (!isset($this->deprSubjects[$type][$subtype])) {
529  return '';
530  }
531 
532  return $this->deprSubjects[$type][$subtype];
533  }
534 
541  protected function existsDeprecatedNotificationOverride(\Elgg\Notifications\Event $event) {
542  $entity = $event->getObject();
543  if (!elgg_instanceof($entity)) {
544  return false;
545  }
546  $params = array(
547  'event' => $event->getAction(),
548  'object_type' => $entity->getType(),
549  'object' => $entity,
550  );
551  $hookresult = $this->hooks->trigger('object:notifications', $entity->getType(), $params, false);
552  if ($hookresult === true) {
553  elgg_deprecated_notice("Using the plugin hook 'object:notifications' has been deprecated by the hook 'send:before', 'notifications'", 1.9);
554  return true;
555  } else {
556  return false;
557  }
558  }
559 }
$object
These two snippets demonstrates triggering an event and how to register for that event.
Definition: trigger.php:7
$action
Definition: full.php:125
getDeprecatedNotificationBody(\Elgg\Notifications\Notification $notification,\Elgg\Notifications\Event $event, $method)
Get the notification body using a pre-Elgg 1.9 plugin hook.
sendNotification(\Elgg\Notifications\Event $event, $guid, $method)
Send a notification to a subscriber.
$subject
Definition: exceptions.php:25
if($guid==elgg_get_logged_in_user_guid()) $name
Definition: delete.php:21
$method
Definition: form.php:25
existsDeprecatedNotificationOverride(\Elgg\Notifications\Event $event)
Is someone using the deprecated override.
$data
Definition: opendd.php:13
$subtype
Definition: delete.php:28
sendNotifications($event, $subscriptions)
Sends the notifications based on subscriptions.
$guid
Removes an admin notice.
getMethodsAsDeprecatedGlobal()
Provides a way to incrementally wean Elgg's notifications code from the global $NOTIFICATION_HANDLERS...
getDeprecatedHandler($method)
Get a deprecated notification handler callback.
setDeprecatedNotificationSubject($type, $subtype, $subject)
Set message subject for deprecated notification code.
$string
$actions
Definition: user_hover.php:12
$params
Definition: login.php:72
elgg_instanceof($entity, $type=null, $subtype=null, $class=null)
Checks if $entity is an and optionally for type and subtype.
Definition: entities.php:716
$container
Definition: delete.php:29
$language
Definition: useradd.php:20
__construct(\Elgg\Notifications\SubscriptionsService $subscriptions,\Elgg\Queue\Queue $queue,\Elgg\PluginHooksService $hooks,\ElggSession $session,\Elgg\I18n\Translator $translator,\Elgg\Database\EntityTable $entities)
Constructor.
elgg_deprecated_notice($msg, $dep_version, $backtrace_level=1)
Log a notice about deprecated use of a function, view, etc.
Definition: elgglib.php:1070
enqueueEvent($action, $type, $object)
Add a notification event to the queue.
getActor()
Get the actor of the event.
Definition: Event.php:60
getDeprecatedNotificationSubject($type, $subtype)
Get the deprecated subject.
$entity
Definition: delete.php:7
if(elgg_in_context('widget')) $count
Definition: pagination.php:21
has_access_to_entity($entity, $user=null)
Can a user access an entity.
Definition: access.php:237
$handler
Definition: add.php:10
registerEvent($type, $subtype, array $actions=array())
registerDeprecatedHandler($method, $handler)
Register a deprecated notification handler.
processQueue($stopTime)
Pull notification events from queue until stop time is reached.
_elgg_notify_user($to, $from, $subject, $message, array $params=null, $methods_override="")
Notify a user via their preferences.
getObject()
Get the object of the event.
Definition: Event.php:78
if(!$display_name) $type
Definition: delete.php:27