Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

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: 02.04.2025, 15:02 - Dateigröße: 33.25 KiB


0001  <?php
0002  /**
0003  *
0004  * This file is part of the phpBB Forum Software package.
0005  *
0006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
0007  * @license GNU General Public License, version 2 (GPL-2.0)
0008  *
0009  * For full copyright and license information, please see
0010  * the docs/CREDITS.txt file.
0011  *
0012  */
0013   
0014  namespace phpbb\notification;
0015   
0016  use Symfony\Component\DependencyInjection\ContainerInterface;
0017   
0018  /**
0019  * Notifications service class
0020  */
0021  class manager
0022  {
0023      /** @var array */
0024      protected $notification_types;
0025   
0026      /** @var array */
0027      protected $subscription_types;
0028   
0029      /** @var method\method_interface[] */
0030      protected $notification_methods;
0031   
0032      /** @var ContainerInterface */
0033      protected $phpbb_container;
0034   
0035      /** @var \phpbb\user_loader */
0036      protected $user_loader;
0037   
0038      /** @var \phpbb\event\dispatcher_interface */
0039      protected $phpbb_dispatcher;
0040   
0041      /** @var \phpbb\db\driver\driver_interface */
0042      protected $db;
0043   
0044      /** @var \phpbb\cache\service */
0045      protected $cache;
0046   
0047      /** @var \phpbb\language\language */
0048      protected $language;
0049   
0050      /** @var \phpbb\user */
0051      protected $user;
0052   
0053      /** @var string */
0054      protected $notification_types_table;
0055   
0056      /** @var string */
0057      protected $user_notifications_table;
0058   
0059      /**
0060      * Notification Constructor
0061      *
0062      * @param array $notification_types
0063      * @param array $notification_methods
0064      * @param ContainerInterface $phpbb_container
0065      * @param \phpbb\user_loader $user_loader
0066      * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher
0067      * @param \phpbb\db\driver\driver_interface $db
0068      * @param \phpbb\cache\service $cache
0069      * @param \phpbb\language\language $language
0070      * @param \phpbb\user $user
0071      * @param string $notification_types_table
0072      * @param string $user_notifications_table
0073      *
0074      * @return \phpbb\notification\manager
0075      */
0076      public function __construct($notification_types, $notification_methods, ContainerInterface $phpbb_container, \phpbb\user_loader $user_loader, \phpbb\event\dispatcher_interface $phpbb_dispatcher, \phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, \phpbb\language\language $language, \phpbb\user $user, $notification_types_table, $user_notifications_table)
0077      {
0078          $this->notification_types = $notification_types;
0079          $this->notification_methods = $notification_methods;
0080          $this->phpbb_container = $phpbb_container;
0081   
0082          $this->user_loader = $user_loader;
0083          $this->phpbb_dispatcher = $phpbb_dispatcher;
0084          $this->db = $db;
0085          $this->cache = $cache;
0086          $this->language = $language;
0087          $this->user = $user;
0088   
0089          $this->notification_types_table = $notification_types_table;
0090          $this->user_notifications_table = $user_notifications_table;
0091      }
0092   
0093      /**
0094      * Load the user's notifications for a given method
0095      *
0096      * @param string $method_name
0097      * @param array $options Optional options to control what notifications are loaded
0098      *                notification_id        Notification id to load (or array of notification ids)
0099      *                user_id                User id to load notifications for (Default: $user->data['user_id'])
0100      *                order_by            Order by (Default: notification_time)
0101      *                order_dir            Order direction (Default: DESC)
0102      *                 limit                Number of notifications to load (Default: 5)
0103      *                 start                Notifications offset (Default: 0)
0104      *                 all_unread            Load all unread notifications? If set to true, count_unread is set to true (Default: false)
0105      *                 count_unread        Count all unread notifications? (Default: false)
0106      *                 count_total            Count all notifications? (Default: false)
0107      * @return array Array of information based on the request with keys:
0108      *    'notifications'        array of notification type objects
0109      *    'unread_count'        number of unread notifications the user has if count_unread is true in the options
0110      *    'total_count'        number of notifications the user has if count_total is true in the options
0111      * @throws \phpbb\notification\exception when the method doesn't refer to a class extending \phpbb\notification\method\method_interface
0112      */
0113      public function load_notifications($method_name, array $options = array())
0114      {
0115          $method = $this->get_method_class($method_name);
0116   
0117          if (! $method instanceof \phpbb\notification\method\method_interface)
0118          {
0119              throw new \phpbb\notification\exception($this->language->lang('NOTIFICATION_METHOD_INVALID', $method_name));
0120          }
0121          else if ($method->is_available())
0122          {
0123              return $method->load_notifications($options);
0124          }
0125          else
0126          {
0127              return array(
0128                  'notifications'        => array(),
0129                  'unread_count'        => 0,
0130                  'total_count'        => 0,
0131              );
0132          }
0133      }
0134   
0135      /**
0136       * Mark notifications read or unread for all available methods
0137       *
0138       * @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
0139       * @param bool|int|array $item_id Item id or array of item ids. False to mark read for all item ids
0140       * @param bool|int|array $user_id User id or array of user ids. False to mark read for all user ids
0141       * @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False)
0142       *
0143       * @deprecated since 3.2
0144       */
0145      public function mark_notifications_read($notification_type_name, $item_id, $user_id, $time = false)
0146      {
0147          $this->mark_notifications($notification_type_name, $item_id, $user_id, $time);
0148      }
0149   
0150      /**
0151      * Mark notifications read or unread for all available methods
0152      *
0153      * @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
0154      * @param bool|int|array $item_id Item id or array of item ids. False to mark read for all item ids
0155      * @param bool|int|array $user_id User id or array of user ids. False to mark read for all user ids
0156      * @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False)
0157      * @param bool $mark_read Define if the notification as to be set to True or False. (Default: True)
0158      */
0159      public function mark_notifications($notification_type_name, $item_id, $user_id, $time = false, $mark_read = true)
0160      {
0161          if (is_array($notification_type_name))
0162          {
0163              $notification_type_id = $this->get_notification_type_ids($notification_type_name);
0164          }
0165          else if ($notification_type_name !== false)
0166          {
0167              $notification_type_id = $this->get_notification_type_id($notification_type_name);
0168          }
0169          else
0170          {
0171              $notification_type_id = false;
0172          }
0173   
0174          /** @var method\method_interface $method */
0175          foreach ($this->get_available_subscription_methods() as $method)
0176          {
0177              $method->mark_notifications($notification_type_id, $item_id, $user_id, $time, $mark_read);
0178          }
0179      }
0180   
0181      /**
0182       * Mark notifications read or unread from a parent identifier for all available methods
0183       *
0184       * @param string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
0185       * @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
0186       * @param bool|int|array $user_id User id or array of user ids. False to mark read for all user ids
0187       * @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False)
0188       *
0189       * @deprecated since 3.2
0190       */
0191      public function mark_notifications_read_by_parent($notification_type_name, $item_parent_id, $user_id, $time = false)
0192      {
0193          $this->mark_notifications_by_parent($notification_type_name, $item_parent_id, $user_id, $time);
0194      }
0195   
0196      /**
0197      * Mark notifications read or unread from a parent identifier for all available methods
0198      *
0199      * @param string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
0200      * @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
0201      * @param bool|int|array $user_id User id or array of user ids. False to mark read for all user ids
0202      * @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False)
0203      * @param bool $mark_read Define if the notification as to be set to True or False. (Default: True)
0204      */
0205      public function mark_notifications_by_parent($notification_type_name, $item_parent_id, $user_id, $time = false, $mark_read = true)
0206      {
0207          if (is_array($notification_type_name))
0208          {
0209              $notification_type_id = $this->get_notification_type_ids($notification_type_name);
0210          }
0211          else
0212          {
0213              $notification_type_id = $this->get_notification_type_id($notification_type_name);
0214          }
0215   
0216          /** @var method\method_interface $method */
0217          foreach ($this->get_available_subscription_methods() as $method)
0218          {
0219              $method->mark_notifications_by_parent($notification_type_id, $item_parent_id, $user_id, $time, $mark_read);
0220          }
0221      }
0222   
0223      /**
0224      * Mark notifications read or unread for a given method
0225      *
0226      * @param string $method_name
0227      * @param int|array $notification_id Notification id or array of notification ids.
0228      * @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False)
0229      * @param bool $mark_read Define if the notification as to be set to True or False. (Default: True)
0230      */
0231      public function mark_notifications_by_id($method_name, $notification_id, $time = false, $mark_read = true)
0232      {
0233          $method = $this->get_method_class($method_name);
0234   
0235          if ($method instanceof \phpbb\notification\method\method_interface && $method->is_available())
0236          {
0237              $method->mark_notifications_by_id($notification_id, $time, $mark_read);
0238          }
0239      }
0240   
0241      /**
0242      * Add a notification
0243      *
0244      * @param string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
0245      *            Note: If you send an array of types, any user who could receive multiple notifications from this single item will only receive
0246      *             a single notification. If they MUST receive multiple notifications, call this function multiple times instead of sending an array
0247      * @param array $data Data specific for this type that will be inserted
0248      * @param array $options Optional options to control what notifications are loaded
0249      *             ignore_users    array of data to specify which users should not receive certain types of notifications
0250      * @return array Information about what users were notified and how they were notified
0251      */
0252      public function add_notifications($notification_type_name, $data, array $options = array())
0253      {
0254          $options = array_merge(array(
0255              'ignore_users'        => array(),
0256          ), $options);
0257   
0258          $notified_users = [];
0259          $add_notifications_override = false;
0260   
0261          /**
0262          * Get notification data before find_users_for_notification() execute
0263          *
0264          * @event core.notification_manager_add_notifications_before
0265          * @var    bool            add_notifications_override    Flag indicating whether function should return after event
0266          * @var    array|string    notification_type_name        Type identifier or array of item types
0267          * @var    string            data                        Data specific for this notification type that will be inserted
0268          * @var    array             notified_users                Array of notified users
0269          * @var    string            options                        Optional options to control what notifications are loaded
0270          * @since 3.3.6-RC1
0271          */
0272          $vars = [
0273              'add_notifications_override',
0274              'notification_type_name',
0275              'data',
0276              'notified_users',
0277              'options',
0278          ];
0279          extract($this->phpbb_dispatcher->trigger_event('core.notification_manager_add_notifications_before', compact($vars)));
0280   
0281          if ($add_notifications_override)
0282          {
0283              return $notified_users;
0284          }
0285   
0286          if (is_array($notification_type_name))
0287          {
0288              $temp_options = $options;
0289   
0290              foreach ($notification_type_name as $type)
0291              {
0292                  $temp_options['ignore_users'] = $options['ignore_users'] + $notified_users;
0293                  $notified_users += $this->add_notifications($type, $data, $temp_options);
0294              }
0295   
0296              return $notified_users;
0297          }
0298   
0299          // find out which users want to receive this type of notification
0300          $notify_users = $this->get_item_type_class($notification_type_name)->find_users_for_notification($data, $options);
0301   
0302          /**
0303          * Allow filtering the notify_users array for a notification that is about to be sent.
0304          * Here, $notify_users is already filtered by f_read and the ignored list included in the options variable
0305          *
0306          * @event core.notification_manager_add_notifications
0307          * @var    string    notification_type_name        The notification type identifier
0308          * @var    array     data                        Data specific for the notification_type_name used will be inserted
0309          * @var    array     notify_users                The array of userid that are going to be notified for this notification. Set to array() to cancel.
0310          * @var    array     options                        The options that were used when this method was called (read only)
0311          *
0312          * @since 3.1.3-RC1
0313          */
0314          $vars = array(
0315              'notification_type_name',
0316              'data',
0317              'notify_users',
0318              'options',
0319          );
0320          extract($this->phpbb_dispatcher->trigger_event('core.notification_manager_add_notifications', compact($vars)));
0321   
0322          $this->add_notifications_for_users($notification_type_name, $data, $notify_users);
0323   
0324          return $notify_users;
0325      }
0326   
0327      /**
0328      * Add a notification for specific users
0329      *
0330      * @param string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
0331      * @param array $data Data specific for this type that will be inserted
0332      * @param array $notify_users User list to notify
0333      */
0334      public function add_notifications_for_users($notification_type_name, $data, $notify_users)
0335      {
0336          if (is_array($notification_type_name))
0337          {
0338              foreach ($notification_type_name as $type)
0339              {
0340                  $this->add_notifications_for_users($type, $data, $notify_users);
0341              }
0342   
0343              return;
0344          }
0345   
0346          $notification_type_id = $this->get_notification_type_id($notification_type_name);
0347   
0348          $item_id = $this->get_item_type_class($notification_type_name)->get_item_id($data);
0349   
0350          $user_ids = array();
0351          $notification_methods = array();
0352   
0353          // Never send notifications to the anonymous user!
0354          unset($notify_users[ANONYMOUS]);
0355   
0356          // Make sure not to send new notifications to users who've already been notified about this item
0357          // This may happen when an item was added, but now new users are able to see the item
0358          // We remove each user which was already notified by at least one method.
0359          /** @var method\method_interface $method */
0360          foreach ($this->get_subscription_methods_instances() as $method)
0361          {
0362              $notified_users = $method->get_notified_users($notification_type_id, array('item_id' => $item_id));
0363   
0364              foreach ($notified_users as $user => $notifications)
0365              {
0366                  unset($notify_users[$user]);
0367              }
0368          }
0369   
0370          /**
0371          * Allow filtering the $notify_users array by $notification_type_name for a notification that is about to be sent.
0372          * Here, $notify_users is already filtered from users who've already been notified.
0373          *
0374          * @event core.notification_manager_add_notifications_for_users_modify_data
0375          * @var    string    notification_type_name        The notification type identifier
0376          * @var    array     data                        Data specific for this type that will be inserted
0377          * @var    array     notify_users                User list to notify
0378          *
0379          * @since 3.2.10-RC1
0380          * @since 3.3.1-RC1
0381          */
0382          $vars = [
0383              'notification_type_name',
0384              'data',
0385              'notify_users',
0386          ];
0387          extract($this->phpbb_dispatcher->trigger_event('core.notification_manager_add_notifications_for_users_modify_data', compact($vars)));
0388   
0389          if (!count($notify_users))
0390          {
0391              return;
0392          }
0393   
0394          // Allow notifications to perform actions before creating the insert array (such as run a query to cache some data needed for all notifications)
0395          $notification = $this->get_item_type_class($notification_type_name);
0396          $pre_create_data = $notification->pre_create_insert_array($data, $notify_users);
0397          unset($notification);
0398   
0399          // Go through each user so we can insert a row in the DB and then notify them by their desired means
0400          foreach ($notify_users as $user => $methods)
0401          {
0402              $notification = $this->get_item_type_class($notification_type_name);
0403   
0404              $notification->user_id = (int) $user;
0405   
0406              // Generate the insert_array
0407              $notification->create_insert_array($data, $pre_create_data);
0408   
0409              // Users are needed to send notifications
0410              $user_ids = array_merge($user_ids, $notification->users_to_query());
0411   
0412              foreach ($methods as $method)
0413              {
0414                  // Do not load non-existent notification methods
0415                  if (!isset($this->notification_methods[$method]))
0416                  {
0417                      continue;
0418                  }
0419   
0420                  // Setup the notification methods and add the notification to the queue
0421                  if (!isset($notification_methods[$method]))
0422                  {
0423                      $notification_methods[$method] = $this->get_method_class($method);
0424                  }
0425                  $notification_methods[$method]->add_to_queue($notification);
0426              }
0427          }
0428   
0429          // We need to load all of the users to send notifications
0430          $this->user_loader->load_users($user_ids);
0431   
0432          // run the queue for each method to send notifications
0433          foreach ($notification_methods as $method)
0434          {
0435              $method->notify();
0436          }
0437      }
0438   
0439      /**
0440      * Update notification
0441      *
0442      * @param string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
0443      * @param array $data Data specific for this type that will be updated
0444      * @param array $options
0445      */
0446      public function update_notifications($notification_type_name, array $data, array $options = array())
0447      {
0448          if (is_array($notification_type_name))
0449          {
0450              foreach ($notification_type_name as $type)
0451              {
0452                  $this->update_notifications($type, $data);
0453              }
0454   
0455              return;
0456          }
0457   
0458          $this->update_notification($this->get_item_type_class($notification_type_name), $data, $options);
0459      }
0460   
0461      /**
0462      * Update a notification
0463      *
0464      * @param \phpbb\notification\type\type_interface $notification The notification
0465      * @param array $data Data specific for this type that will be updated
0466      * @param array $options
0467      */
0468      public function update_notification(\phpbb\notification\type\type_interface $notification, array $data, array $options = array())
0469      {
0470          if (empty($options))
0471          {
0472              $options['item_id'] = $notification->get_item_id($data);
0473          }
0474   
0475          /** @var method\method_interface $method */
0476          foreach ($this->get_available_subscription_methods() as $method)
0477          {
0478              $method->update_notification($notification, $data, $options);
0479          }
0480      }
0481   
0482      /**
0483      * Delete a notification
0484      *
0485      * @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)
0486      * @param int|array $item_id Identifier within the type (or array of ids)
0487      * @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)
0488      * @param mixed $user_id User id (Default: false; not checked)
0489      */
0490      public function delete_notifications($notification_type_name, $item_id, $parent_id = false, $user_id = false)
0491      {
0492          if (is_array($notification_type_name))
0493          {
0494              foreach ($notification_type_name as $type)
0495              {
0496                  $this->delete_notifications($type, $item_id, $parent_id, $user_id);
0497              }
0498   
0499              return;
0500          }
0501   
0502          $notification_type_id = $this->get_notification_type_id($notification_type_name);
0503   
0504          /** @var method\method_interface $method */
0505          foreach ($this->get_available_subscription_methods() as $method)
0506          {
0507              $method->delete_notifications($notification_type_id, $item_id, $parent_id, $user_id);
0508          }
0509      }
0510   
0511      /**
0512      * Get all of the subscription types
0513      *
0514      * @return array Array of item types
0515      */
0516      public function get_subscription_types()
0517      {
0518          if ($this->subscription_types === null)
0519          {
0520              $this->subscription_types = array();
0521   
0522              foreach ($this->notification_types as $type_name => $data)
0523              {
0524                  /** @var type\base $type */
0525                  $type = $this->get_item_type_class($type_name);
0526   
0527                  if ($type instanceof \phpbb\notification\type\type_interface && $type->is_available())
0528                  {
0529                      $options = array_merge(array(
0530                          'type'    => $type,
0531                          'id'    => $type->get_type(),
0532                          'lang'    => 'NOTIFICATION_TYPE_' . strtoupper($type->get_type()),
0533                          'group'    => 'NOTIFICATION_GROUP_MISCELLANEOUS',
0534                      ), (($type::$notification_option !== false) ? $type::$notification_option : array()));
0535   
0536                      $this->subscription_types[$options['group']][$options['id']] = $options;
0537                  }
0538              }
0539   
0540              // Move Miscellaneous to the very last section
0541              if (isset($this->subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS']))
0542              {
0543                  $miscellaneous = $this->subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS'];
0544                  unset($this->subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS']);
0545                  $this->subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS'] = $miscellaneous;
0546              }
0547          }
0548   
0549          return $this->subscription_types;
0550      }
0551   
0552      /**
0553      * Get all of the subscription methods
0554      *
0555      * @return array Array of methods
0556      */
0557      public function get_subscription_methods()
0558      {
0559          $subscription_methods = array();
0560   
0561          /** @var method\method_interface $method */
0562          foreach ($this->get_available_subscription_methods() as $method_name => $method)
0563          {
0564              $subscription_methods[$method_name] = array(
0565                  'method'    => $method,
0566                  'id'        => $method->get_type(),
0567                  'lang'        => str_replace('.', '_', strtoupper($method->get_type())),
0568              );
0569          }
0570   
0571          return $subscription_methods;
0572      }
0573   
0574      /**
0575      * Get all of the subscription methods
0576      *
0577      * @return array Array of method's instances
0578      */
0579      private function get_subscription_methods_instances()
0580      {
0581          $subscription_methods = array();
0582   
0583          foreach ($this->notification_methods as $method_name => $data)
0584          {
0585              $method = $this->get_method_class($method_name);
0586   
0587              if ($method instanceof \phpbb\notification\method\method_interface)
0588              {
0589                  $subscription_methods[$method_name] = $method;
0590              }
0591          }
0592   
0593          return $subscription_methods;
0594      }
0595   
0596      /**
0597      * Get all of the available subscription methods
0598      *
0599      * @return array Array of method's instances
0600      */
0601      private function get_available_subscription_methods()
0602      {
0603          $subscription_methods = array();
0604   
0605          /** @var method\method_interface $method */
0606          foreach ($this->get_subscription_methods_instances() as $method_name => $method)
0607          {
0608              if ($method->is_available())
0609              {
0610                  $subscription_methods[$method_name] = $method;
0611              }
0612          }
0613   
0614          return $subscription_methods;
0615      }
0616   
0617   
0618      /**
0619      * Get user's notification data
0620      *
0621      * @param int $user_id The user_id of the user to get the notifications for
0622      *
0623      * @return array User's notification
0624      */
0625      protected function get_user_notifications($user_id)
0626      {
0627          $sql = 'SELECT method, notify, item_type
0628                  FROM ' . $this->user_notifications_table . '
0629                  WHERE user_id = ' . (int) $user_id . '
0630                      AND item_id = 0';
0631   
0632          $result = $this->db->sql_query($sql);
0633          $user_notifications = array();
0634   
0635          while ($row = $this->db->sql_fetchrow($result))
0636          {
0637              $user_notifications[$row['item_type']][] = $row;
0638          }
0639   
0640          $this->db->sql_freeresult($result);
0641   
0642          return $user_notifications;
0643      }
0644   
0645      /**
0646      * Get global subscriptions (item_id = 0)
0647      *
0648      * @param bool|int $user_id The user_id to add the subscription for (bool false for current user)
0649      *
0650      * @return array Subscriptions
0651      */
0652      public function get_global_subscriptions($user_id = false)
0653      {
0654          $user_id = $user_id ?: $this->user->data['user_id'];
0655   
0656          $subscriptions = array();
0657          $default_methods = $this->get_default_methods();
0658   
0659          $user_notifications = $this->get_user_notifications($user_id);
0660   
0661          foreach ($this->get_subscription_types() as $types)
0662          {
0663              foreach ($types as $id => $type)
0664              {
0665                  $type_subscriptions = $default_methods;
0666                  if (!empty($user_notifications[$id]))
0667                  {
0668                      foreach ($user_notifications[$id] as $user_notification)
0669                      {
0670                          $key = array_search($user_notification['method'], $type_subscriptions, true);
0671                          if (!$user_notification['notify'])
0672                          {
0673                              if ($key !== false)
0674                              {
0675                                  unset($type_subscriptions[$key]);
0676                              }
0677   
0678                              continue;
0679                          }
0680                          else if ($key === false)
0681                          {
0682                              $type_subscriptions[] = $user_notification['method'];
0683                          }
0684                      }
0685                  }
0686   
0687                  if (!empty($type_subscriptions))
0688                  {
0689                      $subscriptions[$id] = $type_subscriptions;
0690                  }
0691              }
0692          }
0693   
0694          return $subscriptions;
0695      }
0696   
0697      /**
0698      * Add a subscription
0699      *
0700      * @param string $item_type Type identifier of the subscription
0701      * @param int $item_id The id of the item
0702      * @param string $method The method of the notification e.g. 'board', 'email', or 'jabber'
0703      *                       (if null a subscription will be added for all the defaults methods)
0704      * @param bool|int $user_id The user_id to add the subscription for (bool false for current user)
0705      */
0706      public function add_subscription($item_type, $item_id = 0, $method = null, $user_id = false)
0707      {
0708          if ($method === null)
0709          {
0710              foreach ($this->get_default_methods() as $method_name)
0711              {
0712                  $this->add_subscription($item_type, $item_id, $method_name, $user_id);
0713              }
0714   
0715              return;
0716          }
0717   
0718          $user_id = ($user_id === false) ? $this->user->data['user_id'] : $user_id;
0719   
0720          $sql = 'SELECT notify
0721              FROM ' . $this->user_notifications_table . "
0722              WHERE item_type = '" . $this->db->sql_escape($item_type) . "'
0723                  AND item_id = " . (int) $item_id . '
0724                  AND user_id = ' .(int) $user_id . "
0725                  AND method = '" . $this->db->sql_escape($method) . "'";
0726          $this->db->sql_query($sql);
0727          $current = $this->db->sql_fetchfield('notify');
0728          $this->db->sql_freeresult();
0729   
0730          if ($current === false)
0731          {
0732              $sql = 'INSERT INTO ' . $this->user_notifications_table . ' ' .
0733                  $this->db->sql_build_array('INSERT', array(
0734                      'item_type'        => $item_type,
0735                      'item_id'        => (int) $item_id,
0736                      'user_id'        => (int) $user_id,
0737                      'method'        => $method,
0738                      'notify'        => 1,
0739                  ));
0740              $this->db->sql_query($sql);
0741          }
0742          else if (!$current)
0743          {
0744              $sql = 'UPDATE ' . $this->user_notifications_table . "
0745                  SET notify = 1
0746                  WHERE item_type = '" . $this->db->sql_escape($item_type) . "'
0747                      AND item_id = " . (int) $item_id . '
0748                      AND user_id = ' .(int) $user_id . "
0749                      AND method = '" . $this->db->sql_escape($method) . "'";
0750              $this->db->sql_query($sql);
0751          }
0752      }
0753   
0754      /**
0755      * Delete a subscription
0756      *
0757      * @param string $item_type Type identifier of the subscription
0758      * @param int $item_id The id of the item
0759      * @param string $method The method of the notification e.g. 'board', 'email', or 'jabber'
0760      * @param bool|int $user_id The user_id to add the subscription for (bool false for current user)
0761      */
0762      public function delete_subscription($item_type, $item_id = 0, $method = null, $user_id = false)
0763      {
0764          if ($method === null)
0765          {
0766              foreach ($this->get_default_methods() as $method_name)
0767              {
0768                  $this->delete_subscription($item_type, $item_id, $method_name, $user_id);
0769              }
0770   
0771              return;
0772          }
0773   
0774          $user_id = $user_id ?: $this->user->data['user_id'];
0775   
0776          $sql = 'UPDATE ' . $this->user_notifications_table . "
0777              SET notify = 0
0778              WHERE item_type = '" . $this->db->sql_escape($item_type) . "'
0779                  AND item_id = " . (int) $item_id . '
0780                  AND user_id = ' .(int) $user_id . "
0781                  AND method = '" . $this->db->sql_escape($method) . "'";
0782          $this->db->sql_query($sql);
0783   
0784          if (!$this->db->sql_affectedrows())
0785          {
0786              $sql = 'INSERT INTO ' . $this->user_notifications_table . ' ' .
0787                  $this->db->sql_build_array('INSERT', array(
0788                      'item_type'        => $item_type,
0789                      'item_id'        => (int) $item_id,
0790                      'user_id'        => (int) $user_id,
0791                      'method'        => $method,
0792                      'notify'        => 0,
0793                  ));
0794              $this->db->sql_query($sql);
0795          }
0796      }
0797   
0798      /**
0799      * Disable all notifications of a certain type
0800      *
0801      * This should be called when an extension which has notification types
0802      * is disabled so that all those notifications are hidden and do not
0803      * cause errors
0804      *
0805      * @param string $notification_type_name Type identifier of the subscription
0806      */
0807      public function disable_notifications($notification_type_name)
0808      {
0809          $sql = 'UPDATE ' . $this->notification_types_table . "
0810              SET notification_type_enabled = 0
0811              WHERE notification_type_name = '" . $this->db->sql_escape($notification_type_name) . "'";
0812          $this->db->sql_query($sql);
0813      }
0814   
0815      /**
0816      * Purge all notifications of a certain type
0817      *
0818      * This should be called when an extension which has notification types
0819      * is purged so that all those notifications are removed
0820      *
0821      * @param string $notification_type_name Type identifier of the subscription
0822      */
0823      public function purge_notifications($notification_type_name)
0824      {
0825          // If a notification is never used, its type will not be added to the database
0826          // nor its id cached. If this method is called by an extension during the
0827          // purge step, and that extension never used its notifications,
0828          // get_notification_type_id() will throw an exception. However,
0829          // because no notification type was added to the database,
0830          // there is nothing to delete, so we can silently drop the exception.
0831          try
0832          {
0833              $notification_type_id = $this->get_notification_type_id($notification_type_name);
0834   
0835              /** @var method\method_interface $method */
0836              foreach ($this->get_available_subscription_methods() as $method)
0837              {
0838                  $method->purge_notifications($notification_type_id);
0839              }
0840   
0841          }
0842          catch (\phpbb\notification\exception $e)
0843          {
0844              // Continue
0845          }
0846      }
0847   
0848      /**
0849      * Enable all notifications of a certain type
0850      *
0851      * This should be called when an extension which has notification types
0852      * that was disabled is re-enabled so that all those notifications that
0853      * were hidden are shown again
0854      *
0855      * @param string $notification_type_name Type identifier of the subscription
0856      */
0857      public function enable_notifications($notification_type_name)
0858      {
0859          $sql = 'UPDATE ' . $this->notification_types_table . "
0860              SET notification_type_enabled = 1
0861              WHERE notification_type_name = '" . $this->db->sql_escape($notification_type_name) . "'";
0862          $this->db->sql_query($sql);
0863      }
0864   
0865      /**
0866      * Delete all notifications older than a certain time
0867      *
0868      * @param int $timestamp Unix timestamp to delete all notifications that were created before
0869      * @param bool $only_read True (default) to only prune read notifications
0870      */
0871      public function prune_notifications($timestamp, $only_read = true)
0872      {
0873          /** @var method\method_interface $method */
0874          foreach ($this->get_available_subscription_methods() as $method)
0875          {
0876              $method->prune_notifications($timestamp, $only_read);
0877          }
0878      }
0879   
0880      /**
0881       * Helper to get the list of methods enabled by default
0882       *
0883       * @return method\method_interface[]
0884       */
0885      public function get_default_methods()
0886      {
0887          $default_methods = array();
0888   
0889          foreach ($this->notification_methods as $method)
0890          {
0891              if ($method->is_enabled_by_default() && $method->is_available())
0892              {
0893                  $default_methods[] = $method->get_type();
0894              }
0895          }
0896   
0897          return $default_methods;
0898      }
0899   
0900      /**
0901       * Helper to get the notifications item type class and set it up
0902       *
0903       * @param string $notification_type_name
0904       * @param array  $data
0905       * @return type\type_interface
0906       */
0907      public function get_item_type_class($notification_type_name, $data = array())
0908      {
0909          $item = $this->load_object($notification_type_name);
0910   
0911          $item->set_initial_data($data);
0912   
0913          return $item;
0914      }
0915   
0916      /**
0917       * Helper to get the notifications method class and set it up
0918       *
0919       * @param string $method_name
0920       * @return method\method_interface
0921       */
0922      public function get_method_class($method_name)
0923      {
0924          return $this->load_object($method_name);
0925      }
0926   
0927      /**
0928       * Helper to load objects (notification types/methods)
0929       *
0930       * @param string $object_name
0931       * @return method\method_interface|type\type_interface
0932       */
0933      protected function load_object($object_name)
0934      {
0935          $object = $this->phpbb_container->get($object_name);
0936   
0937          if (method_exists($object, 'set_notification_manager'))
0938          {
0939              $object->set_notification_manager($this);
0940          }
0941   
0942          return $object;
0943      }
0944   
0945      /**
0946      * Get the notification type id from the name
0947      *
0948      * @param string $notification_type_name The name
0949      * @return int the notification_type_id
0950      * @throws \phpbb\notification\exception
0951      */
0952      public function get_notification_type_id($notification_type_name)
0953      {
0954          $sql = 'SELECT notification_type_id, notification_type_name
0955              FROM ' . $this->notification_types_table;
0956          $result = $this->db->sql_query($sql, 604800); // cache for one week
0957          while ($row = $this->db->sql_fetchrow($result))
0958          {
0959              $notification_type_ids[$row['notification_type_name']] = (int) $row['notification_type_id'];
0960          }
0961          $this->db->sql_freeresult($result);
0962   
0963          if (!isset($notification_type_ids[$notification_type_name]))
0964          {
0965              if (!isset($this->notification_types[$notification_type_name]) && !isset($this->notification_types['notification.type.' . $notification_type_name]))
0966              {
0967                  throw new \phpbb\notification\exception('NOTIFICATION_TYPE_NOT_EXIST', array($notification_type_name));
0968              }
0969   
0970              $sql = 'INSERT INTO ' . $this->notification_types_table . ' ' . $this->db->sql_build_array('INSERT', array(
0971                  'notification_type_name'        => $notification_type_name,
0972                  'notification_type_enabled'        => 1,
0973              ));
0974              $this->db->sql_query($sql);
0975   
0976              // expose new notification type ID for this request
0977              $notification_type_ids[$notification_type_name] = (int) $this->db->sql_nextid();
0978   
0979              // destroy cache, we have a new addition which we have to to load next time
0980              $this->cache->destroy('sql', $this->notification_types_table);
0981          }
0982   
0983          return $notification_type_ids[$notification_type_name];
0984      }
0985   
0986      /**
0987      * Get notification type ids (as an array)
0988      *
0989      * @param string|array $notification_type_names Notification type names
0990      * @return array Array of integers
0991      */
0992      public function get_notification_type_ids($notification_type_names)
0993      {
0994          if (!is_array($notification_type_names))
0995          {
0996              $notification_type_names = array($notification_type_names);
0997          }
0998   
0999          $notification_type_ids = array();
1000   
1001          foreach ($notification_type_names as $name)
1002          {
1003              $notification_type_ids[$name] = $this->get_notification_type_id($name);
1004          }
1005   
1006          return $notification_type_ids;
1007      }
1008   
1009      /**
1010      * Find the users which are already notified
1011      *
1012      * @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 retrieve all item types
1013      * @param array $options
1014      * @return array The list of the notified users
1015      */
1016      public function get_notified_users($notification_type_name, array $options)
1017      {
1018          $notification_type_id = $this->get_notification_type_id($notification_type_name);
1019   
1020          $notified_users = array();
1021   
1022          /** @var method\method_interface $method */
1023          foreach ($this->get_available_subscription_methods() as $method)
1024          {
1025              $notified_users = $notified_users + $method->get_notified_users($notification_type_id, $options);
1026          }
1027   
1028          return $notified_users;
1029      }
1030  }
1031