Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
53.57% covered (warning)
53.57%
15 / 28
CRAP
64.06% covered (warning)
64.06%
82 / 128
base
0.00% covered (danger)
0.00%
0 / 1
53.57% covered (warning)
53.57%
15 / 28
195.40
64.06% covered (warning)
64.06%
82 / 128
 __construct
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
8 / 8
 set_notification_manager
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
3 / 3
 set_initial_data
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
3 / 3
 __get
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
1 / 1
 __set
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
 __toString
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 1
 get_data
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
1 / 1
 set_data
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
 create_insert_array
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
7 / 7
 get_insert_array
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
3 / 3
 create_update_array
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
7 / 7
 mark_read
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 1
 mark_unread
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 1
 get_redirect_url
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 1
 prepare_for_display
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 16
 get_unsubscribe_url
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 1
 get_style_class
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 1
 get_avatar
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 1
 get_reference
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 1
 get_forum
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 1
 get_reason
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 1
 get_load_special
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 load_special
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 is_available
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 pre_create_insert_array
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 check_user_notification_options
0.00% covered (danger)
0.00%
0 / 1
18.77
74.42% covered (warning)
74.42%
32 / 43
 mark
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 get_authorised_recipients
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
9 / 9
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\notification\type;
/**
* Base notifications class
*/
abstract class base implements \phpbb\notification\type\type_interface
{
    /** @var \phpbb\notification\manager */
    protected $notification_manager;
    /** @var \phpbb\db\driver\driver_interface */
    protected $db;
    /** @var \phpbb\language\language */
    protected $language;
    /** @var \phpbb\user */
    protected $user;
    /** @var \phpbb\auth\auth */
    protected $auth;
    /** @var string */
    protected $phpbb_root_path;
    /** @var string */
    protected $php_ext;
    /** @var string */
    protected $user_notifications_table;
    /**
    * Notification option data (for outputting to the user)
    *
    * @var bool|array False if the service should use its default data
    *                     Array of data (including keys 'id', 'lang', and 'group')
    */
    static public $notification_option = false;
    /**
    * The notification_type_id, set upon creation of the class
    * This is the notification_type_id from the notification_types table
    *
    * @var int
    */
    protected $notification_type_id;
    /**
    * Identification data
    * notification_type_id    - ID of the item type (auto generated, from notification types table)
    * item_id                - ID of the item (e.g. post_id, msg_id)
    * item_parent_id        - Parent item id (ex: for topic => forum_id, for post => topic_id, etc)
    * user_id
    * notification_read
    * notification_time
    * notification_data (special serialized field that each notification type can use to store stuff)
    *
    * @var array $data Notification row from the database
    *         This must be private, all interaction should use __get(), __set(), get_data(), set_data()
    */
    private $data = array();
    /**
     * Notification Type Base Constructor
     *
     * @param \phpbb\db\driver\driver_interface $db
     * @param \phpbb\language\language          $language
     * @param \phpbb\user                       $user
     * @param \phpbb\auth\auth                  $auth
     * @param string                            $phpbb_root_path
     * @param string                            $php_ext
     * @param string                            $user_notifications_table
     */
    public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\language\language $language, \phpbb\user $user, \phpbb\auth\auth $auth, $phpbb_root_path, $php_ext, $user_notifications_table)
    {
        $this->db = $db;
        $this->language = $language;
        $this->user = $user;
        $this->auth = $auth;
        $this->phpbb_root_path = $phpbb_root_path;
        $this->php_ext = $php_ext;
        $this->user_notifications_table = $user_notifications_table;
    }
    /**
    * Set notification manager (required)
    *
    * @param \phpbb\notification\manager $notification_manager
    */
    public function set_notification_manager(\phpbb\notification\manager $notification_manager)
    {
        $this->notification_manager = $notification_manager;
        $this->notification_type_id = $this->notification_manager->get_notification_type_id($this->get_type());
    }
    /**
    * Set initial data from the database
    *
    * @param array $data Row directly from the database
    */
    public function set_initial_data($data = array())
    {
        // The row from the database (unless this is a new notification we're going to add)
        $this->data = $data;
        $this->data['notification_data'] = (isset($this->data['notification_data'])) ? unserialize($this->data['notification_data']) : array();
    }
    /**
    * Magic method to get data from this notification
    *
    * @param mixed $name
    * @return mixed
    */
    public function __get($name)
    {
        return (!isset($this->data[$name])) ? null : $this->data[$name];
    }
    /**
    * Magic method to set data on this notification
    *
    * @param mixed $name
    * @param mixed $value
    *
    * @return null
    */
    public function __set($name, $value)
    {
        $this->data[$name] = $value;
    }
    /**
    * Magic method to get a string of this notification
    *
    * Primarily for testing
    *
    * @return mixed
    */
    public function __toString()
    {
        return (!empty($this->data)) ? var_export($this->data, true) : $this->get_type();
    }
    /**
    * Get special data (only important for the classes that extend this)
    *
    * @param string $name Name of the variable to get
    * @return mixed
    */
    protected function get_data($name)
    {
        return ($name === false) ? $this->data['notification_data'] : ((isset($this->data['notification_data'][$name])) ? $this->data['notification_data'][$name] : null);
    }
    /**
    * Set special data (only important for the classes that extend this)
    *
    * @param string $name Name of the variable to set
    * @param mixed $value Value to set to the variable
    * @return mixed
    */
    protected function set_data($name, $value)
    {
        $this->data['notification_data'][$name] = $value;
    }
    /**
    * {@inheritdoc}
    */
    public function create_insert_array($type_data, $pre_create_data = array())
    {
        // Defaults
        $this->data = array_merge(array(
            'item_id'                => static::get_item_id($type_data),
            'notification_type_id'    => $this->notification_type_id,
            'item_parent_id'        => static::get_item_parent_id($type_data),
            'notification_time'        => time(),
            'notification_read'        => false,
            'notification_data'        => array(),
        ), $this->data);
    }
    /**
    * {@inheritdoc}
    */
    public function get_insert_array()
    {
        $data = $this->data;
        $data['notification_data'] = serialize($data['notification_data']);
        return $data;
    }
    /**
    * Function for preparing the data for update in an SQL query
    * (The service handles insertion)
    *
    * @param array $type_data Data unique to this notification type
    * @return array Array of data ready to be updated in the database
    */
    public function create_update_array($type_data)
    {
        $this->create_insert_array($type_data);
        $data = $this->get_insert_array();
        // Unset data unique to each row
        unset(
            $data['notification_time'], // Also unsetting time, since it always tries to change the time to current (if you actually need to change the time, over-ride this function)
            $data['notification_id'],
            $data['notification_read'],
            $data['user_id']
        );
        return $data;
    }
    /**
    * Mark this item read
    *
    * @param bool $return True to return a string containing the SQL code to update this item, False to execute it (Default: False)
    * @return string|null If $return is False, nothing will be returned, else the sql code to update this item
    */
    public function mark_read($return = false)
    {
        return $this->mark(false, $return);
    }
    /**
    * Mark this item unread
    *
    * @param bool $return True to return a string containing the SQL code to update this item, False to execute it (Default: False)
    * @return string|null If $return is False, nothing will be returned, else the sql code to update this item
    */
    public function mark_unread($return = false)
    {
        return $this->mark(true, $return);
    }
    /**
    * {inheritDoc}
    */
    public function get_redirect_url()
    {
        return $this->get_url();
    }
    /**
    * Prepare to output the notification to the template
    *
    * @return array Template variables
    */
    public function prepare_for_display()
    {
        $mark_hash = generate_link_hash('mark_notification_read');
        if ($this->get_url())
        {
            $u_mark_read = append_sid($this->phpbb_root_path . 'index.' . $this->php_ext, 'mark_notification=' . $this->notification_id . '&amp;hash=' . $mark_hash);
        }
        else
        {
            $redirect = (($this->user->page['page_dir']) ? $this->user->page['page_dir'] . '/' : '') . $this->user->page['page_name'] . (($this->user->page['query_string']) ? '?' . $this->user->page['query_string'] : '');
            $u_mark_read = append_sid($this->phpbb_root_path . 'index.' . $this->php_ext, 'mark_notification=' . $this->notification_id . '&amp;hash=' . $mark_hash . '&amp;redirect=' . urlencode($redirect));
        }
        return array(
            'NOTIFICATION_ID'    => $this->notification_id,
            'STYLING'            => $this->get_style_class(),
            'AVATAR'            => $this->get_avatar(),
            'FORMATTED_TITLE'    => $this->get_title(),
            'REFERENCE'            => $this->get_reference(),
            'FORUM'                => $this->get_forum(),
            'REASON'            => $this->get_reason(),
            'URL'                => $this->get_url(),
            'TIME'                   => $this->user->format_date($this->notification_time),
            'UNREAD'            => !$this->notification_read,
            'U_MARK_READ'        => (!$this->notification_read) ? $u_mark_read : '',
        );
    }
    /**
    * -------------- Fall back functions -------------------
    */
    /**
    * URL to unsubscribe to this notification (fall back)
    *
    * @param string|bool $method Method name to unsubscribe from (email|jabber|etc), False to unsubscribe from all notifications for this item
    * @return false
    */
    public function get_unsubscribe_url($method = false)
    {
        return false;
    }
    /**
    * Get the CSS style class of the notification (fall back)
    *
    * @return string
    */
    public function get_style_class()
    {
        return '';
    }
    /**
    * Get the user's avatar (fall back)
    *
    * @return string
    */
    public function get_avatar()
    {
        return '';
    }
    /**
    * Get the reference of the notification (fall back)
    *
    * @return string
    */
    public function get_reference()
    {
        return '';
    }
    /**
    * Get the forum of the notification reference (fall back)
    *
    * @return string
    */
    public function get_forum()
    {
        return '';
    }
    /**
    * Get the reason for the notification (fall back)
    *
    * @return string
    */
    public function get_reason()
    {
        return '';
    }
    /**
    * Get the special items to load (fall back)
    *
    * @return array
    */
    public function get_load_special()
    {
        return array();
    }
    /**
     * Load the special items (fall back)
     *
     * @param array $data
     * @param array $notifications
     */
    public function load_special($data, $notifications)
    {
        return;
    }
    /**
    * Is available (fall back)
    *
    * @return bool
    */
    public function is_available()
    {
        return true;
    }
    /**
     * Pre create insert array function (fall back)
     *
     * @param array $type_data
     * @param array $notify_users
     * @return array
     */
    public function pre_create_insert_array($type_data, $notify_users)
    {
        return array();
    }
    /**
    * -------------- Helper functions -------------------
    */
    /**
     * Find the users who want to receive notifications (helper)
     *
     * @param array|bool $user_ids User IDs to check if they want to receive notifications
     *                             (Bool False to check all users besides anonymous and bots (USER_IGNORE))
     * @param array      $options
     * @return array
     */
    protected function check_user_notification_options($user_ids = false, $options = array())
    {
        $options = array_merge(array(
            'ignore_users'        => array(),
            'item_type'            => $this->get_type(),
            'item_id'            => 0, // Global by default
        ), $options);
        if ($user_ids === false)
        {
            $user_ids = array();
            $sql = 'SELECT user_id
                FROM ' . USERS_TABLE . '
                WHERE user_id <> ' . ANONYMOUS . '
                    AND user_type <> ' . USER_IGNORE;
            $result = $this->db->sql_query($sql);
            while ($row = $this->db->sql_fetchrow($result))
            {
                $user_ids[] = $row['user_id'];
            }
            $this->db->sql_freeresult($result);
        }
        if (empty($user_ids))
        {
            return array();
        }
        $rowset = $output = array();
        $sql = 'SELECT user_id, method, notify
            FROM ' . $this->user_notifications_table . '
            WHERE ' . $this->db->sql_in_set('user_id', $user_ids) . "
                AND item_type = '" . $this->db->sql_escape($options['item_type']) . "'
                AND item_id = " . (int) $options['item_id'];
        $result = $this->db->sql_query($sql);
        while ($row = $this->db->sql_fetchrow($result))
        {
            if (isset($options['ignore_users'][$row['user_id']]) && in_array($row['method'], $options['ignore_users'][$row['user_id']]))
            {
                continue;
            }
            if (!isset($rowset[$row['user_id']]))
            {
                $rowset[$row['user_id']] = array();
            }
            $rowset[$row['user_id']][$row['method']] = $row['notify'];
            if (!isset($output[$row['user_id']]))
            {
                $output[$row['user_id']] = array();
            }
            if ($row['notify'])
            {
                $output[$row['user_id']][] = $row['method'];
            }
        }
        $this->db->sql_freeresult($result);
        $default_methods = $this->notification_manager->get_default_methods();
        foreach ($user_ids as $user_id)
        {
            if (isset($options['ignore_users'][$user_id]))
            {
                continue;
            }
            if (!array_key_exists($user_id, $rowset))
            {
                // No rows at all for this user, use the default methods
                $output[$user_id] = $default_methods;
            }
            else
            {
                foreach ($default_methods as $default_method)
                {
                    if (!array_key_exists($default_method, $rowset[$user_id]))
                    {
                        // No user preference for this type recorded, but it should be enabled by default.
                        $output[$user_id][] = $default_method;
                    }
                }
            }
        }
        return $output;
    }
    /**
    * Mark this item read/unread helper
    *
    * @param bool $unread Unread (True/False) (Default: False)
    * @param bool $return True to return a string containing the SQL code to update this item, False to execute it (Default: False)
    * @return string|null If $return is False, nothing will be returned, else the sql code to update this item
    */
    protected function mark($unread = true, $return = false)
    {
        $this->notification_read = (bool) !$unread;
        if ($return)
        {
            $where = array(
                'notification_type_id = ' . (int) $this->notification_type_id,
                'item_id = ' . (int) $this->item_id,
                'user_id = ' . (int) $this->user_id,
            );
            $where = implode(' AND ', $where);
            return $where;
        }
        else
        {
            $this->notification_manager->mark_notifications($this->get_type(), (int) $this->item_id, (int) $this->user_id, false, $this->notification_read);
        }
        return null;
    }
    /**
     * Get a list of users that are authorised to receive notifications
     *
     * @param array $users Array of users that have subscribed to a notification
     * @param int $forum_id Forum ID of the forum
     * @param array $options Array of notification options
     * @param bool $sort Whether the users array should be sorted. Default: false
     * @return array Array of users that are authorised recipients
     */
    protected function get_authorised_recipients($users, $forum_id, $options, $sort = false)
    {
        if (empty($users))
        {
            return array();
        }
        $users = array_unique($users);
        if ($sort)
        {
            sort($users);
        }
        $auth_read = $this->auth->acl_get_list($users, 'f_read', $forum_id);
        if (empty($auth_read))
        {
            return array();
        }
        return $this->check_user_notification_options($auth_read[$forum_id]['f_read'], $options);
    }
}