Completed
Pull Request — master (#133)
by Goffy
16:45
created

XoopsNotificationHandler::triggerEvent()   F

Complexity

Conditions 26
Paths 11256

Size

Total Lines 107
Code Lines 74

Duplication

Lines 39
Ratio 36.45 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 26
eloc 74
nc 11256
nop 7
dl 39
loc 107
rs 2
c 1
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 34 and the first side effect is on line 19.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * XOOPS Kernel Class
4
 *
5
 * You may not change or alter any portion of this comment or credits
6
 * of supporting developers from this source code or any supporting source code
7
 * which is considered copyrighted (c) material of the original comment or credit authors.
8
 * This program is distributed in the hope that it will be useful,
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * @copyright       (c) 2000-2016 XOOPS Project (www.xoops.org)
13
 * @license             GNU GPL 2 (http://www.gnu.org/licenses/gpl-2.0.html)
14
 * @package             kernel
15
 * @since               2.0.0
16
 * @author              Michael van Dam <[email protected]>
17
 * @author              Kazumi Ono (AKA onokazu) http://www.myweb.ne.jp/, http://jp.xoops.org/
18
 */
19
defined('XOOPS_ROOT_PATH') || exit('Restricted access');
20
21
// RMV-NOTIFY
22
include_once $GLOBALS['xoops']->path('include/notification_constants.php');
23
include_once $GLOBALS['xoops']->path('include/notification_functions.php');
24
25
/**
26
 * A Notification
27
 *
28
 * @package             kernel
29
 * @subpackage          notification
30
 *
31
 * @author              Michael van Dam    <[email protected]>
32
 * @copyright       (c) 2000-2016 XOOPS Project (www.xoops.org)
33
 */
34
class XoopsNotification extends XoopsObject
35
{
36
    /**
37
     * Constructor
38
     **/
39
    public function __construct()
40
    {
41
        parent::__construct();
42
        $this->initVar('not_id', XOBJ_DTYPE_INT, null, false);
43
        $this->initVar('not_modid', XOBJ_DTYPE_INT, null, false);
44
        $this->initVar('not_category', XOBJ_DTYPE_TXTBOX, null, false, 30);
45
        $this->initVar('not_itemid', XOBJ_DTYPE_INT, 0, false);
46
        $this->initVar('not_event', XOBJ_DTYPE_TXTBOX, null, false, 30);
47
        $this->initVar('not_uid', XOBJ_DTYPE_INT, 0, true);
48
        $this->initVar('not_mode', XOBJ_DTYPE_INT, 0, false);
49
    }
50
51
    // FIXME:???
52
    // To send email to multiple users simultaneously, we would need to move
53
    // the notify functionality to the handler class.  BUT, some of the tags
54
    // are user-dependent, so every email msg will be unique.  (Unless maybe use
55
    // smarty for email templates in the future.)  Also we would have to keep
56
    // track if each user wanted email or PM.
57
58
    /**
59
     * Returns Class Base Variable not_id
60
     * @param  string $format
61
     * @return mixed
62
     */
63
    public function id($format = 'N')
64
    {
65
        return $this->getVar('not_id', $format);
66
    }
67
68
    /**
69
     * Returns Class Base Variable not_id
70
     * @param  string $format
71
     * @return mixed
72
     */
73
    public function not_id($format = '')
74
    {
75
        return $this->getVar('not_id', $format);
76
    }
77
78
    /**
79
     * Returns Class Base Variable not_modid
80
     * @param  string $format
81
     * @return mixed
82
     */
83
    public function not_modid($format = '')
84
    {
85
        return $this->getVar('not_modid', $format);
86
    }
87
88
    /**
89
     * Returns Class Base Variable mid
90
     * @param  string $format
91
     * @return mixed
92
     */
93
    public function not_category($format = '')
94
    {
95
        return $this->getVar('not_category', $format);
96
    }
97
98
    /**
99
     * Returns Class Base Variable not_itemid
100
     * @param  string $format
101
     * @return mixed
102
     */
103
    public function not_itemid($format = '')
104
    {
105
        return $this->getVar('not_itemid', $format);
106
    }
107
108
    /**
109
     * Returns Class Base Variable not_event
110
     * @param  string $format
111
     * @return mixed
112
     */
113
    public function not_event($format = '')
114
    {
115
        return $this->getVar('not_event', $format);
116
    }
117
118
    /**
119
     * Returns Class Base Variable not_uid
120
     * @param  string $format
121
     * @return mixed
122
     */
123
    public function not_uid($format = '')
124
    {
125
        return $this->getVar('not_uid', $format);
126
    }
127
128
    /**
129
     * Returns Class Base Variable not_mode
130
     * @param  string $format
131
     * @return mixed
132
     */
133
    public function not_mode($format = '')
134
    {
135
        return $this->getVar('not_mode', $format);
136
    }
137
138
    /**
139
     * Send a notification message to the user
140
     *
141
     * @param string $template_dir Template directory
142
     * @param string $template     Template name
143
     * @param string $subject      Subject line for notification message
144
     * @param array  $tags         Array of substitutions for template variables
145
     *
146
     * @return bool true if success, false if error
147
     **/
148
    public function notifyUser($template_dir, $template, $subject, $tags)
149
    {
150
        // Check the user's notification preference.
151
        $member_handler = xoops_getHandler('member');
152
        $user           = $member_handler->getUser($this->getVar('not_uid'));
153
        if (!is_object($user)) {
154
            return true;
155
        }
156
        $method = $user->getVar('notify_method');
157
158
        $xoopsMailer =& xoops_getMailer();
159
        include_once $GLOBALS['xoops']->path('include/notification_constants.php');
160
        switch ($method) {
161
            case XOOPS_NOTIFICATION_METHOD_PM:
162
                $xoopsMailer->usePM();
163
                $config_handler    = xoops_getHandler('config');
164
                $xoopsMailerConfig = $config_handler->getConfigsByCat(XOOPS_CONF_MAILER);
165
                $xoopsMailer->setFromUser($member_handler->getUser($xoopsMailerConfig['fromuid']));
166
                foreach ($tags as $k => $v) {
167
                    $xoopsMailer->assign($k, $v);
168
                }
169
                break;
170
            case XOOPS_NOTIFICATION_METHOD_EMAIL:
171
                $xoopsMailer->useMail();
172
                foreach ($tags as $k => $v) {
173
                    $xoopsMailer->assign($k, preg_replace('/&amp;/i', '&', $v));
174
                }
175
                break;
176
            default:
177
                return true; // report error in user's profile??
178
//                break;
179
        }
180
181
        // Set up the mailer
182
        $xoopsMailer->setTemplateDir($template_dir);
183
        $xoopsMailer->setTemplate($template);
184
        $xoopsMailer->setToUsers($user);
185
        //global $xoopsConfig;
186
        //$xoopsMailer->setFromEmail($xoopsConfig['adminmail']);
187
        //$xoopsMailer->setFromName($xoopsConfig['sitename']);
188
        $xoopsMailer->setSubject($subject);
189
        $success = $xoopsMailer->send();
190
191
        // If send-once-then-delete, delete notification
192
        // If send-once-then-wait, disable notification
193
        include_once $GLOBALS['xoops']->path('include/notification_constants.php');
194
        $notification_handler = xoops_getHandler('notification');
195
196
        if ($this->getVar('not_mode') == XOOPS_NOTIFICATION_MODE_SENDONCETHENDELETE) {
197
            $notification_handler->delete($this);
198
199
            return $success;
200
        }
201
202
        if ($this->getVar('not_mode') == XOOPS_NOTIFICATION_MODE_SENDONCETHENWAIT) {
203
            $this->setVar('not_mode', XOOPS_NOTIFICATION_MODE_WAITFORLOGIN);
204
            $notification_handler->insert($this);
205
        }
206
207
        return $success;
208
    }
209
}
210
211
/**
212
 * XOOPS notification handler class.
213
 *
214
 * This class is responsible for providing data access mechanisms to the data source
215
 * of XOOPS notification class objects.
216
 *
217
 *
218
 * @package             kernel
219
 * @subpackage          notification
220
 *
221
 * @author              Michael van Dam <[email protected]>
222
 * @copyright       (c) 2000-2016 XOOPS Project (www.xoops.org)
223
 */
224
class XoopsNotificationHandler extends XoopsObjectHandler
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
225
{
226
    /**
227
     * Create a {@link XoopsNotification}
228
     *
229
     * @param bool $isNew Flag the object as "new"?
230
     *
231
     * @return XoopsNotification
232
     */
233
    public function create($isNew = true)
234
    {
235
        $notification = new XoopsNotification();
236
        if ($isNew) {
237
            $notification->setNew();
238
        }
239
240
        return $notification;
241
    }
242
243
    /**
244
     * Retrieve a {@link XoopsNotification}
245
     *
246
     * @param int $id ID
247
     *
248
     * @return XoopsNotification {@link XoopsNotification}, FALSE on fail
249
     **/
250 View Code Duplication
    public function get($id)
251
    {
252
        $notification = false;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The expression false; of type false adds false to the return on line 266 which is incompatible with the return type documented by XoopsNotificationHandler::get of type XoopsNotification. It seems like you forgot to handle an error condition.
Loading history...
253
        $id           = (int)$id;
254
        if ($id > 0) {
255
            $sql = 'SELECT * FROM ' . $this->db->prefix('xoopsnotifications') . ' WHERE not_id=' . $id;
256
            if (!$result = $this->db->query($sql)) {
257
                return $notification;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $notification; (false) is incompatible with the return type documented by XoopsNotificationHandler::get of type XoopsNotification.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
258
            }
259
            $numrows = $this->db->getRowsNum($result);
260
            if ($numrows == 1) {
261
                $notification = new XoopsNotification();
262
                $notification->assignVars($this->db->fetchArray($result));
263
            }
264
        }
265
266
        return $notification;
267
    }
268
269
    /**
270
     * Write a notification(subscription) to database
271
     *
272
     * @param  XoopsObject|XoopsNotification $notification a XoopsNotification object
273
     *
274
     * @return bool true on success, otherwise false
275
     **/
276
    public function insert(XoopsObject $notification)
277
    {
278
        $className = 'XoopsNotification';
279
        if (!($notification instanceof $className)) {
280
            return false;
281
        }
282
        if (!$notification->isDirty()) {
283
            return true;
284
        }
285
        if (!$notification->cleanVars()) {
286
            return false;
287
        }
288
        foreach ($notification->cleanVars as $k => $v) {
289
            ${$k} = $v;
290
        }
291
        if ($notification->isNew()) {
292
            $not_id = $this->db->genId('xoopsnotifications_not_id_seq');
293
            $sql    = sprintf('INSERT INTO %s (not_id, not_modid, not_itemid, not_category, not_uid, not_event, not_mode) VALUES (%u, %u, %u, %s, %u, %s, %u)', $this->db->prefix('xoopsnotifications'), $not_id, $not_modid, $not_itemid, $this->db->quoteString($not_category), $not_uid, $this->db->quoteString($not_event), $not_mode);
0 ignored issues
show
Bug introduced by
The variable $not_modid does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $not_itemid does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $not_category does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $not_uid does not exist. Did you mean $not_id?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
Bug introduced by
The variable $not_event does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $not_mode does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
294
        } else {
295
            $sql = sprintf('UPDATE %s SET not_modid = %u, not_itemid = %u, not_category = %s, not_uid = %u, not_event = %s, not_mode = %u WHERE not_id = %u', $this->db->prefix('xoopsnotifications'), $not_modid, $not_itemid, $this->db->quoteString($not_category), $not_uid, $this->db->quoteString($not_event), $not_mode, $not_id);
0 ignored issues
show
Bug introduced by
The variable $not_uid does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $not_id seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
296
        }
297
        if (!$result = $this->db->query($sql)) {
298
            return false;
299
        }
300
        if (empty($not_id)) {
301
            $not_id = $this->db->getInsertId();
302
        }
303
        $notification->assignVar('not_id', $not_id);
304
305
        return true;
306
    }
307
308
    /**
309
     * Delete a {@link XoopsNotification} from the database
310
     *
311
     * @param  XoopsObject|XoopsNotification $notification a XoopsNotification object
312
     *
313
     * @return bool true on success, otherwise false
314
     **/
315
    public function delete(XoopsObject $notification)
316
    {
317
        $className = 'XoopsNotification';
318
        if (!($notification instanceof $className)) {
319
            return false;
320
        }
321
322
        $sql = sprintf('DELETE FROM %s WHERE not_id = %u', $this->db->prefix('xoopsnotifications'), $notification->getVar('not_id'));
323
        if (!$result = $this->db->query($sql)) {
324
            return false;
325
        }
326
327
        return true;
328
    }
329
330
    /**
331
     * Get some {@link XoopsNotification}s
332
     *
333
     * @param CriteriaElement $criteria
334
     * @param bool            $id_as_key Use IDs as keys into the array?
335
     *
336
     * @return array Array of {@link XoopsNotification} objects
337
     **/
338 View Code Duplication
    public function getObjects(CriteriaElement $criteria = null, $id_as_key = false)
339
    {
340
        $ret   = array();
341
        $limit = $start = 0;
342
        $sql   = 'SELECT * FROM ' . $this->db->prefix('xoopsnotifications');
343
        if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
344
            $sql .= ' ' . $criteria->renderWhere();
0 ignored issues
show
Bug introduced by
The method renderWhere() does not exist on CriteriaElement. Did you maybe mean render()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
345
            $sort = ($criteria->getSort() != '') ? $criteria->getSort() : 'not_id';
346
            $sql .= ' ORDER BY ' . $sort . ' ' . $criteria->getOrder();
347
            $limit = $criteria->getLimit();
348
            $start = $criteria->getStart();
349
        }
350
        $result = $this->db->query($sql, $limit, $start);
351
        if (!$result) {
352
            return $ret;
353
        }
354
        while ($myrow = $this->db->fetchArray($result)) {
355
            $notification = new XoopsNotification();
356
            $notification->assignVars($myrow);
357
            if (!$id_as_key) {
358
                $ret[] =& $notification;
359
            } else {
360
                $ret[$myrow['not_id']] =& $notification;
361
            }
362
            unset($notification);
363
        }
364
365
        return $ret;
366
    }
367
368
    // TODO: Need this??
369
    /**
370
     * Count Notifications
371
     *
372
     * @param CriteriaElement $criteria {@link CriteriaElement}
373
     *
374
     * @return int Count
375
     **/
376 View Code Duplication
    public function getCount(CriteriaElement $criteria = null)
377
    {
378
        $sql = 'SELECT COUNT(*) FROM ' . $this->db->prefix('xoopsnotifications');
379
        if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
380
            $sql .= ' ' . $criteria->renderWhere();
0 ignored issues
show
Bug introduced by
The method renderWhere() does not exist on CriteriaElement. Did you maybe mean render()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
381
        }
382
        if (!$result = $this->db->query($sql)) {
383
            return 0;
384
        }
385
        list($count) = $this->db->fetchRow($result);
386
387
        return $count;
388
    }
389
390
    /**
391
     * Delete multiple notifications
392
     *
393
     * @param CriteriaElement $criteria {@link CriteriaElement}
394
     *
395
     * @return bool
396
     **/
397 View Code Duplication
    public function deleteAll(CriteriaElement $criteria = null)
398
    {
399
        $sql = 'DELETE FROM ' . $this->db->prefix('xoopsnotifications');
400
        if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
401
            $sql .= ' ' . $criteria->renderWhere();
0 ignored issues
show
Bug introduced by
The method renderWhere() does not exist on CriteriaElement. Did you maybe mean render()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
402
        }
403
        if (!$result = $this->db->query($sql)) {
404
            return false;
405
        }
406
407
        return true;
408
    }
409
410
    // TODO: rename this...
411
    // Also, should we have get by module, get by category, etc...??
412
    /**
413
     * @param $module_id
414
     * @param $category
415
     * @param $item_id
416
     * @param $event
417
     * @param $user_id
418
     *
419
     * @return bool
420
     */
421
    public function &getNotification($module_id, $category, $item_id, $event, $user_id)
422
    {
423
        $criteria = new CriteriaCompo();
424
        $criteria->add(new Criteria('not_modid', (int)$module_id));
425
        $criteria->add(new Criteria('not_category', $this->db->escape($category)));
426
        $criteria->add(new Criteria('not_itemid', (int)$item_id));
427
        $criteria->add(new Criteria('not_event', $this->db->escape($event)));
428
        $criteria->add(new Criteria('not_uid', (int)$user_id));
429
        $objects = $this->getObjects($criteria);
430
        if (count($objects) == 1) {
431
            return $objects[0];
432
        }
433
        $inst = false;
434
435
        return $inst;
436
    }
437
438
    /**
439
     * Determine if a user is subscribed to a particular event in
440
     * a particular module.
441
     *
442
     * @param string $category  Category of notification event
443
     * @param int    $item_id   Item ID of notification event
444
     * @param string $event     Event
445
     * @param int    $module_id ID of module (default current module)
446
     * @param int    $user_id   ID of user (default current user)
447
     *                          return int  0 if not subscribe; non-zero if subscribed
448
     *
449
     * @return int
450
     */
451
    public function isSubscribed($category, $item_id, $event, $module_id, $user_id)
452
    {
453
        $criteria = new CriteriaCompo();
454
        $criteria->add(new Criteria('not_modid', (int)$module_id));
455
        $criteria->add(new Criteria('not_category', $this->db->escape($category)));
456
        $criteria->add(new Criteria('not_itemid', (int)$item_id));
457
        $criteria->add(new Criteria('not_event', $this->db->escape($event)));
458
        $criteria->add(new Criteria('not_uid', (int)$user_id));
459
460
        return $this->getCount($criteria);
461
    }
462
463
    // TODO: how about a function to subscribe a whole group of users???
464
    // e.g. if we want to add all moderators to be notified of subscription
465
    // of new threads...
466
    /**
467
     * Subscribe for notification for an event(s)
468
     *
469
     * @param string $category  category of notification
470
     * @param int    $item_id   ID of the item
471
     * @param mixed  $events    event string or array of events
472
     * @param int    $mode      force a particular notification mode
473
     *                          (e.g. once_only) (default to current user preference)
474
     * @param int    $module_id ID of the module (default to current module)
475
     * @param int    $user_id   ID of the user (default to current user)
476
     *                          *
477
     *
478
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be false|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
479
     */
480
    public function subscribe($category, $item_id, $events, $mode = null, $module_id = null, $user_id = null)
481
    {
482 View Code Duplication
        if (!isset($user_id)) {
483
            global $xoopsUser;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
484
            if (empty($xoopsUser)) {
485
                return false; // anonymous cannot subscribe
486
            } else {
487
                $user_id = $xoopsUser->getVar('uid');
488
            }
489
        }
490
491
        if (!isset($module_id)) {
492
            global $xoopsModule;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
493
            $module_id = $xoopsModule->getVar('mid');
494
        }
495
496
        if (!isset($mode)) {
497
            $user = new XoopsUser($user_id);
498
            $mode = $user->getVar('notify_mode');
499
        }
500
501
        if (!is_array($events)) {
502
            $events = array($events);
503
        }
504
        foreach ($events as $event) {
505
            if ($notification =& $this->getNotification($module_id, $category, $item_id, $event, $user_id)) {
506
                if ($notification->getVar('not_mode') != $mode) {
0 ignored issues
show
Bug introduced by
The method getVar cannot be called on $notification (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
507
                    $this->updateByField($notification, 'not_mode', $mode);
508
                }
509
            } else {
510
                $notification = $this->create();
511
                $notification->setVar('not_modid', $module_id);
512
                $notification->setVar('not_category', $category);
513
                $notification->setVar('not_itemid', $item_id);
514
                $notification->setVar('not_uid', $user_id);
515
                $notification->setVar('not_event', $event);
516
                $notification->setVar('not_mode', $mode);
517
                $this->insert($notification);
518
            }
519
        }
520
        return null;
521
    }
522
523
    // TODO: this will be to provide a list of everything a particular
524
    // user has subscribed to... e.g. for on the 'Profile' page, similar
525
    // to how we see the various posts etc. that the user has made.
526
    // We may also want to have a function where we can specify module id
527
    /**
528
     * Get a list of notifications by user ID
529
     *
530
     * @param int $user_id ID of the user
531
     *
532
     * @return array Array of {@link XoopsNotification} objects
533
     **/
534
    public function getByUser($user_id)
535
    {
536
        $criteria = new Criteria('not_uid', $user_id);
537
538
        return $this->getObjects($criteria, true);
539
    }
540
541
    // TODO: rename this??
542
    /**
543
     * Get a list of notification events for the current item/mod/user
544
     *
545
     * @param $category
546
     * @param $item_id
547
     * @param $module_id
548
     * @param $user_id
549
     * @return array
550
     */
551
    public function getSubscribedEvents($category, $item_id, $module_id, $user_id)
552
    {
553
        $criteria = new CriteriaCompo();
554
        $criteria->add(new Criteria('not_modid', (int)$module_id));
555
        $criteria->add(new Criteria('not_category', $this->db->escape($category)));
556
        if ($item_id) {
557
            $criteria->add(new Criteria('not_itemid', (int)$item_id));
558
        }
559
        $criteria->add(new Criteria('not_uid', (int)$user_id));
560
        $results = $this->getObjects($criteria, true);
561
        $ret     = array();
562
        foreach (array_keys($results) as $i) {
563
            $ret[] = $results[$i]->getVar('not_event');
564
        }
565
566
        return $ret;
567
    }
568
569
    // TODO: is this a useful function?? (Copied from comment_handler)
570
    /**
571
     * Retrieve items by their ID
572
     *
573
     * @param int    $module_id Module ID
574
     * @param int    $item_id   Item ID
575
     * @param string $order     Sort order
576
     *
577
     * @param null   $status
578
     *
579
     * @return array Array of {@link XoopsNotification} objects
580
     */
581 View Code Duplication
    public function getByItemId($module_id, $item_id, $order = null, $status = null)
582
    {
583
        $criteria = new CriteriaCompo(new Criteria('com_modid', (int)$module_id));
584
        $criteria->add(new Criteria('com_itemid', (int)$item_id));
585
        if (isset($status)) {
586
            $criteria->add(new Criteria('com_status', (int)$status));
587
        }
588
        if (isset($order)) {
589
            $criteria->setOrder($order);
590
        }
591
592
        return $this->getObjects($criteria);
593
    }
594
595
    /**
596
     * Send notifications to users
597
     *
598
     * @param string $category     notification category
599
     * @param int    $item_id      ID of the item
600
     * @param array  $events       trigger events
601
     * @param array  $extra_tags   array of substitutions for template to be
602
     *                              merged with the one from function..
603
     * @param array  $user_list    only notify the selected users
604
     * @param int    $module_id    ID of the module
605
     * @param int    $omit_user_id ID of the user to omit from notifications. (default to current user).  set to 0 for all users to receive notification.
606
     * @internal param string $event notification event
607
     */
608
    // TODO:(?) - pass in an event LIST.  This will help to avoid
609
    // problem of sending people multiple emails for similar events.
610
    // BUT, then we need an array of mail templates, etc...  Unless
611
    // mail templates can include logic in the future, then we can
612
    // tailor the mail so it makes sense for any of the possible
613
    // (or combination of) events.
614
    public function triggerEvents($category, $item_id, $events, $extra_tags = array(), $user_list = array(), $module_id = null, $omit_user_id = null)
615
    {
616
        if (!is_array($events)) {
617
            $events = array($events);
618
        }
619
        foreach ($events as $event) {
620
            $this->triggerEvent($category, $item_id, $event, $extra_tags, $user_list, $module_id, $omit_user_id);
621
        }
622
    }
623
624
    /**
625
     * Enter description here...
626
     *
627
     * @param  int   $category
628
     * @param  int   $item_id
629
     * @param  int   $event
630
     * @param  array $extra_tags
631
     * @param  array $user_list
632
     * @param  int   $module_id
633
     * @param  int   $omit_user_id
634
     * @return mixed
635
     */
636
    public function triggerEvent($category, $item_id, $event, $extra_tags = array(), $user_list = array(), $module_id = null, $omit_user_id = null)
637
    {
638 View Code Duplication
        if (!isset($module_id)) {
639
            global $xoopsModule;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
640
            $module    =& $xoopsModule;
641
            $module_id = !empty($xoopsModule) ? $xoopsModule->getVar('mid') : 0;
642
        } else {
643
            $module_handler = xoops_getHandler('module');
644
            $module         = $module_handler->get($module_id);
645
        }
646
647
        // Check if event is enabled
648
        $config_handler = xoops_getHandler('config');
649
        $mod_config     = $config_handler->getConfigsByCat(0, $module->getVar('mid'));
650
        if (empty($mod_config['notification_enabled'])) {
651
            return false;
652
        }
653
        $category_info =& notificationCategoryInfo($category, $module_id);
654
        $event_info    =& notificationEventInfo($category, $event, $module_id);
655
        if (!in_array(notificationGenerateConfig($category_info, $event_info, 'option_name'), $mod_config['notification_events']) && empty($event_info['invisible'])) {
656
            return false;
657
        }
658
659 View Code Duplication
        if (!isset($omit_user_id)) {
660
            global $xoopsUser;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
661
            $omit_user_id = 0;
662
            if (!empty($xoopsUser)) {
663
                $omit_user_id = $xoopsUser->getVar('uid');
664
            }
665
        }
666
        $criteria = new CriteriaCompo();
667
        $criteria->add(new Criteria('not_modid', (int)$module_id));
668
        $criteria->add(new Criteria('not_category', $this->db->escape($category)));
669
        $criteria->add(new Criteria('not_itemid', (int)$item_id));
670
        $criteria->add(new Criteria('not_event', $this->db->escape($event)));
671
        $mode_criteria = new CriteriaCompo();
672
        $mode_criteria->add(new Criteria('not_mode', XOOPS_NOTIFICATION_MODE_SENDALWAYS), 'OR');
673
        $mode_criteria->add(new Criteria('not_mode', XOOPS_NOTIFICATION_MODE_SENDONCETHENDELETE), 'OR');
674
        $mode_criteria->add(new Criteria('not_mode', XOOPS_NOTIFICATION_MODE_SENDONCETHENWAIT), 'OR');
675
        $criteria->add($mode_criteria);
676
        if (!empty($user_list)) {
677
            $user_criteria = new CriteriaCompo();
678
            foreach ($user_list as $user) {
679
                $user_criteria->add(new Criteria('not_uid', (int)$user), 'OR');
680
            }
681
            $criteria->add($user_criteria);
682
        }
683
        $notifications = $this->getObjects($criteria);
684
        if (empty($notifications)) {
685
            return null;
686
        }
687
688
        // Add some tag substitutions here
689
690
        $not_config = $module->getInfo('notification');
691
        $tags       = array();
692
        if (!empty($not_config)) {
693 View Code Duplication
            if (!empty($not_config['tags_file'])) {
694
                $tags_file = $GLOBALS['xoops']->path('modules/' . $module->getVar('dirname') . '/' . $not_config['tags_file']);
695
                if (file_exists($tags_file)) {
696
                    include_once $tags_file;
697
                    if (!empty($not_config['tags_func'])) {
698
                        $tags_func = $not_config['tags_func'];
699
                        if (function_exists($tags_func)) {
700
                            $tags = $tags_func($category, (int)$item_id, $event);
701
                        }
702
                    }
703
                }
704
            }
705
            // RMV-NEW
706 View Code Duplication
            if (!empty($not_config['lookup_file'])) {
707
                $lookup_file = $GLOBALS['xoops']->path('modules/' . $module->getVar('dirname') . '/' . $not_config['lookup_file']);
708
                if (file_exists($lookup_file)) {
709
                    include_once $lookup_file;
710
                    if (!empty($not_config['lookup_func'])) {
711
                        $lookup_func = $not_config['lookup_func'];
712
                        if (function_exists($lookup_func)) {
713
                            $item_info = $lookup_func($category, (int)$item_id);
714
                        }
715
                    }
716
                }
717
            }
718
        }
719
        $tags['X_ITEM_NAME']       = !empty($item_info['name']) ? $item_info['name'] : '[' . _NOT_ITEMNAMENOTAVAILABLE . ']';
720
        $tags['X_ITEM_URL']        = !empty($item_info['url']) ? $item_info['url'] : '[' . _NOT_ITEMURLNOTAVAILABLE . ']';
721
        $tags['X_ITEM_TYPE']       = !empty($category_info['item_name']) ? $category_info['title'] : '[' . _NOT_ITEMTYPENOTAVAILABLE . ']';
722
        $tags['X_MODULE']          = $module->getVar('name');
723
        $tags['X_MODULE_URL']      = XOOPS_URL . '/modules/' . $module->getVar('dirname') . '/';
724
        $tags['X_NOTIFY_CATEGORY'] = $category;
725
        $tags['X_NOTIFY_EVENT']    = $event;
726
727
        $template_dir = $event_info['mail_template_dir'];
728
        $template     = $event_info['mail_template'] . '.tpl';
729
        $subject      = $event_info['mail_subject'];
730
731
        foreach ($notifications as $notification) {
732
            if (empty($omit_user_id) || $notification->getVar('not_uid') != $omit_user_id) {
733
                // user-specific tags
734
                //$tags['X_UNSUBSCRIBE_URL'] = 'TODO';
735
                // TODO: don't show unsubscribe link if it is 'one-time' ??
736
                $tags['X_UNSUBSCRIBE_URL'] = XOOPS_URL . '/notifications.php';
737
                $tags                      = array_merge($tags, $extra_tags);
738
                $notification->notifyUser($template_dir, $template, $subject, $tags);
739
            }
740
        }
741
        return null;
742
    }
743
744
    /**
745
     * Delete all notifications for one user
746
     *
747
     * @param  int $user_id ID of the user
748
     * @return bool
749
     **/
750
    public function unsubscribeByUser($user_id)
751
    {
752
        $criteria = new Criteria('not_uid', (int)$user_id);
753
754
        return $this->deleteAll($criteria);
755
    }
756
757
    // TODO: allow these to use current module, etc...
758
    /**
759
     * Unsubscribe notifications for an event(s).
760
     *
761
     * @param string $category  category of the events
762
     * @param int    $item_id   ID of the item
763
     * @param mixed  $events    event string or array of events
764
     * @param int    $module_id ID of the module (default current module)
765
     * @param int    $user_id   UID of the user (default current user)
766
     *
767
     * @return bool
768
     **/
769
    public function unsubscribe($category, $item_id, $events, $module_id = null, $user_id = null)
770
    {
771 View Code Duplication
        if (!isset($user_id)) {
772
            global $xoopsUser;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
773
            if (empty($xoopsUser)) {
774
                return false; // anonymous cannot subscribe
775
            } else {
776
                $user_id = $xoopsUser->getVar('uid');
777
            }
778
        }
779
        if (!isset($module_id)) {
780
            global $xoopsModule;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
781
            $module_id = $xoopsModule->getVar('mid');
782
        }
783
        $criteria = new CriteriaCompo();
784
        $criteria->add(new Criteria('not_modid', (int)$module_id));
785
        $criteria->add(new Criteria('not_category', $this->db->escape($category)));
786
        $criteria->add(new Criteria('not_itemid', (int)$item_id));
787
        $criteria->add(new Criteria('not_uid', (int)$user_id));
788
        if (!is_array($events)) {
789
            $events = array($events);
790
        }
791
        $event_criteria = new CriteriaCompo();
792
        foreach ($events as $event) {
793
            $event_criteria->add(new Criteria('not_event', $this->db->escape($event)), 'OR');
794
        }
795
        $criteria->add($event_criteria);
796
797
        return $this->deleteAll($criteria);
798
    }
799
800
    // TODO: When 'update' a module, may need to switch around some
801
    //  notification classes/IDs...  or delete the ones that no longer
802
    //  exist.
803
    /**
804
     * Delete all notifications for a particular module
805
     *
806
     * @param  int $module_id ID of the module
807
     * @return bool
808
     **/
809
    public function unsubscribeByModule($module_id)
810
    {
811
        $criteria = new Criteria('not_modid', (int)$module_id);
812
813
        return $this->deleteAll($criteria);
814
    }
815
816
    /**
817
     * Delete all subscriptions for a particular item.
818
     *
819
     * @param int    $module_id ID of the module to which item belongs
820
     * @param string $category  Notification category of the item
821
     * @param int    $item_id   ID of the item
822
     *
823
     * @return bool
824
     **/
825
    public function unsubscribeByItem($module_id, $category, $item_id)
826
    {
827
        $criteria = new CriteriaCompo();
828
        $criteria->add(new Criteria('not_modid', (int)$module_id));
829
        $criteria->add(new Criteria('not_category', $this->db->escape($category)));
830
        $criteria->add(new Criteria('not_itemid', (int)$item_id));
831
832
        return $this->deleteAll($criteria);
833
    }
834
835
    /**
836
     * Perform notification maintenance activites at login time.
837
     * In particular, any notifications for the newly logged-in
838
     * user with mode XOOPS_NOTIFICATION_MODE_WAITFORLOGIN are
839
     * switched to mode XOOPS_NOTIFICATION_MODE_SENDONCETHENWAIT.
840
     *
841
     * @param int $user_id ID of the user being logged in
842
     **/
843
    public function doLoginMaintenance($user_id)
844
    {
845
        $criteria = new CriteriaCompo();
846
        $criteria->add(new Criteria('not_uid', (int)$user_id));
847
        $criteria->add(new Criteria('not_mode', XOOPS_NOTIFICATION_MODE_WAITFORLOGIN));
848
849
        $notifications = $this->getObjects($criteria, true);
850
        foreach ($notifications as $n) {
851
            $n->setVar('not_mode', XOOPS_NOTIFICATION_MODE_SENDONCETHENWAIT);
852
            $this->insert($n);
853
        }
854
    }
855
856
    /**
857
     * Update
858
     *
859
     * @param XoopsNotification $notification {@link XoopsNotification} object
860
     * @param string            $field_name   Name of the field
861
     * @param mixed             $field_value  Value to write
862
     *
863
     * @return bool
864
     **/
865
    public function updateByField(XoopsNotification $notification, $field_name, $field_value)
866
    {
867
        $notification->unsetNew();
868
        $notification->setVar($field_name, $field_value);
869
870
        return $this->insert($notification);
871
    }
872
}
873