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