XoopsModule   F
last analyzed

Complexity

Total Complexity 87

Size/Duplication

Total Lines 657
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 175
dl 0
loc 657
rs 2
c 1
b 0
f 0
wmc 87

46 Methods

Rating   Name   Duplication   Size   Complexity  
F loadInfoAsVar() 0 23 15
A setMessage() 0 3 1
A __construct() 0 17 1
A mainLink() 0 9 2
A getInfo() 0 15 4
A versionCompare() 0 11 3
A getMessages() 0 3 1
A setInfo() 0 9 2
A getStatus() 0 3 1
A id() 0 3 1
A checkAccess() 0 5 1
A executeScript() 0 5 1
A gettemplate() 0 5 1
A subLink() 0 15 4
A install() 0 5 1
A hassearch() 0 3 1
A hasnotification() 0 3 1
A insert() 0 5 1
A update() 0 5 1
A insertGroupPermissions() 0 5 1
A getAdminMenu() 0 7 2
A getCurrentPage() 0 5 1
A name() 0 3 1
A loadErrorMessages() 0 5 1
A insertConfigCategories() 0 5 1
A loadLanguage() 0 5 1
A executeSQL() 0 5 1
A insertConfig() 0 5 1
A version() 0 3 1
A mid() 0 3 1
A icon() 0 3 1
A weight() 0 3 1
A last_update() 0 3 1
A getByDirname() 0 7 1
A dirname() 0 3 1
A hasmain() 0 3 1
A hascomments() 0 3 1
A insertTemplates() 0 5 1
A loadInfo() 0 28 6
A insertBlocks() 0 5 1
A hasadmin() 0 3 1
B search() 0 21 9
A isactive() 0 3 1
A hasconfig() 0 3 1
A loadAdminMenu() 0 7 4
A insertProfileFields() 0 5 1

How to fix   Complexity   

Complex Class

Complex classes like XoopsModule often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use XoopsModule, and based on these observations, apply Extract Interface, too.

1
<?php
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-2025 XOOPS Project (https://xoops.org)
13
 * @license             GNU GPL 2 (https://www.gnu.org/licenses/gpl-2.0.html)
14
 * @package             kernel
15
 * @since               2.0.0
16
 */
17
defined('XOOPS_ROOT_PATH') || exit('Restricted access');
18
19
/**
20
 * A Module
21
 *
22
 * @package kernel
23
 * @author  Kazumi Ono <[email protected]>
24
 */
25
class XoopsModule extends XoopsObject
26
{
27
    /**
28
     *
29
     * @var string
30
     */
31
    public $modinfo;
32
    /**
33
     *
34
     * @var array
35
     */
36
    public $adminmenu;
37
    /**
38
     *
39
     * @var array
40
     */
41
    public $_msg;
42
43
    //PHP 8.2 Dynamic properties deprecated
44
    public $mid;
45
    public $name;
46
    public $version;
47
    public $last_update;
48
    public $weight;
49
    public $isactive;
50
    public $dirname;
51
    public $hasmain;
52
    public $hasadmin;
53
    public $hassearch;
54
    public $hasconfig;
55
    public $hascomments;
56
    // RMV-NOTIFY
57
    public $hasnotification;
58
59
    /**
60
     * Constructor
61
     */
62
    public function __construct()
63
    {
64
        parent::__construct();
65
        $this->initVar('mid', XOBJ_DTYPE_INT, null, false);
66
        $this->initVar('name', XOBJ_DTYPE_TXTBOX, null, true, 150);
67
        $this->initVar('version', XOBJ_DTYPE_TXTBOX, null, false);
68
        $this->initVar('last_update', XOBJ_DTYPE_INT, null, false);
69
        $this->initVar('weight', XOBJ_DTYPE_INT, 0, false);
70
        $this->initVar('isactive', XOBJ_DTYPE_INT, 1, false);
71
        $this->initVar('dirname', XOBJ_DTYPE_OTHER, null, true);
72
        $this->initVar('hasmain', XOBJ_DTYPE_INT, 0, false);
73
        $this->initVar('hasadmin', XOBJ_DTYPE_INT, 0, false);
74
        $this->initVar('hassearch', XOBJ_DTYPE_INT, 0, false);
75
        $this->initVar('hasconfig', XOBJ_DTYPE_INT, 0, false);
76
        $this->initVar('hascomments', XOBJ_DTYPE_INT, 0, false);
77
        // RMV-NOTIFY
78
        $this->initVar('hasnotification', XOBJ_DTYPE_INT, 0, false);
79
    }
80
81
    /**
82
     * Load module info
83
     *
84
     * @param string  $dirname Directory Name
85
     * @param boolean $verbose
86
     */
87
    public function loadInfoAsVar($dirname, $verbose = true)
88
    {
89
        $dirname = basename($dirname);
90
        if (!isset($this->modinfo)) {
91
            $this->loadInfo($dirname, $verbose);
92
        }
93
        $this->setVar('name', $this->modinfo['name'], true);
94
        $this->setVar('version', $this->modinfo['version'], true);
95
        $this->setVar('dirname', $this->modinfo['dirname'], true);
96
        $hasmain     = (isset($this->modinfo['hasMain']) && $this->modinfo['hasMain'] == 1) ? 1 : 0;
97
        $hasadmin    = (isset($this->modinfo['hasAdmin']) && $this->modinfo['hasAdmin'] == 1) ? 1 : 0;
98
        $hassearch   = (isset($this->modinfo['hasSearch']) && $this->modinfo['hasSearch'] == 1) ? 1 : 0;
99
        $hasconfig   = ((isset($this->modinfo['config']) && \is_array($this->modinfo['config'])) || !empty($this->modinfo['hasComments'])) ? 1 : 0;
100
        $hascomments = (isset($this->modinfo['hasComments']) && $this->modinfo['hasComments'] == 1) ? 1 : 0;
101
        // RMV-NOTIFY
102
        $hasnotification = (isset($this->modinfo['hasNotification']) && $this->modinfo['hasNotification'] == 1) ? 1 : 0;
103
        $this->setVar('hasmain', $hasmain);
104
        $this->setVar('hasadmin', $hasadmin);
105
        $this->setVar('hassearch', $hassearch);
106
        $this->setVar('hasconfig', $hasconfig);
107
        $this->setVar('hascomments', $hascomments);
108
        // RMV-NOTIFY
109
        $this->setVar('hasnotification', $hasnotification);
110
    }
111
112
    /**
113
     * add a message
114
     *
115
     * @param string $str message to add
116
     * @access public
117
     */
118
    public function setMessage($str)
119
    {
120
        $this->_msg[] = trim($str);
121
    }
122
123
    /**
124
     * return the messages for this object as an array
125
     *
126
     * @return array an array of messages
127
     * @access public
128
     */
129
    public function getMessages()
130
    {
131
        return $this->_msg;
132
    }
133
134
    /**
135
     * Set module info
136
     *
137
     * @param  string $name
138
     * @param  mixed  $value
139
     * @return bool
140
     **/
141
    public function setInfo($name, $value)
142
    {
143
        if (empty($name)) {
144
            $this->modinfo = $value;
145
        } else {
146
            $this->modinfo[$name] = $value;
147
        }
148
149
        return true;
150
    }
151
152
    /**
153
     * Get module info
154
     *
155
     * @param  string $name
156
     * @return array|string    Array of module information.
157
     *                     If {@link $name} is set, returns a single module information item as string.
158
     */
159
    public function &getInfo($name = null)
160
    {
161
        if (!isset($this->modinfo)) {
162
            $this->loadInfo($this->getVar('dirname'));
0 ignored issues
show
Bug introduced by
It seems like $this->getVar('dirname') can also be of type array and array; however, parameter $dirname of XoopsModule::loadInfo() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

162
            $this->loadInfo(/** @scrutinizer ignore-type */ $this->getVar('dirname'));
Loading history...
163
        }
164
        if (isset($name)) {
165
            if (isset($this->modinfo[$name])) {
166
                return $this->modinfo[$name];
167
            }
168
            $return = false;
169
170
            return $return;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $return returns the type false which is incompatible with the documented return type array|string.
Loading history...
171
        }
172
173
        return $this->modinfo;
174
    }
175
176
    /**
177
     * Get status
178
     *
179
     * @return string
180
     */
181
    public function getStatus()
182
    {
183
        return substr(strrchr($this->getVar('version'), '-'), 1);
184
    }
185
186
    /**
187
     * Compares two "XOOPS-standardized" version number strings.
188
     *
189
     * @param  string $version1
190
     * @param  string $version2
191
     * @param  string $operator
192
     * @return boolean The function will return true if the relationship is the one specified by the operator, false otherwise.
193
     */
194
    public function versionCompare($version1 = '', $version2 = '', $operator = '<')
195
    {
196
        $version1 = strtolower($version1);
197
        $version2 = strtolower($version2);
198
        if (false !== strpos($version2, '-stable')) {
199
            $version2 = substr($version2, 0, strpos($version2, '-stable'));
200
        }
201
        if (false !== strpos($version1, '-stable')) {
202
            $version1 = substr($version1, 0, strpos($version1, '-stable'));
203
        }
204
        return version_compare($version1, $version2, $operator);
0 ignored issues
show
Bug Best Practice introduced by
The expression return version_compare($..., $version2, $operator) also could return the type integer which is incompatible with the documented return type boolean.
Loading history...
205
    }
206
207
    /**
208
     * Get a link to the modules main page
209
     *
210
     * @return string FALSE on fail
211
     */
212
    public function mainLink()
213
    {
214
        if ($this->getVar('hasmain') == 1) {
215
            $ret = '<a href="' . XOOPS_URL . '/modules/' . $this->getVar('dirname') . '/">' . $this->getVar('name') . '</a>';
216
217
            return $ret;
218
        }
219
220
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
221
    }
222
223
    /**
224
     * Get links to the subpages
225
     *
226
     * @return array
227
     */
228
    public function subLink()
229
    {
230
        $ret = [];
231
        if ($this->getInfo('sub') && \is_array($this->getInfo('sub'))) {
232
            foreach ($this->getInfo('sub') as $submenu) {
233
                $ret[] = [
234
                    'id' => $submenu['id']?? '',
235
                    'name' => $submenu['name'],
236
                    'url'  => $submenu['url'],
237
                    'icon' => $submenu['icon']?? '',
238
                ];
239
            }
240
        }
241
242
        return $ret;
243
    }
244
245
    /**
246
     * Load the admin menu for the module
247
     */
248
    public function loadAdminMenu()
249
    {
250
        $adminmenu = [];
251
        if ($this->getInfo('adminmenu') && $this->getInfo('adminmenu') != '' && file_exists(XOOPS_ROOT_PATH . '/modules/' . $this->getVar('dirname') . '/' . $this->getInfo('adminmenu'))) {
0 ignored issues
show
Bug introduced by
Are you sure $this->getInfo('adminmenu') of type array|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

251
        if ($this->getInfo('adminmenu') && $this->getInfo('adminmenu') != '' && file_exists(XOOPS_ROOT_PATH . '/modules/' . $this->getVar('dirname') . '/' . /** @scrutinizer ignore-type */ $this->getInfo('adminmenu'))) {
Loading history...
252
            include XOOPS_ROOT_PATH . '/modules/' . $this->getVar('dirname') . '/' . $this->getInfo('adminmenu');
253
        }
254
        $this->adminmenu = & $adminmenu;
255
    }
256
257
    /**
258
     * Get the admin menu for the module
259
     *
260
     * @return array
261
     */
262
    public function &getAdminMenu()
263
    {
264
        if (!isset($this->adminmenu)) {
265
            $this->loadAdminMenu();
266
        }
267
268
        return $this->adminmenu;
269
    }
270
271
    /**
272
     * Load the module info for this module
273
     *
274
     * @param string $dirname Module directory
275
     * @param bool   $verbose Give an error on fail?
276
     *
277
     * @return bool true if loaded
278
     */
279
    public function loadInfo($dirname, $verbose = true)
280
    {
281
        static $modVersions;
282
        $dirname = basename($dirname);
283
        if (isset($modVersions[$dirname])) {
284
            $this->modinfo = $modVersions[$dirname];
285
286
            return true;
287
        }
288
        global $xoopsConfig;
289
        if (file_exists($file = $GLOBALS['xoops']->path('modules/' . $dirname . '/language/' . $xoopsConfig['language'] . '/modinfo.php'))) {
290
            include_once $file;
291
        } elseif (file_exists($file = $GLOBALS['xoops']->path('modules/' . $dirname . '/language/english/modinfo.php'))) {
292
            include_once $file;
293
        }
294
295
        if (!file_exists($file = $GLOBALS['xoops']->path('modules/' . $dirname . '/xoops_version.php'))) {
296
            if (false !== (bool) $verbose) {
297
                echo "Module File for $dirname Not Found!";
298
            }
299
300
            return false;
301
        }
302
        include $file;
303
        $modVersions[$dirname] = $modversion;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $modversion does not exist. Did you maybe mean $modVersions?
Loading history...
304
        $this->modinfo         = $modVersions[$dirname];
305
306
        return true;
307
    }
308
309
    /**
310
     * Search contents within a module
311
     *
312
     * @param  string  $term
313
     * @param  string  $andor 'AND' or 'OR'
314
     * @param  integer $limit
315
     * @param  integer $offset
316
     * @param  integer $userid
317
     * @return mixed   Search result.
318
     */
319
    public function search($term = '', $andor = 'AND', $limit = 0, $offset = 0, $userid = 0)
320
    {
321
        if ($this->getVar('hassearch') != 1) {
322
            return false;
323
        }
324
        $search = & $this->getInfo('search');
325
        if ($this->getVar('hassearch') != 1 || !isset($search['file']) || !isset($search['func']) || $search['func'] == '' || $search['file'] == '') {
326
            return false;
327
        }
328
        if (file_exists($file = $GLOBALS['xoops']->path('modules/' . $this->getVar('dirname') . '/' . $search['file']))) {
329
            include_once $file;
330
        } else {
331
            return false;
332
        }
333
        if (function_exists($search['func'])) {
334
            $func = $search['func'];
335
336
            return $func($term, $andor, $limit, $offset, $userid);
337
        }
338
339
        return false;
340
    }
341
342
    /**
343
     * Returns Class Base Variable mid
344
     * @param  string $format
345
     * @return mixed
346
     */
347
    public function id($format = 'N')
348
    {
349
        return $this->getVar('mid', $format);
350
    }
351
352
    /**
353
     * Returns Class Base Variable mid
354
     * @param  string $format
355
     * @return mixed
356
     */
357
    public function mid($format = '')
358
    {
359
        return $this->getVar('mid', $format);
360
    }
361
362
    /**
363
     * Returns Class Base Variable name
364
     * @param  string $format
365
     * @return mixed
366
     */
367
    public function name($format = '')
368
    {
369
        return $this->getVar('name', $format);
370
    }
371
372
    /**
373
     * Returns Class Base Variable version
374
     * @param  string $format
375
     * @return mixed
376
     */
377
    public function version($format = '')
378
    {
379
        return $this->getVar('version', $format);
380
    }
381
382
    /**
383
     * Returns Class Base Variable last_update
384
     * @param  string $format
385
     * @return mixed
386
     */
387
    public function last_update($format = '')
388
    {
389
        return $this->getVar('last_update', $format);
390
    }
391
392
    /**
393
     * Returns Class Base Variable weight
394
     * @param  string $format
395
     * @return mixed
396
     */
397
    public function weight($format = '')
398
    {
399
        return $this->getVar('weight', $format);
400
    }
401
402
    /**
403
     * Returns Class Base Variable isactive
404
     * @param  string $format
405
     * @return mixed
406
     */
407
    public function isactive($format = '')
408
    {
409
        return $this->getVar('isactive', $format);
410
    }
411
412
    /**
413
     * Returns Class Base Variable dirname
414
     * @param  string $format
415
     * @return mixed
416
     */
417
    public function dirname($format = '')
418
    {
419
        return $this->getVar('dirname', $format);
420
    }
421
422
    /**
423
     * Returns Class Base Variable hasmain
424
     * @param  string $format
425
     * @return mixed
426
     */
427
    public function hasmain($format = '')
428
    {
429
        return $this->getVar('hasmain', $format);
430
    }
431
432
    /**
433
     * Returns Class Base Variable hasadmin
434
     * @param  string $format
435
     * @return mixed
436
     */
437
    public function hasadmin($format = '')
438
    {
439
        return $this->getVar('hasadmin', $format);
440
    }
441
442
    /**
443
     * Returns Class Base Variable hassearch
444
     * @param  string $format
445
     * @return mixed
446
     */
447
    public function hassearch($format = '')
448
    {
449
        return $this->getVar('hassearch', $format);
450
    }
451
452
    /**
453
     * Returns Class Base Variable hasconfig
454
     * @param  string $format
455
     * @return mixed
456
     */
457
    public function hasconfig($format = '')
458
    {
459
        return $this->getVar('hasconfig', $format);
460
    }
461
462
    /**
463
     * Returns Class Base Variable hascomments
464
     * @param  string $format
465
     * @return mixed
466
     */
467
    public function hascomments($format = '')
468
    {
469
        return $this->getVar('hascomments', $format);
470
    }
471
472
    /**
473
     * Returns Class Base Variable hasnotification
474
     * @param  string $format
475
     * @return mixed
476
     */
477
    public function hasnotification($format = '')
478
    {
479
        return $this->getVar('hasnotification', $format);
480
    }
481
482
    /**
483
     * @param $dirname
484
     *
485
     * @return mixed
486
     */
487
    public static function getByDirname($dirname)
488
    {
489
        /** @var XoopsModuleHandler $modhandler */
490
        $modhandler = xoops_getHandler('module');
491
        $inst       = $modhandler->getByDirname($dirname);
492
493
        return $inst;
494
    }
495
496
497
    /**
498
     * Returns Class Base Variable icon
499
     * @param  string $format
500
     * @return mixed
501
     */
502
    public function icon($format = '')
503
    {
504
        return $this->getVar('icon', $format);
505
    }
506
507
508
    ##################### Deprecated Methods ######################
509
510
    /**#@+
511
     * @deprecated
512
     */
513
    public function checkAccess()
514
    {
515
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
516
517
        return false;
518
    }
519
520
    /**
521
     * @param string $type
522
     *
523
     * @return bool
524
     */
525
    public function loadLanguage($type = 'main')
0 ignored issues
show
Unused Code introduced by
The parameter $type is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

525
    public function loadLanguage(/** @scrutinizer ignore-unused */ $type = 'main')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
526
    {
527
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
528
529
        return false;
530
    }
531
532
    /**
533
     * @return bool
534
     */
535
    public function loadErrorMessages()
536
    {
537
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
538
539
        return false;
540
    }
541
542
    /**
543
     * @return bool
544
     */
545
    public function getCurrentPage()
546
    {
547
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
548
549
        return false;
550
    }
551
552
    /**
553
     * @param array $admingroups
554
     * @param array $accessgroups
555
     *
556
     * @return bool
557
     */
558
    public function install($admingroups = [], $accessgroups = [])
0 ignored issues
show
Unused Code introduced by
The parameter $accessgroups is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

558
    public function install($admingroups = [], /** @scrutinizer ignore-unused */ $accessgroups = [])

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $admingroups is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

558
    public function install(/** @scrutinizer ignore-unused */ $admingroups = [], $accessgroups = [])

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
559
    {
560
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
561
562
        return false;
563
    }
564
565
    /**
566
     * @return bool
567
     */
568
    public function update()
569
    {
570
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
571
572
        return false;
573
    }
574
575
    /**
576
     * @return bool
577
     */
578
    public function insert()
579
    {
580
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
581
582
        return false;
583
    }
584
585
    /**
586
     * @return bool
587
     */
588
    public function executeSQL()
589
    {
590
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
591
592
        return false;
593
    }
594
595
    /**
596
     * @return bool
597
     */
598
    public function insertTemplates()
599
    {
600
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
601
602
        return false;
603
    }
604
605
    /**
606
     * @param      $template
607
     * @param bool $block
608
     *
609
     * @return bool
610
     */
611
    public function gettemplate($template, $block = false)
0 ignored issues
show
Unused Code introduced by
The parameter $template is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

611
    public function gettemplate(/** @scrutinizer ignore-unused */ $template, $block = false)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $block is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

611
    public function gettemplate($template, /** @scrutinizer ignore-unused */ $block = false)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
612
    {
613
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
614
615
        return false;
616
    }
617
618
    /**
619
     * @return bool
620
     */
621
    public function insertBlocks()
622
    {
623
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
624
625
        return false;
626
    }
627
628
    /**
629
     * @return bool
630
     */
631
    public function insertConfigCategories()
632
    {
633
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
634
635
        return false;
636
    }
637
638
    /**
639
     * @return bool
640
     */
641
    public function insertConfig()
642
    {
643
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
644
645
        return false;
646
    }
647
648
    /**
649
     * @return bool
650
     */
651
    public function insertProfileFields()
652
    {
653
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
654
655
        return false;
656
    }
657
658
    /**
659
     * @param     $type
660
     * @param int $state
661
     *
662
     * @return bool
663
     */
664
    public function executeScript($type, $state = 2)
0 ignored issues
show
Unused Code introduced by
The parameter $type is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

664
    public function executeScript(/** @scrutinizer ignore-unused */ $type, $state = 2)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $state is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

664
    public function executeScript($type, /** @scrutinizer ignore-unused */ $state = 2)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
665
    {
666
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
667
668
        return false;
669
    }
670
671
    /**
672
     * @param $groups
673
     * @param $type
674
     *
675
     * @return bool
676
     */
677
    public function insertGroupPermissions($groups, $type)
0 ignored issues
show
Unused Code introduced by
The parameter $groups is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

677
    public function insertGroupPermissions(/** @scrutinizer ignore-unused */ $groups, $type)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $type is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

677
    public function insertGroupPermissions($groups, /** @scrutinizer ignore-unused */ $type)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
678
    {
679
        $GLOBALS['xoopsLogger']->addDeprecated(__METHOD__ . ' is deprecated');
680
681
        return false;
682
    }
683
    /**#@-*/
684
}
685
686
/**
687
 * XOOPS module handler class.
688
 *
689
 * This class is responsible for providing data access mechanisms to the data source
690
 * of XOOPS module class objects.
691
 *
692
 * @package       kernel
693
 * @author        Kazumi Ono <[email protected]>
694
 * @copyright (c) 2000-2016 XOOPS Project - www.xoops.org
695
 *
696
 * @todo Why is this not a XoopsPersistableObjectHandler?
697
 */
698
class XoopsModuleHandler extends XoopsObjectHandler
699
{
700
    /**
701
     * holds an array of cached module references, indexed by module id
702
     *
703
     * @var array
704
     * @access private
705
     */
706
    public $_cachedModule_mid = [];
707
708
    /**
709
     * holds an array of cached module references, indexed by module dirname
710
     *
711
     * @var array
712
     * @access private
713
     */
714
    public $_cachedModule_dirname = [];
715
716
    /**
717
     * Create a new {@link XoopsModule} object
718
     *
719
     * @param  boolean $isNew Flag the new object as "new"
720
     * @return XoopsModule
721
     */
722
    public function create($isNew = true)
723
    {
724
        $module = new XoopsModule();
725
        if ($isNew) {
726
            $module->setNew();
727
        }
728
729
        return $module;
730
    }
731
732
    /**
733
     * Load a module from the database
734
     *
735
     * @param  int $id ID of the module
736
     * @return XoopsObject|false false on fail
737
     */
738
    public function get($id)
739
    {
740
        static $_cachedModule_dirname;
741
        static $_cachedModule_mid;
742
        $id     = (int) $id;
743
        $module = false;
744
        if ($id > 0) {
745
            if (!empty($_cachedModule_mid[$id])) {
746
                return $_cachedModule_mid[$id];
747
            } else {
748
                $sql = 'SELECT * FROM ' . $this->db->prefix('modules') . ' WHERE mid = ' . $id;
749
                $result = $this->db->query($sql);
0 ignored issues
show
Bug introduced by
The method query() does not exist on XoopsDatabase. Since it exists in all sub-types, consider adding an abstract or default implementation to XoopsDatabase. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

749
                /** @scrutinizer ignore-call */ 
750
                $result = $this->db->query($sql);
Loading history...
750
                if (!$this->db->isResultSet($result)) {
751
                    return $module;
752
                }
753
                $numrows = $this->db->getRowsNum($result);
0 ignored issues
show
Bug introduced by
The method getRowsNum() does not exist on XoopsDatabase. Since it exists in all sub-types, consider adding an abstract or default implementation to XoopsDatabase. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

753
                /** @scrutinizer ignore-call */ 
754
                $numrows = $this->db->getRowsNum($result);
Loading history...
754
                if ($numrows == 1) {
755
                    $module = new XoopsModule();
756
                    $myrow  = $this->db->fetchArray($result);
0 ignored issues
show
Bug introduced by
The method fetchArray() does not exist on XoopsDatabase. Since it exists in all sub-types, consider adding an abstract or default implementation to XoopsDatabase. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

756
                    /** @scrutinizer ignore-call */ 
757
                    $myrow  = $this->db->fetchArray($result);
Loading history...
757
                    $module->assignVars($myrow);
758
                    $_cachedModule_mid[$id]                            = &$module;
759
                    $_cachedModule_dirname[$module->getVar('dirname')] = &$module;
760
761
                    return $module;
762
                }
763
            }
764
        }
765
766
        return $module;
767
    }
768
769
    /**
770
     * Load a module by its dirname
771
     *
772
     * @param  string $dirname
773
     * @return XoopsModule|FALSE on fail
774
     */
775
    public function getByDirname($dirname)
776
    {
777
        $dirname = basename($dirname);
778
        // Sanitize $dirname to prevent SQL injection
779
        $dirname = $this->db->escape(trim($dirname));
0 ignored issues
show
Bug introduced by
The method escape() does not exist on XoopsDatabase. Since it exists in all sub-types, consider adding an abstract or default implementation to XoopsDatabase. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

779
        /** @scrutinizer ignore-call */ 
780
        $dirname = $this->db->escape(trim($dirname));
Loading history...
780
781
        //could not we check for spaces instead??
782
        if (strpos(strtolower($dirname), ' union ')) {
783
            return false;
784
        }
785
        static $_cachedModule_mid;
786
        static $_cachedModule_dirname;
787
        if (!empty($_cachedModule_dirname[$dirname])) {
788
            return $_cachedModule_dirname[$dirname];
789
        } else {
790
            $module = false;
791
            $sql    = 'SELECT * FROM ' . $this->db->prefix('modules') . ' WHERE dirname = ?';
792
            $stmt   = $this->db->conn->prepare($sql);
793
            $stmt->bind_param('s', $dirname);
794
            $success = $stmt->execute();
795
            if (!$success) {
796
                return $module;
797
            }
798
            $result = $stmt->get_result();
799
800
            if (!$this->db->isResultSet($result)) {
801
                return $module;
802
            }
803
            $numrows = $this->db->getRowsNum($result);
804
            if ($numrows == 1) {
805
                $module = new XoopsModule();
806
                $myrow  = $this->db->fetchArray($result);
807
                $module->assignVars($myrow);
808
                $_cachedModule_dirname[$dirname]           = & $module;
809
                $_cachedModule_mid[$module->getVar('mid')] = & $module;
810
            }
811
812
            return $module;
813
        }
814
    }
815
816
    /**
817
     * Write a module to the database
818
     *
819
     * @param  XoopsObject|XoopsModule $module a XoopsModule object
820
     *
821
     * @return bool true on success, otherwise false
822
     */
823
    public function insert(XoopsObject $module)
824
    {
825
        $className = 'XoopsModule';
826
        if (!($module instanceof $className)) {
827
            return false;
828
        }
829
        if (!$module->isDirty()) {
830
            return true;
831
        }
832
        if (!$module->cleanVars()) {
833
            return false;
834
        }
835
        foreach ($module->cleanVars as $k => $v) {
836
            ${$k} = $v;
837
        }
838
        if ($module->isNew()) {
839
            $mid = $this->db->genId('modules_mid_seq');
0 ignored issues
show
Bug introduced by
The method genId() does not exist on XoopsDatabase. Since it exists in all sub-types, consider adding an abstract or default implementation to XoopsDatabase. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

839
            /** @scrutinizer ignore-call */ 
840
            $mid = $this->db->genId('modules_mid_seq');
Loading history...
840
            $sql = sprintf('INSERT INTO %s (mid, name, version, last_update, weight, isactive, dirname, hasmain, hasadmin, hassearch, hasconfig, hascomments, hasnotification) VALUES (%u, %s, %s, %u, %u, %u, %s, %u, %u, %u, %u, %u, %u)', $this->db->prefix('modules'), $mid, $this->db->quoteString($name), $this->db->quoteString($version), time(), $weight, 1, $this->db->quoteString($dirname), $hasmain, $hasadmin, $hassearch, $hasconfig, $hascomments, $hasnotification);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $hasmain seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $dirname seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $weight seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $hasconfig seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $hascomments seems to be never defined.
Loading history...
Bug introduced by
The method quoteString() does not exist on XoopsDatabase. Since it exists in all sub-types, consider adding an abstract or default implementation to XoopsDatabase. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

840
            $sql = sprintf('INSERT INTO %s (mid, name, version, last_update, weight, isactive, dirname, hasmain, hasadmin, hassearch, hasconfig, hascomments, hasnotification) VALUES (%u, %s, %s, %u, %u, %u, %s, %u, %u, %u, %u, %u, %u)', $this->db->prefix('modules'), $mid, $this->db->/** @scrutinizer ignore-call */ quoteString($name), $this->db->quoteString($version), time(), $weight, 1, $this->db->quoteString($dirname), $hasmain, $hasadmin, $hassearch, $hasconfig, $hascomments, $hasnotification);
Loading history...
Comprehensibility Best Practice introduced by
The variable $hasadmin seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $hasnotification seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $hassearch seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $version seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $name seems to be never defined.
Loading history...
841
        } else {
842
            $sql = sprintf('UPDATE %s SET name = %s, dirname = %s, version = %s, last_update = %u, weight = %u, isactive = %u, hasmain = %u, hasadmin = %u, hassearch = %u, hasconfig = %u, hascomments = %u, hasnotification = %u WHERE mid = %u', $this->db->prefix('modules'), $this->db->quoteString($name), $this->db->quoteString($dirname), $this->db->quoteString($version), time(), $weight, $isactive, $hasmain, $hasadmin, $hassearch, $hasconfig, $hascomments, $hasnotification, $mid);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $isactive seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $mid seems to be never defined.
Loading history...
843
        }
844
        if (!$result = $this->db->query($sql)) {
0 ignored issues
show
Unused Code introduced by
The assignment to $result is dead and can be removed.
Loading history...
845
            return false;
846
        }
847
        if (empty($mid)) {
848
            $mid = $this->db->getInsertId();
0 ignored issues
show
Bug introduced by
The method getInsertId() does not exist on XoopsDatabase. Since it exists in all sub-types, consider adding an abstract or default implementation to XoopsDatabase. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

848
            /** @scrutinizer ignore-call */ 
849
            $mid = $this->db->getInsertId();
Loading history...
849
        }
850
        $module->assignVar('mid', $mid);
851
        if (!empty($this->_cachedModule_dirname[$dirname])) {
852
            unset($this->_cachedModule_dirname[$dirname]);
853
        }
854
        if (!empty($this->_cachedModule_mid[$mid])) {
855
            unset($this->_cachedModule_mid[$mid]);
856
        }
857
858
        return true;
859
    }
860
861
    /**
862
     * Delete a module from the database
863
     *
864
     * @param  XoopsObject|XoopsModule $module a XoopsModule object
865
     *
866
     * @return bool true on success, otherwise false
867
     */
868
    public function delete(XoopsObject $module)
869
    {
870
        $className = 'XoopsModule';
871
        if (!($module instanceof $className)) {
872
            return false;
873
        }
874
        $sql = sprintf('DELETE FROM %s WHERE mid = %u', $this->db->prefix('modules'), $module->getVar('mid'));
0 ignored issues
show
Bug introduced by
It seems like $module->getVar('mid') can also be of type array and array; however, parameter $values of sprintf() does only seem to accept double|integer|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

874
        $sql = sprintf('DELETE FROM %s WHERE mid = %u', $this->db->prefix('modules'), /** @scrutinizer ignore-type */ $module->getVar('mid'));
Loading history...
875
        if (!$result = $this->db->query($sql)) {
0 ignored issues
show
Unused Code introduced by
The assignment to $result is dead and can be removed.
Loading history...
876
            return false;
877
        }
878
        // delete admin permissions assigned for this module
879
        $sql = sprintf("DELETE FROM %s WHERE gperm_name = 'module_admin' AND gperm_itemid = %u", $this->db->prefix('group_permission'), $module->getVar('mid'));
880
        $this->db->query($sql);
881
        // delete read permissions assigned for this module
882
        $sql = sprintf("DELETE FROM %s WHERE gperm_name = 'module_read' AND gperm_itemid = %u", $this->db->prefix('group_permission'), $module->getVar('mid'));
883
        $this->db->query($sql);
884
885
        $sql = sprintf('SELECT block_id FROM %s WHERE module_id = %u', $this->db->prefix('block_module_link'), $module->getVar('mid'));
886
        $result = $this->db->query($sql);
887
        if ($this->db->isResultSet($result)) {
888
            $block_id_arr = [];
889
            /** @var array $myrow */
890
            while (false !== ($myrow = $this->db->fetchArray($result))) {
891
                $block_id_arr[] = $myrow['block_id'];
892
            }
893
        }
894
        // loop through block_id_arr
895
        if (isset($block_id_arr)) {
896
            foreach ($block_id_arr as $i) {
897
                $sql = sprintf('SELECT block_id FROM %s WHERE module_id != %u AND block_id = %u', $this->db->prefix('block_module_link'), $module->getVar('mid'), $i);
898
                $result2 = $this->db->query($sql);
899
                if ($this->db->isResultSet($result2)) {
900
                    if (0 < $this->db->getRowsNum($result2)) {
901
                        // this block has other entries, so delete the entry for this module
902
                        $sql = sprintf('DELETE FROM %s WHERE (module_id = %u) AND (block_id = %u)', $this->db->prefix('block_module_link'), $module->getVar('mid'), $i);
903
                        $this->db->query($sql);
904
                    } else {
905
                        // this block doesn't have other entries, so disable the block and let it show on top page only. otherwise, this block will not display anymore on block admin page!
906
                        $sql = sprintf('UPDATE %s SET visible = 0 WHERE bid = %u', $this->db->prefix('newblocks'), $i);
907
                        $this->db->query($sql);
908
                        $sql = sprintf('UPDATE %s SET module_id = -1 WHERE module_id = %u', $this->db->prefix('block_module_link'), $module->getVar('mid'));
909
                        $this->db->query($sql);
910
                    }
911
                }
912
            }
913
        }
914
915
        $dirname = (string) $module->getVar('dirname');
916
        $mid = (int) $module->getVar('mid');
917
918
        if (!empty($this->_cachedModule_dirname[$dirname])) {
919
            unset($this->_cachedModule_dirname[$dirname]);
920
        }
921
        if (!empty($this->_cachedModule_mid[$mid])) {
922
            unset($this->_cachedModule_mid[$mid]);
923
        }
924
925
        return true;
926
    }
927
928
    /**
929
     * Load some modules
930
     *
931
     * @param  CriteriaElement|CriteriaCompo $criteria  {@link CriteriaElement}
932
     * @param  boolean         $id_as_key Use the ID as key into the array
933
     * @return array
934
     */
935
    public function getObjects(?CriteriaElement $criteria = null, $id_as_key = false)
936
    {
937
        if (func_num_args() > 0) {
938
            $criteria = func_get_arg(0);
939
        }
940
941
        if (version_compare(PHP_VERSION, '8.0.0', '>=')) {
942
            $criteria = $criteria ?? null;
943
        }
944
945
        if (func_num_args() > 0) {
946
            $criteria = func_get_arg(0);
947
        }
948
949
        if (version_compare(PHP_VERSION, '8.0.0', '>=')) {
950
            $criteria = $criteria ?? null; // Explicitly set to null if not provided
951
        }
952
953
        $ret   = [];
954
        $limit = $start = 0;
955
        $sql   = 'SELECT * FROM ' . $this->db->prefix('modules');
956
        if (isset($criteria) && \method_exists($criteria, 'renderWhere')) {
957
            $sql .= ' ' . $criteria->renderWhere();
958
            $sql .= ' ORDER BY weight ' . $criteria->getOrder() . ', mid ASC';
959
            $limit = $criteria->getLimit();
960
            $start = $criteria->getStart();
961
        }
962
        $result = $this->db->query($sql, $limit, $start);
963
        if (!$this->db->isResultSet($result)) {
964
            return $ret;
965
        }
966
        /** @var array $myrow */
967
        while (false !== ($myrow = $this->db->fetchArray($result))) {
968
            $module = new XoopsModule();
969
            $module->assignVars($myrow);
970
            if (!$id_as_key) {
971
                $ret[] = & $module;
972
            } else {
973
                $ret[$myrow['mid']] = & $module;
974
            }
975
            unset($module);
976
        }
977
978
        return $ret;
979
    }
980
981
    /**
982
     * Count some modules
983
     *
984
     * @param  CriteriaElement|CriteriaCompo $criteria {@link CriteriaElement}
985
     * @return int
986
     */
987
    public function getCount(?CriteriaElement $criteria = null)
988
    {
989
        if (func_num_args() > 0) {
990
            $criteria = func_get_arg(0);
991
        }
992
993
        if (version_compare(PHP_VERSION, '8.0.0', '>=')) {
994
            $criteria = $criteria ?? null;
995
        }
996
997
        $sql = 'SELECT COUNT(*) FROM ' . $this->db->prefix('modules');
998
        if (isset($criteria) && \method_exists($criteria, 'renderWhere')) {
999
            $sql .= ' ' . $criteria->renderWhere();
1000
        }
1001
        $result = $this->db->query($sql);
1002
        if (!$this->db->isResultSet($result)) {
1003
            return 0;
1004
        }
1005
        [$count] = $this->db->fetchRow($result);
0 ignored issues
show
Bug introduced by
The method fetchRow() does not exist on XoopsDatabase. Since it exists in all sub-types, consider adding an abstract or default implementation to XoopsDatabase. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1005
        /** @scrutinizer ignore-call */ 
1006
        [$count] = $this->db->fetchRow($result);
Loading history...
1006
1007
        return (int) $count;
1008
    }
1009
1010
    /**
1011
     * returns an array of module names
1012
     *
1013
     * @param  CriteriaElement $criteria
1014
     * @param  boolean         $dirname_as_key if true, array keys will be module directory names
1015
     *                                         if false, array keys will be module id
1016
     * @return array
1017
     */
1018
    public function getList(?CriteriaElement $criteria = null, $dirname_as_key = false)
1019
    {
1020
1021
        if (func_num_args() > 0) {
1022
            $criteria = func_get_arg(0);
1023
        }
1024
1025
        if (version_compare(PHP_VERSION, '8.0.0', '>=')) {
1026
            $criteria = $criteria ?? null; // Explicitly set to null if not provided
1027
        }
1028
1029
1030
        $ret     = [];
1031
        $modules = $this->getObjects($criteria, true);
1032
        foreach (array_keys($modules) as $i) {
1033
            if (!$dirname_as_key) {
1034
                $ret[$i] = $modules[$i]->getVar('name');
1035
            } else {
1036
                $ret[$modules[$i]->getVar('dirname')] = $modules[$i]->getVar('name');
1037
            }
1038
        }
1039
1040
        return $ret;
1041
    }
1042
}
1043