Verzeichnisstruktur phpBB-3.1.0


Veröffentlicht
27.10.2014

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

manager.php

Zuletzt modifiziert: 09.10.2024, 12:51 - Dateigröße: 32.05 KiB


001  <?php
002  /**
003  *
004  * This file is part of the phpBB Forum Software package.
005  *
006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
007  * @license GNU General Public License, version 2 (GPL-2.0)
008  *
009  * For full copyright and license information, please see
010  * the docs/CREDITS.txt file.
011  *
012  */
013   
014  namespace phpbb\notification;
015   
016  use Symfony\Component\DependencyInjection\ContainerInterface;
017   
018  /**
019  * Notifications service class
020  */
021  class manager
022  {
023      /** @var array */
024      protected $notification_types;
025   
026      /** @var array */
027      protected $notification_methods;
028   
029      /** @var ContainerInterface */
030      protected $phpbb_container;
031   
032      /** @var \phpbb\user_loader */
033      protected $user_loader;
034   
035      /** @var \phpbb\config\config */
036      protected $config;
037   
038      /** @var \phpbb\db\driver\driver_interface */
039      protected $db;
040   
041      /** @var \phpbb\cache\service */
042      protected $cache;
043   
044      /** @var \phpbb\user */
045      protected $user;
046   
047      /** @var string */
048      protected $phpbb_root_path;
049   
050      /** @var string */
051      protected $php_ext;
052   
053      /** @var string */
054      protected $notification_types_table;
055   
056      /** @var string */
057      protected $notifications_table;
058   
059      /** @var string */
060      protected $user_notifications_table;
061   
062      /**
063      * Notification Constructor
064      *
065      * @param array $notification_types
066      * @param array $notification_methods
067      * @param ContainerInterface $phpbb_container
068      * @param \phpbb\user_loader $user_loader
069      * @param \phpbb\config\config $config
070      * @param \phpbb\db\driver\driver_interface $db
071      * @param \phpbb\cache\service $cache
072      * @param \phpbb\user $user
073      * @param string $phpbb_root_path
074      * @param string $php_ext
075      * @param string $notification_types_table
076      * @param string $notifications_table
077      * @param string $user_notifications_table
078      *
079      * @return \phpbb\notification\manager
080      */
081      public function __construct($notification_types, $notification_methods, ContainerInterface $phpbb_container, \phpbb\user_loader $user_loader, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, $user, $phpbb_root_path, $php_ext, $notification_types_table, $notifications_table, $user_notifications_table)
082      {
083          $this->notification_types = $notification_types;
084          $this->notification_methods = $notification_methods;
085          $this->phpbb_container = $phpbb_container;
086   
087          $this->user_loader = $user_loader;
088          $this->config = $config;
089          $this->db = $db;
090          $this->cache = $cache;
091          $this->user = $user;
092   
093          $this->phpbb_root_path = $phpbb_root_path;
094          $this->php_ext = $php_ext;
095   
096          $this->notification_types_table = $notification_types_table;
097          $this->notifications_table = $notifications_table;
098          $this->user_notifications_table = $user_notifications_table;
099      }
100   
101      /**
102      * Load the user's notifications
103      *
104      * @param array $options Optional options to control what notifications are loaded
105      *                notification_id        Notification id to load (or array of notification ids)
106      *                user_id                User id to load notifications for (Default: $user->data['user_id'])
107      *                order_by            Order by (Default: notification_time)
108      *                order_dir            Order direction (Default: DESC)
109      *                 limit                Number of notifications to load (Default: 5)
110      *                 start                Notifications offset (Default: 0)
111      *                 all_unread            Load all unread notifications? If set to true, count_unread is set to true (Default: false)
112      *                 count_unread        Count all unread notifications? (Default: false)
113      *                 count_total            Count all notifications? (Default: false)
114      * @return array Array of information based on the request with keys:
115      *    'notifications'        array of notification type objects
116      *    'unread_count'        number of unread notifications the user has if count_unread is true in the options
117      *    'total_count'        number of notifications the user has if count_total is true in the options
118      */
119      public function load_notifications(array $options = array())
120      {
121          // Merge default options
122          $options = array_merge(array(
123              'notification_id'    => false,
124              'user_id'            => $this->user->data['user_id'],
125              'order_by'            => 'notification_time',
126              'order_dir'            => 'DESC',
127              'limit'                => 0,
128              'start'                => 0,
129              'all_unread'        => false,
130              'count_unread'        => false,
131              'count_total'        => false,
132          ), $options);
133   
134          // If all_unread, count_unread must be true
135          $options['count_unread'] = ($options['all_unread']) ? true : $options['count_unread'];
136   
137          // Anonymous users and bots never receive notifications
138          if ($options['user_id'] == $this->user->data['user_id'] && ($this->user->data['user_id'] == ANONYMOUS || $this->user->data['user_type'] == USER_IGNORE))
139          {
140              return array(
141                  'notifications'        => array(),
142                  'unread_count'        => 0,
143                  'total_count'        => 0,
144              );
145          }
146   
147          $notifications = $user_ids = array();
148          $load_special = array();
149          $total_count = $unread_count = 0;
150   
151          if ($options['count_unread'])
152          {
153              // Get the total number of unread notifications
154              $sql = 'SELECT COUNT(n.notification_id) AS unread_count
155                  FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
156                  WHERE n.user_id = ' . (int) $options['user_id'] . '
157                      AND n.notification_read = 0
158                      AND nt.notification_type_id = n.notification_type_id
159                      AND nt.notification_type_enabled = 1';
160              $result = $this->db->sql_query($sql);
161              $unread_count = (int) $this->db->sql_fetchfield('unread_count');
162              $this->db->sql_freeresult($result);
163          }
164   
165          if ($options['count_total'])
166          {
167              // Get the total number of notifications
168              $sql = 'SELECT COUNT(n.notification_id) AS total_count
169                  FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
170                  WHERE n.user_id = ' . (int) $options['user_id'] . '
171                      AND nt.notification_type_id = n.notification_type_id
172                      AND nt.notification_type_enabled = 1';
173              $result = $this->db->sql_query($sql);
174              $total_count = (int) $this->db->sql_fetchfield('total_count');
175              $this->db->sql_freeresult($result);
176          }
177   
178          if (!$options['count_total'] || $total_count)
179          {
180              $rowset = array();
181   
182              // Get the main notifications
183              $sql = 'SELECT n.*, nt.notification_type_name
184                  FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
185                  WHERE n.user_id = ' . (int) $options['user_id'] .
186                      (($options['notification_id']) ? ((is_array($options['notification_id'])) ? ' AND ' . $this->db->sql_in_set('n.notification_id', $options['notification_id']) : ' AND n.notification_id = ' . (int) $options['notification_id']) : '') . '
187                      AND nt.notification_type_id = n.notification_type_id
188                      AND nt.notification_type_enabled = 1
189                  ORDER BY n.' . $this->db->sql_escape($options['order_by']) . ' ' . $this->db->sql_escape($options['order_dir']);
190              $result = $this->db->sql_query_limit($sql, $options['limit'], $options['start']);
191   
192              while ($row = $this->db->sql_fetchrow($result))
193              {
194                  $rowset[$row['notification_id']] = $row;
195              }
196              $this->db->sql_freeresult($result);
197   
198              // Get all unread notifications
199              if ($unread_count && $options['all_unread'] && !empty($rowset))
200              {
201                  $sql = 'SELECT n.*, nt.notification_type_name
202                  FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
203                      WHERE n.user_id = ' . (int) $options['user_id'] . '
204                          AND n.notification_read = 0
205                          AND ' . $this->db->sql_in_set('n.notification_id', array_keys($rowset), true) . '
206                          AND nt.notification_type_id = n.notification_type_id
207                          AND nt.notification_type_enabled = 1
208                      ORDER BY n.' . $this->db->sql_escape($options['order_by']) . ' ' . $this->db->sql_escape($options['order_dir']);
209                  $result = $this->db->sql_query_limit($sql, $options['limit'], $options['start']);
210   
211                  while ($row = $this->db->sql_fetchrow($result))
212                  {
213                      $rowset[$row['notification_id']] = $row;
214                  }
215                  $this->db->sql_freeresult($result);
216              }
217   
218              foreach ($rowset as $row)
219              {
220                  $notification = $this->get_item_type_class($row['notification_type_name'], $row);
221   
222                  // Array of user_ids to query all at once
223                  $user_ids = array_merge($user_ids, $notification->users_to_query());
224   
225                  // Some notification types also require querying additional tables themselves
226                  if (!isset($load_special[$row['notification_type_name']]))
227                  {
228                      $load_special[$row['notification_type_name']] = array();
229                  }
230                  $load_special[$row['notification_type_name']] = array_merge($load_special[$row['notification_type_name']], $notification->get_load_special());
231   
232                  $notifications[$row['notification_id']] = $notification;
233              }
234   
235              $this->user_loader->load_users($user_ids);
236   
237              // Allow each type to load its own special items
238              foreach ($load_special as $item_type => $data)
239              {
240                  $item_class = $this->get_item_type_class($item_type);
241   
242                  $item_class->load_special($data, $notifications);
243              }
244          }
245   
246          return array(
247              'notifications'        => $notifications,
248              'unread_count'        => $unread_count,
249              'total_count'        => $total_count,
250          );
251      }
252   
253      /**
254      * Mark notifications read
255      *
256      * @param bool|string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types). False to mark read for all item types
257      * @param bool|int|array $item_id Item id or array of item ids. False to mark read for all item ids
258      * @param bool|int|array $user_id User id or array of user ids. False to mark read for all user ids
259      * @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False)
260      */
261      public function mark_notifications_read($notification_type_name, $item_id, $user_id, $time = false)
262      {
263          $time = ($time !== false) ? $time : time();
264   
265          $sql = 'UPDATE ' . $this->notifications_table . "
266              SET notification_read = 1
267              WHERE notification_time <= " . (int) $time .
268                  (($notification_type_name !== false) ? ' AND ' .
269                      (is_array($notification_type_name) ? $this->db->sql_in_set('notification_type_id', $this->get_notification_type_ids($notification_type_name)) : 'notification_type_id = ' . $this->get_notification_type_id($notification_type_name)) : '') .
270                  (($user_id !== false) ? ' AND ' . (is_array($user_id) ? $this->db->sql_in_set('user_id', $user_id) : 'user_id = ' . (int) $user_id) : '') .
271                  (($item_id !== false) ? ' AND ' . (is_array($item_id) ? $this->db->sql_in_set('item_id', $item_id) : 'item_id = ' . (int) $item_id) : '');
272          $this->db->sql_query($sql);
273      }
274   
275      /**
276      * Mark notifications read from a parent identifier
277      *
278      * @param string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
279      * @param bool|int|array $item_parent_id Item parent id or array of item parent ids. False to mark read for all item parent ids
280      * @param bool|int|array $user_id User id or array of user ids. False to mark read for all user ids
281      * @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False)
282      */
283      public function mark_notifications_read_by_parent($notification_type_name, $item_parent_id, $user_id, $time = false)
284      {
285          $time = ($time !== false) ? $time : time();
286   
287          $sql = 'UPDATE ' . $this->notifications_table . "
288              SET notification_read = 1
289              WHERE notification_time <= " . (int) $time .
290                  (($notification_type_name !== false) ? ' AND ' .
291                      (is_array($notification_type_name) ? $this->db->sql_in_set('notification_type_id', $this->get_notification_type_ids($notification_type_name)) : 'notification_type_id = ' . $this->get_notification_type_id($notification_type_name)) : '') .
292                  (($item_parent_id !== false) ? ' AND ' . (is_array($item_parent_id) ? $this->db->sql_in_set('item_parent_id', $item_parent_id) : 'item_parent_id = ' . (int) $item_parent_id) : '') .
293                  (($user_id !== false) ? ' AND ' . (is_array($user_id) ? $this->db->sql_in_set('user_id', $user_id) : 'user_id = ' . (int) $user_id) : '');
294          $this->db->sql_query($sql);
295      }
296   
297      /**
298      * Mark notifications read
299      *
300      * @param int|array $notification_id Notification id or array of notification ids.
301      * @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False)
302      */
303      public function mark_notifications_read_by_id($notification_id, $time = false)
304      {
305          $time = ($time !== false) ? $time : time();
306   
307          $sql = 'UPDATE ' . $this->notifications_table . "
308              SET notification_read = 1
309              WHERE notification_time <= " . (int) $time . '
310                  AND ' . ((is_array($notification_id)) ? $this->db->sql_in_set('notification_id', $notification_id) : 'notification_id = ' . (int) $notification_id);
311          $this->db->sql_query($sql);
312      }
313   
314      /**
315      * Add a notification
316      *
317      * @param string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
318      *            Note: If you send an array of types, any user who could receive multiple notifications from this single item will only receive
319      *             a single notification. If they MUST receive multiple notifications, call this function multiple times instead of sending an array
320      * @param array $data Data specific for this type that will be inserted
321      * @param array $options Optional options to control what notifications are loaded
322      *             ignore_users    array of data to specify which users should not receive certain types of notifications
323      * @return array Information about what users were notified and how they were notified
324      */
325      public function add_notifications($notification_type_name, $data, array $options = array())
326      {
327          $options = array_merge(array(
328              'ignore_users'        => array(),
329          ), $options);
330   
331          if (is_array($notification_type_name))
332          {
333              $notified_users = array();
334              $temp_options = $options;
335   
336              foreach ($notification_type_name as $type)
337              {
338                  $temp_options['ignore_users'] = $options['ignore_users'] + $notified_users;
339                  $notified_users += $this->add_notifications($type, $data, $temp_options);
340              }
341   
342              return $notified_users;
343          }
344   
345          $item_id = $this->get_item_type_class($notification_type_name)->get_item_id($data);
346   
347          // find out which users want to receive this type of notification
348          $notify_users = $this->get_item_type_class($notification_type_name)->find_users_for_notification($data, $options);
349   
350          $this->add_notifications_for_users($notification_type_name, $data, $notify_users);
351   
352          return $notify_users;
353      }
354   
355      /**
356      * Add a notification for specific users
357      *
358      * @param string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
359      * @param array $data Data specific for this type that will be inserted
360      * @param array $notify_users User list to notify
361      */
362      public function add_notifications_for_users($notification_type_name, $data, $notify_users)
363      {
364          if (is_array($notification_type_name))
365          {
366              foreach ($notification_type_name as $type)
367              {
368                  $this->add_notifications_for_users($type, $data, $notify_users);
369              }
370   
371              return;
372          }
373   
374          $notification_type_id = $this->get_notification_type_id($notification_type_name);
375   
376          $item_id = $this->get_item_type_class($notification_type_name)->get_item_id($data);
377   
378          $user_ids = array();
379          $notification_objects = $notification_methods = array();
380   
381          // Never send notifications to the anonymous user!
382          unset($notify_users[ANONYMOUS]);
383   
384          // Make sure not to send new notifications to users who've already been notified about this item
385          // This may happen when an item was added, but now new users are able to see the item
386          $sql = 'SELECT n.user_id
387              FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
388              WHERE n.notification_type_id = ' . (int) $notification_type_id . '
389                  AND n.item_id = ' . (int) $item_id . '
390                  AND nt.notification_type_id = n.notification_type_id
391                  AND nt.notification_type_enabled = 1';
392          $result = $this->db->sql_query($sql);
393          while ($row = $this->db->sql_fetchrow($result))
394          {
395              unset($notify_users[$row['user_id']]);
396          }
397          $this->db->sql_freeresult($result);
398   
399          if (!sizeof($notify_users))
400          {
401              return;
402          }
403   
404          // Allow notifications to perform actions before creating the insert array (such as run a query to cache some data needed for all notifications)
405          $notification = $this->get_item_type_class($notification_type_name);
406          $pre_create_data = $notification->pre_create_insert_array($data, $notify_users);
407          unset($notification);
408   
409          $insert_buffer = new \phpbb\db\sql_insert_buffer($this->db, $this->notifications_table);
410   
411          // Go through each user so we can insert a row in the DB and then notify them by their desired means
412          foreach ($notify_users as $user => $methods)
413          {
414              $notification = $this->get_item_type_class($notification_type_name);
415   
416              $notification->user_id = (int) $user;
417   
418              // Insert notification row using buffer.
419              $insert_buffer->insert($notification->create_insert_array($data, $pre_create_data));
420   
421              // Users are needed to send notifications
422              $user_ids = array_merge($user_ids, $notification->users_to_query());
423   
424              foreach ($methods as $method)
425              {
426                  // setup the notification methods and add the notification to the queue
427                  if ($method) // blank means we just insert it as a notification, but do not notify them by any other means
428                  {
429                      if (!isset($notification_methods[$method]))
430                      {
431                          $notification_methods[$method] = $this->get_method_class($method);
432                      }
433   
434                      $notification_methods[$method]->add_to_queue($notification);
435                  }
436              }
437          }
438   
439          $insert_buffer->flush();
440   
441          // We need to load all of the users to send notifications
442          $this->user_loader->load_users($user_ids);
443   
444          // run the queue for each method to send notifications
445          foreach ($notification_methods as $method)
446          {
447              $method->notify();
448          }
449      }
450   
451      /**
452      * Update a notification
453      *
454      * @param string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
455      * @param array $data Data specific for this type that will be updated
456      */
457      public function update_notifications($notification_type_name, $data)
458      {
459          if (is_array($notification_type_name))
460          {
461              foreach ($notification_type_name as $type)
462              {
463                  $this->update_notifications($type, $data);
464              }
465   
466              return;
467          }
468   
469          $notification = $this->get_item_type_class($notification_type_name);
470   
471          // Allow the notifications class to over-ride the update_notifications functionality
472          if (method_exists($notification, 'update_notifications'))
473          {
474              // Return False to over-ride the rest of the update
475              if ($notification->update_notifications($data) === false)
476              {
477                  return;
478              }
479          }
480   
481          $notification_type_id = $this->get_notification_type_id($notification_type_name);
482          $item_id = $notification->get_item_id($data);
483          $update_array = $notification->create_update_array($data);
484   
485          $sql = 'UPDATE ' . $this->notifications_table . '
486              SET ' . $this->db->sql_build_array('UPDATE', $update_array) . '
487              WHERE notification_type_id = ' . (int) $notification_type_id . '
488                  AND item_id = ' . (int) $item_id;
489          $this->db->sql_query($sql);
490      }
491   
492      /**
493      * Delete a notification
494      *
495      * @param string|array $notification_type_name Type identifier or array of item types (only acceptable if the $item_id is identical for the specified types)
496      * @param int|array $item_id Identifier within the type (or array of ids)
497      * @param mixed $parent_id Parent identifier within the type (or array of ids), used in combination with item_id if specified (Default: false; not checked)
498      */
499      public function delete_notifications($notification_type_name, $item_id, $parent_id = false)
500      {
501          if (is_array($notification_type_name))
502          {
503              foreach ($notification_type_name as $type)
504              {
505                  $this->delete_notifications($type, $item_id, $parent_id);
506              }
507   
508              return;
509          }
510   
511          $notification_type_id = $this->get_notification_type_id($notification_type_name);
512   
513          $sql = 'DELETE FROM ' . $this->notifications_table . '
514              WHERE notification_type_id = ' . (int) $notification_type_id . '
515                  AND ' . (is_array($item_id) ? $this->db->sql_in_set('item_id', $item_id) : 'item_id = ' . (int) $item_id) .
516                  (($parent_id !== false) ? ' AND ' . ((is_array($parent_id) ? $this->db->sql_in_set('item_parent_id', $parent_id) : 'item_parent_id = ' . (int) $parent_id)) : '');
517          $this->db->sql_query($sql);
518      }
519   
520      /**
521      * Get all of the subscription types
522      *
523      * @return array Array of item types
524      */
525      public function get_subscription_types()
526      {
527          $subscription_types = array();
528   
529          foreach ($this->notification_types as $type_name => $data)
530          {
531              $type = $this->get_item_type_class($type_name);
532   
533              if ($type instanceof \phpbb\notification\type\type_interface && $type->is_available())
534              {
535                  $options = array_merge(array(
536                      'id'        => $type->get_type(),
537                      'lang'        => 'NOTIFICATION_TYPE_' . strtoupper($type->get_type()),
538                      'group'        => 'NOTIFICATION_GROUP_MISCELLANEOUS',
539                  ), (($type::$notification_option !== false) ? $type::$notification_option : array()));
540   
541                  $subscription_types[$options['group']][$options['id']] = $options;
542              }
543          }
544   
545          // Move Miscellaneous to the very last section
546          if (isset($subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS']))
547          {
548              $miscellaneous = $subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS'];
549              unset($subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS']);
550              $subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS'] = $miscellaneous;
551          }
552   
553          return $subscription_types;
554      }
555   
556      /**
557      * Get all of the subscription methods
558      *
559      * @return array Array of methods
560      */
561      public function get_subscription_methods()
562      {
563          $subscription_methods = array();
564   
565          foreach ($this->notification_methods as $method_name => $data)
566          {
567              $method = $this->get_method_class($method_name);
568   
569              if ($method instanceof \phpbb\notification\method\method_interface && $method->is_available())
570              {
571                  $subscription_methods[$method_name] = array(
572                      'id'        => $method->get_type(),
573                      'lang'        => str_replace('.', '_', strtoupper($method->get_type())),
574                  );
575              }
576          }
577   
578          return $subscription_methods;
579      }
580   
581   
582      /**
583      * Get user's notification data
584      *
585      * @param int $user_id The user_id of the user to get the notifications for
586      *
587      * @return array User's notification
588      */
589      protected function get_user_notifications($user_id)
590      {
591          $sql = 'SELECT method, notify, item_type
592                  FROM ' . $this->user_notifications_table . '
593                  WHERE user_id = ' . (int) $user_id . '
594                      AND item_id = 0';
595   
596          $result = $this->db->sql_query($sql);
597          $user_notifications = array();
598   
599          while ($row = $this->db->sql_fetchrow($result))
600          {
601              $user_notifications[$row['item_type']][] = $row;
602          }
603   
604          $this->db->sql_freeresult($result);
605   
606          return $user_notifications;
607      }
608   
609      /**
610      * Get global subscriptions (item_id = 0)
611      *
612      * @param bool|int $user_id The user_id to add the subscription for (bool false for current user)
613      *
614      * @return array Subscriptions
615      */
616      public function get_global_subscriptions($user_id = false)
617      {
618          $user_id = ($user_id === false) ? $this->user->data['user_id'] : $user_id;
619   
620          $subscriptions = array();
621   
622          $user_notifications = $this->get_user_notifications($user_id);
623   
624          foreach ($this->get_subscription_types() as $types)
625          {
626              foreach ($types as $id => $type)
627              {
628   
629                  if (empty($user_notifications[$id]))
630                  {
631                      // No rows at all, default to ''
632                      $subscriptions[$id] = array('');
633                  }
634                  else
635                  {
636                      foreach ($user_notifications[$id] as $user_notification)
637                      {
638                          if (!$user_notification['notify'])
639                          {
640                              continue;
641                          }
642   
643                          if (!isset($subscriptions[$id]))
644                          {
645                              $subscriptions[$id] = array();
646                          }
647   
648                          $subscriptions[$id][] = $user_notification['method'];
649                      }
650                  }
651              }
652          }
653   
654          return $subscriptions;
655      }
656   
657      /**
658      * Add a subscription
659      *
660      * @param string $item_type Type identifier of the subscription
661      * @param int $item_id The id of the item
662      * @param string $method The method of the notification e.g. '', 'email', or 'jabber'
663      * @param bool|int $user_id The user_id to add the subscription for (bool false for current user)
664      */
665      public function add_subscription($item_type, $item_id = 0, $method = '', $user_id = false)
666      {
667          if ($method !== '')
668          {
669              // Make sure to subscribe them to the base subscription
670              $this->add_subscription($item_type, $item_id, '', $user_id);
671          }
672   
673          $user_id = ($user_id === false) ? $this->user->data['user_id'] : $user_id;
674   
675          $sql = 'SELECT notify
676              FROM ' . $this->user_notifications_table . "
677              WHERE item_type = '" . $this->db->sql_escape($item_type) . "'
678                  AND item_id = " . (int) $item_id . '
679                  AND user_id = ' .(int) $user_id . "
680                  AND method = '" . $this->db->sql_escape($method) . "'";
681          $this->db->sql_query($sql);
682          $current = $this->db->sql_fetchfield('notify');
683          $this->db->sql_freeresult();
684   
685          if ($current === false)
686          {
687              $sql = 'INSERT INTO ' . $this->user_notifications_table . ' ' .
688                  $this->db->sql_build_array('INSERT', array(
689                      'item_type'        => $item_type,
690                      'item_id'        => (int) $item_id,
691                      'user_id'        => (int) $user_id,
692                      'method'        => $method,
693                      'notify'        => 1,
694                  ));
695              $this->db->sql_query($sql);
696          }
697          else if (!$current)
698          {
699              $sql = 'UPDATE ' . $this->user_notifications_table . "
700                  SET notify = 1
701                  WHERE item_type = '" . $this->db->sql_escape($item_type) . "'
702                      AND item_id = " . (int) $item_id . '
703                      AND user_id = ' .(int) $user_id . "
704                      AND method = '" . $this->db->sql_escape($method) . "'";
705              $this->db->sql_query($sql);
706          }
707      }
708   
709      /**
710      * Delete a subscription
711      *
712      * @param string $item_type Type identifier of the subscription
713      * @param int $item_id The id of the item
714      * @param string $method The method of the notification e.g. '', 'email', or 'jabber'
715      * @param bool|int $user_id The user_id to add the subscription for (bool false for current user)
716      */
717      public function delete_subscription($item_type, $item_id = 0, $method = '', $user_id = false)
718      {
719          $user_id = ($user_id === false) ? $this->user->data['user_id'] : $user_id;
720   
721          // If no method, make sure that no other notification methods for this item are selected before deleting
722          if ($method === '')
723          {
724              $sql = 'SELECT COUNT(*) as num_notifications
725                  FROM ' . $this->user_notifications_table . "
726                  WHERE item_type = '" . $this->db->sql_escape($item_type) . "'
727                      AND item_id = " . (int) $item_id . '
728                      AND user_id = ' .(int) $user_id . "
729                      AND method <> ''
730                      AND notify = 1";
731              $this->db->sql_query($sql);
732              $num_notifications = $this->db->sql_fetchfield('num_notifications');
733              $this->db->sql_freeresult();
734   
735              if ($num_notifications)
736              {
737                  return;
738              }
739          }
740   
741          $sql = 'UPDATE ' . $this->user_notifications_table . "
742              SET notify = 0
743              WHERE item_type = '" . $this->db->sql_escape($item_type) . "'
744                  AND item_id = " . (int) $item_id . '
745                  AND user_id = ' .(int) $user_id . "
746                  AND method = '" . $this->db->sql_escape($method) . "'";
747          $this->db->sql_query($sql);
748   
749          if (!$this->db->sql_affectedrows())
750          {
751              $sql = 'INSERT INTO ' . $this->user_notifications_table . ' ' .
752                  $this->db->sql_build_array('INSERT', array(
753                      'item_type'        => $item_type,
754                      'item_id'        => (int) $item_id,
755                      'user_id'        => (int) $user_id,
756                      'method'        => $method,
757                      'notify'        => 0,
758                  ));
759              $this->db->sql_query($sql);
760          }
761      }
762   
763      /**
764      * Disable all notifications of a certain type
765      *
766      * This should be called when an extension which has notification types
767      * is disabled so that all those notifications are hidden and do not
768      * cause errors
769      *
770      * @param string $notification_type_name Type identifier of the subscription
771      */
772      public function disable_notifications($notification_type_name)
773      {
774          $sql = 'UPDATE ' . $this->notification_types_table . "
775              SET notification_type_enabled = 0
776              WHERE notification_type_name = '" . $this->db->sql_escape($notification_type_name) . "'";
777          $this->db->sql_query($sql);
778      }
779   
780      /**
781      * Purge all notifications of a certain type
782      *
783      * This should be called when an extension which has notification types
784      * is purged so that all those notifications are removed
785      *
786      * @param string $notification_type_name Type identifier of the subscription
787      */
788      public function purge_notifications($notification_type_name)
789      {
790          // If a notification is never used, its type will not be added to the database
791          // nor its id cached. If this method is called by an extension during the
792          // purge step, and that extension never used its notifications,
793          // get_notification_type_id() will throw an exception. However,
794          // because no notification type was added to the database,
795          // there is nothing to delete, so we can silently drop the exception.
796          try
797          {
798              $notification_type_id = $this->get_notification_type_id($notification_type_name);
799   
800              $sql = 'DELETE FROM ' . $this->notifications_table . '
801                  WHERE notification_type_id = ' . (int) $notification_type_id;
802              $this->db->sql_query($sql);
803   
804              $sql = 'DELETE FROM ' . $this->notification_types_table . '
805                  WHERE notification_type_id = ' . (int) $notification_type_id;
806              $this->db->sql_query($sql);
807   
808              $this->cache->destroy('notification_type_ids');
809          }
810          catch (\phpbb\notification\exception $e)
811          {
812              // Continue
813          }
814      }
815   
816      /**
817      * Enable all notifications of a certain type
818      *
819      * This should be called when an extension which has notification types
820      * that was disabled is re-enabled so that all those notifications that
821      * were hidden are shown again
822      *
823      * @param string $notification_type_name Type identifier of the subscription
824      */
825      public function enable_notifications($notification_type_name)
826      {
827          $sql = 'UPDATE ' . $this->notification_types_table . "
828              SET notification_type_enabled = 1
829              WHERE notification_type_name = '" . $this->db->sql_escape($notification_type_name) . "'";
830          $this->db->sql_query($sql);
831      }
832   
833      /**
834      * Delete all notifications older than a certain time
835      *
836      * @param int $timestamp Unix timestamp to delete all notifications that were created before
837      * @param bool $only_read True (default) to only prune read notifications
838      */
839      public function prune_notifications($timestamp, $only_read = true)
840      {
841          $sql = 'DELETE FROM ' . $this->notifications_table . '
842              WHERE notification_time < ' . (int) $timestamp .
843                  (($only_read) ? ' AND notification_read = 1' : '');
844          $this->db->sql_query($sql);
845   
846          $this->config->set('read_notification_last_gc', time(), false);
847      }
848   
849      /**
850      * Helper to get the notifications item type class and set it up
851      */
852      public function get_item_type_class($notification_type_name, $data = array())
853      {
854          $item = $this->load_object($notification_type_name);
855   
856          $item->set_initial_data($data);
857   
858          return $item;
859      }
860   
861      /**
862      * Helper to get the notifications method class and set it up
863      */
864      public function get_method_class($method_name)
865      {
866          return $this->load_object($method_name);
867      }
868   
869      /**
870      * Helper to load objects (notification types/methods)
871      */
872      protected function load_object($object_name)
873      {
874          $object = $this->phpbb_container->get($object_name);
875   
876          if (method_exists($object, 'set_notification_manager'))
877          {
878              $object->set_notification_manager($this);
879          }
880   
881          return $object;
882      }
883   
884      /**
885      * Get the notification type id from the name
886      *
887      * @param string $notification_type_name The name
888      * @return int the notification_type_id
889      * @throws \phpbb\notification\exception
890      */
891      public function get_notification_type_id($notification_type_name)
892      {
893          $notification_type_ids = $this->cache->get('notification_type_ids');
894   
895          if ($notification_type_ids === false)
896          {
897              $notification_type_ids = array();
898   
899              $sql = 'SELECT notification_type_id, notification_type_name
900                  FROM ' . $this->notification_types_table;
901              $result = $this->db->sql_query($sql);
902              while ($row = $this->db->sql_fetchrow($result))
903              {
904                  $notification_type_ids[$row['notification_type_name']] = (int) $row['notification_type_id'];
905              }
906              $this->db->sql_freeresult($result);
907   
908              $this->cache->put('notification_type_ids', $notification_type_ids);
909          }
910   
911          if (!isset($notification_type_ids[$notification_type_name]))
912          {
913              if (!isset($this->notification_types[$notification_type_name]) && !isset($this->notification_types['notification.type.' . $notification_type_name]))
914              {
915                  throw new \phpbb\notification\exception($this->user->lang('NOTIFICATION_TYPE_NOT_EXIST', $notification_type_name));
916              }
917   
918              $sql = 'INSERT INTO ' . $this->notification_types_table . ' ' . $this->db->sql_build_array('INSERT', array(
919                  'notification_type_name'        => $notification_type_name,
920                  'notification_type_enabled'        => 1,
921              ));
922              $this->db->sql_query($sql);
923   
924              $notification_type_ids[$notification_type_name] = (int) $this->db->sql_nextid();
925   
926              $this->cache->put('notification_type_ids', $notification_type_ids);
927          }
928   
929          return $notification_type_ids[$notification_type_name];
930      }
931   
932      /**
933      * Get notification type ids (as an array)
934      *
935      * @param array $notification_type_names Array of strings
936      * @return array Array of integers
937      */
938      public function get_notification_type_ids(array $notification_type_names)
939      {
940          $notification_type_ids = array();
941   
942          foreach ($notification_type_names as $name)
943          {
944              $notification_type_ids[$name] = $this->get_notification_type_id($name);
945          }
946   
947          return $notification_type_ids;
948      }
949  }
950