Completed
Branch master (1b2f30)
by Michael
06:29 queued 03:22
created

sfFaq   D

Complexity

Total Complexity 92

Size/Duplication

Total Lines 653
Duplicated Lines 16.69 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 92
c 1
b 0
f 0
lcom 1
cbo 3
dl 109
loc 653
rs 4.6538

39 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 35 3
A assignOtherProperties() 0 10 1
A checkPermission() 18 18 3
A getGroups_read() 0 8 2
A setGroups_read() 0 4 1
A faqid() 0 4 1
A categoryid() 0 4 1
A category() 0 4 1
B question() 7 17 7
A howdoi() 10 10 4
A diduno() 10 10 4
A uid() 0 4 1
A datesub() 9 9 2
A status() 0 4 1
A counter() 0 4 1
A weight() 0 4 1
A html() 0 4 1
A smiley() 0 4 1
A xcodes() 0 4 1
A cancomment() 0 4 1
A comments() 0 4 1
A notifypub() 0 4 1
A modulelink() 0 4 1
A contextpage() 0 4 1
A exacturl() 0 4 1
A partialview() 0 4 1
A posterName() 0 9 2
D answer() 0 42 9
A getAllAnswers() 0 6 1
A updateCounter() 0 6 1
A store() 0 6 1
A getCategoryName() 0 8 2
C sendNotifications() 28 87 11
A setDefaultPermissions() 13 13 2
A setPermissions() 14 14 3
A notLoaded() 0 4 1
B getWhoAndWhen() 0 24 5
A getComeFrom() 0 10 3
C toArray() 0 33 7

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like sfFaq 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 sfFaq, and based on these observations, apply Extract Interface, too.

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 14 and the first side effect is on line 11.

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
/**
4
 * Module: SmartFAQ
5
 * Author: The SmartFactory <www.smartfactory.ca>
6
 * Licence: GNU
7
 */
8
9
// defined('XOOPS_ROOT_PATH') || exit('XOOPS root path not defined');
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
10
11
require_once XOOPS_ROOT_PATH . '/modules/smartfaq/class/category.php';
12
13
// FAQ status
14
define('_SF_STATUS_NOTSET', -1);
15
define('_SF_STATUS_ALL', 0);
16
define('_SF_STATUS_ASKED', 1);
17
define('_SF_STATUS_OPENED', 2);
18
define('_SF_STATUS_ANSWERED', 3);
19
define('_SF_STATUS_SUBMITTED', 4);
20
define('_SF_STATUS_PUBLISHED', 5);
21
define('_SF_STATUS_NEW_ANSWER', 6);
22
define('_SF_STATUS_OFFLINE', 7);
23
define('_SF_STATUS_REJECTED_QUESTION', 8);
24
define('_SF_STATUS_REJECTED_SMARTFAQ', 9);
25
26
// Notification Events
27
define('_SF_NOT_CATEGORY_CREATED', 1);
28
define('_SF_NOT_FAQ_SUBMITTED', 2);
29
define('_SF_NOT_FAQ_PUBLISHED', 3);
30
define('_SF_NOT_FAQ_REJECTED', 4);
31
define('_SF_NOT_QUESTION_SUBMITTED', 5);
32
define('_SF_NOT_QUESTION_PUBLISHED', 6);
33
define('_SF_NOT_NEW_ANSWER_PROPOSED', 7);
34
define('_SF_NOT_NEW_ANSWER_PUBLISHED', 8);
35
36
/**
37
 * Class sfFaq
38
 */
39
class sfFaq extends XoopsObject
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
40
{
41
42
    /**
43
     * @var sfCategory
44
     * @access private
45
     */
46
    private $category = null;
47
48
    /**
49
     * @var sfAnswer
50
     * @access private
51
     */
52
    private $answer = null;
53
54
    /**
55
     * @var array
56
     * @access private
57
     */
58
    private $_notifications = null;
0 ignored issues
show
Unused Code introduced by
The property $_notifications is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
59
    // TODO : Create a seperated class for notifications
60
61
    /**
62
     * @var array
63
     * @access private
64
     */
65
    private $groups_read = null;
66
67
    /**
68
     * @var object
69
     * @access private
70
     */
71
    // Is this still usefull??
72
    private $_smartModule = null;
0 ignored issues
show
Unused Code introduced by
The property $_smartModule is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
73
    private $_smartModuleConfig;
0 ignored issues
show
Unused Code introduced by
The property $_smartModuleConfig is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
74
75
    /**
76
     * constructor
77
     * @param null $id
78
     */
79
    public function __construct($id = null)
80
    {
81
        $this->db = XoopsDatabaseFactory::getDatabaseConnection();
82
        $this->initVar('faqid', XOBJ_DTYPE_INT, -1, false);
83
        $this->initVar('categoryid', XOBJ_DTYPE_INT, 0, false);
84
        $this->initVar('question', XOBJ_DTYPE_TXTBOX, null, true, 100000);
85
        $this->initVar('howdoi', XOBJ_DTYPE_TXTBOX, null, false, 255);
86
        $this->initVar('diduno', XOBJ_DTYPE_TXTBOX, null, false, 255);
87
        $this->initVar('uid', XOBJ_DTYPE_INT, 0, false);
88
        $this->initVar('datesub', XOBJ_DTYPE_INT, null, false);
89
        $this->initVar('status', XOBJ_DTYPE_INT, -1, false);
90
        $this->initVar('counter', XOBJ_DTYPE_INT, 0, false);
91
        $this->initVar('weight', XOBJ_DTYPE_INT, 0, false);
92
        $this->initVar('html', XOBJ_DTYPE_INT, 1, false);
93
        $this->initVar('smiley', XOBJ_DTYPE_INT, 1, false);
94
        $this->initVar('image', XOBJ_DTYPE_INT, 1, false);
95
        $this->initVar('linebreak', XOBJ_DTYPE_INT, 1, false);
96
        $this->initVar('xcodes', XOBJ_DTYPE_INT, 1, false);
97
        $this->initVar('cancomment', XOBJ_DTYPE_INT, 1, false);
98
        $this->initVar('comments', XOBJ_DTYPE_INT, 0, false);
99
        $this->initVar('notifypub', XOBJ_DTYPE_INT, 1, false);
100
        $this->initVar('modulelink', XOBJ_DTYPE_TXTBOX, 'None', false, 50);
101
        $this->initVar('contextpage', XOBJ_DTYPE_TXTBOX, null, false, 255);
102
        $this->initVar('exacturl', XOBJ_DTYPE_INT, 0, false);
103
        $this->initVar('partialview', XOBJ_DTYPE_INT, 0, false);
104
105
        if (isset($id)) {
106
            $faqHandler = new sfFaqHandler($this->db);
107
            $faq        = &$faqHandler->get($id);
108
            foreach ($faq->vars as $k => $v) {
109
                $this->assignVar($k, $v['value']);
110
            }
111
            $this->assignOtherProperties();
112
        }
113
    }
114
115
    public function assignOtherProperties()
116
    {
117
        $smartModule = sf_getModuleInfo();
118
        $module_id   = $smartModule->getVar('mid');
119
120
        $gpermHandler = xoops_getHandler('groupperm');
121
122
        $this->category    = new sfCategory($this->getVar('categoryid'));
123
        $this->groups_read = $gpermHandler->getGroupIds('item_read', $this->faqid(), $module_id);
124
    }
125
126
    /**
127
     * @return bool
128
     */
129 View Code Duplication
    public function checkPermission()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
130
    {
131
        include_once XOOPS_ROOT_PATH . '/modules/smartfaq/include/functions.php';
132
133
        $userIsAdmin = sf_userIsAdmin();
134
        if ($userIsAdmin) {
135
            return true;
136
        }
137
138
        $smartPermHandler = xoops_getModuleHandler('permission', 'smartfaq');
139
140
        $faqsGranted = $smartPermHandler->getPermissions('item');
141
        if (in_array($this->categoryid(), $faqsGranted)) {
142
            $ret = true;
143
        }
144
145
        return $ret;
0 ignored issues
show
Bug introduced by
The variable $ret does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
146
    }
147
148
    /**
149
     * @return array
150
     */
151
    public function getGroups_read()
152
    {
153
        if (count($this->groups_read) < 1) {
154
            $this->assignOtherProperties();
155
        }
156
157
        return $this->groups_read;
158
    }
159
160
    /**
161
     * @param array $groups_read
162
     */
163
    public function setGroups_read($groups_read = array('0'))
164
    {
165
        $this->groups_read = $groups_read;
166
    }
167
168
    /**
169
     * @return mixed
170
     */
171
    public function faqid()
172
    {
173
        return $this->getVar('faqid');
174
    }
175
176
    /**
177
     * @return mixed
178
     */
179
    public function categoryid()
180
    {
181
        return $this->getVar('categoryid');
182
    }
183
184
    /**
185
     * @return sfCategory
186
     */
187
    public function category()
188
    {
189
        return $this->category;
190
    }
191
192
    /**
193
     * @param  int    $maxLength
194
     * @param  string $format
195
     * @return mixed|string
196
     */
197
    public function question($maxLength = 0, $format = 'S')
198
    {
199
        $ret = $this->getVar('question', $format);
200
        if (($format === 's') || ($format === 'S') || ($format === 'show')) {
201
            $myts = MyTextSanitizer:: getInstance();
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces after double colon; 1 found

This check looks for references to static members where there are spaces between the name of the type and the actual member.

An example:

Certificate:: TRIPLEDES_CBC

will actually work, but is not very readable.

Loading history...
202
            $ret  = $myts->displayTarea($ret);
203
        }
204 View Code Duplication
        if ($maxLength != 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
205
            if (!XOOPS_USE_MULTIBYTES) {
206
                if (strlen($ret) >= $maxLength) {
207
                    $ret = substr($ret, 0, $maxLength - 1) . '...';
208
                }
209
            }
210
        }
211
212
        return $ret;
213
    }
214
215
    /**
216
     * @param  string $format
217
     * @return mixed
218
     */
219 View Code Duplication
    public function howdoi($format = 'S')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
220
    {
221
        $ret = $this->getVar('howdoi', $format);
222
        if (($format === 's') || ($format === 'S') || ($format === 'show')) {
223
            $myts = MyTextSanitizer:: getInstance();
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces after double colon; 1 found

This check looks for references to static members where there are spaces between the name of the type and the actual member.

An example:

Certificate:: TRIPLEDES_CBC

will actually work, but is not very readable.

Loading history...
224
            $ret  = $myts->displayTarea($ret);
225
        }
226
227
        return $ret;
228
    }
229
230
    /**
231
     * @param  string $format
232
     * @return mixed
233
     */
234 View Code Duplication
    public function diduno($format = 'S')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
235
    {
236
        $ret = $this->getVar('diduno', $format);
237
        if (($format === 's') || ($format === 'S') || ($format === 'show')) {
238
            $myts = MyTextSanitizer:: getInstance();
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces after double colon; 1 found

This check looks for references to static members where there are spaces between the name of the type and the actual member.

An example:

Certificate:: TRIPLEDES_CBC

will actually work, but is not very readable.

Loading history...
239
            $ret  = $myts->displayTarea($ret);
240
        }
241
242
        return $ret;
243
    }
244
245
    /**
246
     * @return mixed
247
     */
248
    public function uid()
249
    {
250
        return $this->getVar('uid');
251
    }
252
253
    /**
254
     * @param  string $dateFormat
255
     * @param  string $format
256
     * @return string
257
     */
258 View Code Duplication
    public function datesub($dateFormat = 'none', $format = 'S')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
259
    {
260
        if ($dateFormat === 'none') {
261
            $smartConfig = sf_getModuleConfig();
262
            $dateFormat  = $smartConfig['dateformat'];
263
        }
264
265
        return formatTimestamp($this->getVar('datesub', $format), $dateFormat);
266
    }
267
268
    /**
269
     * @return mixed
270
     */
271
    public function status()
272
    {
273
        return $this->getVar('status');
274
    }
275
276
    /**
277
     * @return mixed
278
     */
279
    public function counter()
280
    {
281
        return $this->getVar('counter');
282
    }
283
284
    /**
285
     * @return mixed
286
     */
287
    public function weight()
288
    {
289
        return $this->getVar('weight');
290
    }
291
292
    /**
293
     * @return mixed
294
     */
295
    public function html()
296
    {
297
        return $this->getVar('html');
298
    }
299
300
    /**
301
     * @return mixed
302
     */
303
    public function smiley()
304
    {
305
        return $this->getVar('smiley');
306
    }
307
308
    /**
309
     * @return mixed
310
     */
311
    public function xcodes()
312
    {
313
        return $this->getVar('xcodes');
314
    }
315
316
    /**
317
     * @return mixed
318
     */
319
    public function cancomment()
320
    {
321
        return $this->getVar('cancomment');
322
    }
323
324
    /**
325
     * @return mixed
326
     */
327
    public function comments()
328
    {
329
        return $this->getVar('comments');
330
    }
331
332
    /**
333
     * @return mixed
334
     */
335
    public function notifypub()
336
    {
337
        return $this->getVar('notifypub');
338
    }
339
340
    /**
341
     * @param  string $format
342
     * @return mixed
343
     */
344
    public function modulelink($format = 'S')
345
    {
346
        return $this->getVar('modulelink', $format);
347
    }
348
349
    /**
350
     * @param  string $format
351
     * @return mixed
352
     */
353
    public function contextpage($format = 'S')
354
    {
355
        return $this->getVar('contextpage', $format);
356
    }
357
358
    /**
359
     * @return mixed
360
     */
361
    public function exacturl()
362
    {
363
        return $this->getVar('exacturl');
364
    }
365
366
    /**
367
     * @return mixed
368
     */
369
    public function partialview()
370
    {
371
        return $this->getVar('partialview');
372
    }
373
374
    /**
375
     * @param  int $realName
376
     * @return string
377
     */
378
    public function posterName($realName = -1)
379
    {
380
        if ($realName == -1) {
381
            $smartConfig = sf_getModuleConfig();
382
            $realName    = $smartConfig['userealname'];
383
        }
384
385
        return sf_getLinkedUnameFromId($this->uid(), $realName);
386
    }
387
388
    /**
389
     * @return mixed|object|sfAnswer
390
     */
391
    public function answer()
392
    {
393
        $answerHandler = new sfAnswerHandler($this->db);
394
        switch ($this->status()) {
395
            case _SF_STATUS_SUBMITTED:
396
                $theAnswers = $answerHandler->getAllAnswers($this->faqid(), _SF_AN_STATUS_APPROVED, 1, 0);
397
                //echo "test";
398
                //exit;
399
                $this->answer = &$theAnswers[0];
400
                break;
401
402
            case _SF_STATUS_ANSWERED:
403
                $theAnswers = $answerHandler->getAllAnswers($this->faqid(), _SF_AN_STATUS_PROPOSED, 1, 0);
404
                //echo "test";
405
                //exit;
406
                $this->answer = &$theAnswers[0];
407
                break;
408
409
            case _SF_STATUS_PUBLISHED:
410
            case _SF_STATUS_NEW_ANSWER:
411
            case _SF_STATUS_OFFLINE:
412
                $this->answer = $answerHandler->getOfficialAnswer($this->faqid());
413
                break;
414
415
            case _SF_STATUS_ASKED:
416
                $this->answer = $answerHandler->create();
417
                break;
418
            case _SF_STATUS_OPENED:
419
                $this->answer = $answerHandler->create();
420
                break;
421
        }
422
423
        if ($this->answer) {
424
            $this->answer->setVar('dohtml', $this->getVar('html'));
425
            $this->answer->setVar('doxcode', $this->getVar('xcodes'));
426
            $this->answer->setVar('dosmiley', $this->getVar('smiley'));
427
            $this->answer->setVar('doimage', $this->getVar('image'));
428
            $this->answer->setVar('dobr', $this->getVar('linebreak'));
429
        }
430
431
        return $this->answer;
432
    }
433
434
    /**
435
     * @return array
436
     */
437
    public function getAllAnswers()
438
    {
439
        $answerHandler = new sfAnswerHandler($this->db);
440
441
        return $answerHandler->getAllAnswers($this->faqid());
442
    }
443
444
    /**
445
     * @return bool
446
     */
447
    public function updateCounter()
448
    {
449
        $faqHandler = new sfFaqHandler($this->db);
450
451
        return $faqHandler->updateCounter($this->faqid());
452
    }
453
454
    /**
455
     * @param  bool $force
456
     * @return bool
457
     */
458
    public function store($force = true)
459
    {
460
        $faqHandler = new sfFaqHandler($this->db);
461
462
        return $faqHandler->insert($this, $force);
463
    }
464
465
    /**
466
     * @return mixed
467
     */
468
    public function getCategoryName()
469
    {
470
        if (!isset($this->category)) {
471
            $this->category = new sfCategory($this->getVar('categoryid'));
472
        }
473
474
        return $this->category->name();
475
    }
476
477
    /**
478
     * @param array $notifications
479
     */
480
    public function sendNotifications($notifications = array())
481
    {
482
        $smartModule = sf_getModuleInfo();
483
484
        $myts                = MyTextSanitizer:: getInstance();
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces after double colon; 1 found

This check looks for references to static members where there are spaces between the name of the type and the actual member.

An example:

Certificate:: TRIPLEDES_CBC

will actually work, but is not very readable.

Loading history...
485
        $notificationHandler = xoops_getHandler('notification');
486
        //$categoryObj = $this->category();
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
487
488
        $tags                  = array();
489
        $tags['MODULE_NAME']   = $myts->displayTarea($smartModule->getVar('name'));
490
        $tags['FAQ_NAME']      = $this->question();
491
        $tags['CATEGORY_NAME'] = $this->getCategoryName();
492
        $tags['CATEGORY_URL']  = XOOPS_URL . '/modules/' . $smartModule->getVar('dirname') . '/category.php?categoryid=' . $this->categoryid();
493
        $tags['FAQ_QUESTION']  = $this->question();
494
        $answerObj             = $this->answer();
495
        if (is_object($answerObj)) {
496
            // TODO : Not sure about the 'formpreview' ...
497
            $tags['FAQ_ANSWER'] = $answerObj->answer('formpreview');
498
        }
499
        $tags['DATESUB'] = $this->datesub();
500
501
        foreach ($notifications as $notification) {
502
            switch ($notification) {
503 View Code Duplication
                case _SF_NOT_FAQ_PUBLISHED:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
504
                    $tags['FAQ_URL'] = XOOPS_URL . '/modules/' . $smartModule->getVar('dirname') . '/faq.php?faqid=' . $this->faqid();
505
506
                    $notificationHandler->triggerEvent('global_faq', 0, 'published', $tags);
507
                    $notificationHandler->triggerEvent('category_faq', $this->categoryid(), 'published', $tags);
508
                    $notificationHandler->triggerEvent('faq', $this->faqid(), 'approved', $tags);
509
                    break;
510
511 View Code Duplication
                case _SF_NOT_FAQ_SUBMITTED:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
512
                    $tags['WAITINGFILES_URL'] = XOOPS_URL . '/modules/' . $smartModule->getVar('dirname') . '/admin/faq.php?faqid=' . $this->faqid();
513
                    $notificationHandler->triggerEvent('global_faq', 0, 'submitted', $tags);
514
                    $notificationHandler->triggerEvent('category_faq', $this->categoryid(), 'submitted', $tags);
515
                    break;
516
517 View Code Duplication
                case _SF_NOT_QUESTION_PUBLISHED:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
518
                    $tags['FAQ_URL'] = XOOPS_URL . '/modules/' . $smartModule->getVar('dirname') . '/answer.php?faqid=' . $this->faqid();
519
                    $notificationHandler->triggerEvent('global_question', 0, 'published', $tags);
520
                    $notificationHandler->triggerEvent('category_question', $this->categoryid(), 'published', $tags);
521
                    $notificationHandler->triggerEvent('question', $this->faqid(), 'approved', $tags);
522
                    break;
523
524 View Code Duplication
                case _SF_NOT_QUESTION_SUBMITTED:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
525
                    $tags['WAITINGFILES_URL'] = XOOPS_URL . '/modules/' . $smartModule->getVar('dirname') . '/admin/question.php?op=mod&faqid=' . $this->faqid();
526
                    $notificationHandler->triggerEvent('global_question', 0, 'submitted', $tags);
527
                    $notificationHandler->triggerEvent('category_question', $this->categoryid(), 'submitted', $tags);
528
                    break;
529
530
                case _SF_NOT_FAQ_REJECTED:
531
                    $notificationHandler->triggerEvent('faq', $this->faqid(), 'rejected', $tags);
532
                    break;
533
534 View Code Duplication
                case _SF_NOT_NEW_ANSWER_PROPOSED:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
535
                    $tags['WAITINGFILES_URL'] = XOOPS_URL . '/modules/' . $smartModule->getVar('dirname') . '/admin/answer.php?op=mod&faqid=' . $this->faqid();
536
                    $notificationHandler->triggerEvent('global_faq', 0, 'answer_proposed', $tags);
537
                    $notificationHandler->triggerEvent('category_faq', $this->categoryid(), 'answer_proposed', $tags);
538
                    break;
539
540
                case _SF_NOT_NEW_ANSWER_PUBLISHED:
541
                    $notificationHandler->triggerEvent('global_faq', 0, 'answer_published', $tags);
542
                    $notificationHandler->triggerEvent('category_faq', $this->categoryid(), 'answer_published', $tags);
543
                    break;
544
545
                // TODO : I commented out this one because I'm not sure. The $this->faqid() should probably be the
546
                // answerid not the faqid....
547
                /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
66% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
548
                case _SF_NOT_ANSWER_APPROVED:
549
                $notificationHandler->triggerEvent('faq', $this->faqid(), 'answer_approved', $tags);
550
                break;
551
                */
552
553
                // TODO : I commented out this one because I'm not sure. The $this->faqid() should probably be the
554
                // answerid not the faqid....
555
                /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
66% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
556
                case _SF_NOT_ANSWER_REJECTED:
557
                $notificationHandler->triggerEvent('faq', $this->faqid(), 'answer_approved', $tags);
558
                break;
559
                */
560
561
                case -1:
562
                default:
563
                    break;
564
            }
565
        }
566
    }
567
568 View Code Duplication
    public function setDefaultPermissions()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
569
    {
570
        $memberHandler = xoops_getHandler('member');
571
        $groups        = $memberHandler->getGroupList();
572
573
        $j         = 0;
574
        $group_ids = array();
575
        foreach (array_keys($groups) as $i) {
576
            $group_ids[$j] = $i;
577
            ++$j;
578
        }
579
        $this->groups_read = $group_ids;
580
    }
581
582
    /**
583
     * @param $group_ids
584
     */
585 View Code Duplication
    public function setPermissions($group_ids)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
586
    {
587
        if (!isset($group_ids)) {
588
            $memberHandler = xoops_getHandler('member');
589
            $groups        = $memberHandler->getGroupList();
590
591
            $j         = 0;
592
            $group_ids = array();
593
            foreach (array_keys($groups) as $i) {
594
                $group_ids[$j] = $i;
595
                ++$j;
596
            }
597
        }
598
    }
599
600
    /**
601
     * @return bool
602
     */
603
    public function notLoaded()
604
    {
605
        return ($this->getVar('faqid') == -1);
606
    }
607
608
    /**
609
     * @param  null  $answerObj
610
     * @param  array $users
611
     * @return string
612
     */
613
    public function getWhoAndWhen($answerObj = null, $users = array())
614
    {
615
        $smartModuleConfig = sf_getModuleConfig();
616
617
        $requester   = sf_getLinkedUnameFromId($this->uid(), $smartModuleConfig['userealname'], $users);
618
        $requestdate = $this->datesub();
619
620
        if (($this->status() == _SF_STATUS_PUBLISHED) || $this->status() == _SF_STATUS_NEW_ANSWER) {
621
            if ($answerObj == null) {
622
                $answerObj = $this->answer();
623
            }
624
            $submitdate = $answerObj->datesub();
625
            if ($this->uid() == $answerObj->uid()) {
626
                $result = sprintf(_MD_SF_REQUESTEDANDANSWERED, $requester, $submitdate);
627
            } else {
628
                $submitter = sf_getLinkedUnameFromId($answerObj->uid(), $smartModuleConfig['userealname'], $users);
629
                $result    = sprintf(_MD_SF_REQUESTEDBYANDANSWEREDBY, $requester, $submitter, $submitdate);
630
            }
631
        } else {
632
            $result = sprintf(_MD_SF_REQUESTEDBY, $requester, $requestdate);
633
        }
634
635
        return $result;
636
    }
637
638
    /**
639
     * @return string
640
     */
641
    public function getComeFrom()
642
    {
643
        global $xoopsConfig;
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...
644
        $text = _MD_SF_QUESTIONCOMEFROM;
645
        if (($this->status() == _SF_STATUS_PUBLISHED) || $this->status() == _SF_STATUS_NEW_ANSWER) {
646
            $text = _MD_SF_FAQCOMEFROM;
647
        }
648
649
        return $text . $xoopsConfig['sitename'] . ' : <a href=' . XOOPS_URL . '/modules/smartfaq/faq.php?faqid=' . $this->faqid() . '>' . XOOPS_URL . '/modules/smartfaq/faq.php?faqid=' . $this->faqid() . '</a>';
650
    }
651
652
    /**
653
     * @param  array $faq
654
     * @param  null  $category
655
     * @param  bool  $linkInQuestion
656
     * @return array
657
     */
658
    public function toArray($faq = array(), $category = null, $linkInQuestion = true)
659
    {
660
        global $xoopsModuleConfig;
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
        $lastfaqsize = (int)$xoopsModuleConfig['lastfaqsize'];
662
663
        $faq['id']         = $this->faqid();
664
        $faq['categoryid'] = $this->categoryid();
665
        $faq['question']   = $this->question();
666
        $page              = ($this->status() == _SF_STATUS_OPENED) ? 'answer.php' : 'faq.php';
667
668
        $faq['questionlink'] = "<a href='$page?faqid=" . $this->faqid() . "'>" . $this->question($lastfaqsize) . '</a>';
669
        if ($linkInQuestion) {
670
            $faq['fullquestionlink'] = "<a href='$page?faqid=" . $this->faqid() . "'>" . $this->question() . '</a>';
671
        } else {
672
            $faq['fullquestionlink'] = $this->question();
673
        }
674
        $faq['faqid']      = $this->faqid();
675
        $faq['counter']    = $this->counter();
676
        $faq['cancomment'] = $this->cancomment();
677
        $faq['comments']   = $this->comments();
678
        $faq['datesub']    = $this->datesub();
679
        if (isset($category)) {
680
            if (is_object($category) && strtolower(get_class($category)) === 'sfcategory') {
681
                $categoryObj = $category;
682
            } elseif (is_array($category)) {
683
                $categoryObj = $category[$this->categoryid()];
684
            }
685
            $faq['categoryname'] = $categoryObj->getVar('name');
0 ignored issues
show
Bug introduced by
The variable $categoryObj does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
686
            $faq['categorylink'] = "<a href='" . XOOPS_URL . '/modules/smartfaq/category.php?categoryid=' . $this->categoryid() . "'>" . $categoryObj->getVar('name') . '</a>';
687
        }
688
689
        return $faq;
690
    }
691
}
692
693
/**
694
 * Q&A handler class.
695
 * This class is responsible for providing data access mechanisms to the data source
696
 * of Q&A class objects.
697
 *
698
 * @author  marcan <[email protected]>
699
 * @package SmartFAQ
700
 */
701
class sfFaqHandler 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...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
702
{
703
    /**
704
     * @param  bool $isNew
705
     * @return sfFaq
706
     */
707
    public function & create($isNew = true)
708
    {
709
        $faq = new sfFaq();
710
        if ($isNew) {
711
            $faq->setDefaultPermissions();
712
            $faq->setNew();
713
        }
714
715
        return $faq;
716
    }
717
718
    /**
719
     * retrieve an FAQ
720
     *
721
     * @param  int $id faqid of the user
722
     * @return mixed reference to the {@link sfFaq} object, FALSE if failed
723
     */
724 View Code Duplication
    public function & get($id)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
725
    {
726
        if ((int)$id > 0) {
727
            $sql = 'SELECT * FROM ' . $this->db->prefix('smartfaq_faq') . ' WHERE faqid=' . $id;
728
            if (!$result = $this->db->query($sql)) {
729
                return false;
730
            }
731
732
            $numrows = $this->db->getRowsNum($result);
733
            if ($numrows == 1) {
734
                $faq = new sfFaq();
735
                $faq->assignVars($this->db->fetchArray($result));
736
737
                return $faq;
738
            }
739
        }
740
741
        return false;
742
    }
743
744
    /**
745
     * insert a new faq in the database
746
     *
747
     * @param  XoopsObject $faq reference to the {@link sfFaq} object
748
     * @param  bool        $force
749
     * @return bool        FALSE if failed, TRUE if already present and unchanged or successful
750
     */
751
    public function insert(XoopsObject $faq, $force = false)
752
    {
753
        if (strtolower(get_class($faq)) !== 'sffaq') {
754
            return false;
755
        }
756
757
        if (!$faq->isDirty()) {
758
            return true;
759
        }
760
761
        if (!$faq->cleanVars()) {
762
            return false;
763
        }
764
765
        foreach ($faq->cleanVars as $k => $v) {
766
            ${$k} = $v;
767
        }
768
769
        if ($faq->isNew()) {
770
            $sql = sprintf('INSERT INTO %s (faqid, categoryid, question, howdoi, diduno, uid, datesub, `status`, counter, weight, html, smiley, xcodes, cancomment, comments, notifypub, modulelink, contextpage, exacturl, partialview) VALUES (NULL, %u, %s, %s, %s, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %s, %s, %u, %u)', $this->db->prefix('smartfaq_faq'), $categoryid, $this->db->quoteString($question), $this->db->quoteString($howdoi), $this->db->quoteString($diduno), $uid, time(), $status, $counter, $weight, $html, $smiley, $xcodes, $cancomment, $comments, $notifypub, $this->db->quoteString($modulelink), $this->db->quoteString($contextpage), $exacturl, $partialview);
0 ignored issues
show
Bug introduced by
The variable $categoryid 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 $question 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 $howdoi 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 $diduno 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 $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 $status 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 $counter 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 $weight 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 $html 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 $smiley 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 $xcodes 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 $cancomment 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 $comments 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 $notifypub 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 $modulelink 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 $contextpage 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 $exacturl 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 $partialview 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...
771
        } else {
772
            $sql = sprintf('UPDATE %s SET categoryid = %u, question = %s, howdoi = %s, diduno = %s, uid = %u, datesub = %u, `status` = %u, counter = %u, weight = %u, html = %u, smiley = %u, xcodes = %u, cancomment = %u, comments = %u, notifypub = %u, modulelink = %s, contextpage = %s, exacturl = %u, partialview = %u  WHERE faqid = %u', $this->db->prefix('smartfaq_faq'), $categoryid, $this->db->quoteString($question), $this->db->quoteString($howdoi), $this->db->quoteString($diduno), $uid, $datesub, $status, $counter, $weight, $html, $smiley, $xcodes, $cancomment, $comments, $notifypub, $this->db->quoteString($modulelink), $this->db->quoteString($contextpage), $exacturl, $partialview, $faqid);
0 ignored issues
show
Bug introduced by
The variable $datesub 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 $faqid 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...
773
        }
774 View Code Duplication
        if (false != $force) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison !== instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
775
            $result = $this->db->queryF($sql);
776
        } else {
777
            $result = $this->db->query($sql);
778
        }
779
780
        if (!$result) {
781
            return false;
782
        }
783
        if ($faq->isNew()) {
784
            $faq->assignVar('faqid', $this->db->getInsertId());
785
        }
786
787
        // Saving permissions
788
        sf_saveItemPermissions($faq->getGroups_read(), $faq->faqid());
789
790
        return true;
791
    }
792
793
    /**
794
     * delete an FAQ from the database
795
     *
796
     * @param  XoopsObject $faq reference to the FAQ to delete
797
     * @param  bool        $force
798
     * @return bool        FALSE if failed.
799
     */
800
    public function delete(XoopsObject $faq, $force = false)
801
    {
802
        $smartModule = sf_getModuleInfo();
803
        $module_id   = $smartModule->getVar('mid');
804
805
        if (strtolower(get_class($faq)) !== 'sffaq') {
806
            return false;
807
        }
808
809
        // Deleting the answers
810
        $answerHandler = new sfAnswerHandler($this->db);
811
        if (!$answerHandler->deleteFaqAnswers($faq)) {
812
            // error msg...
813
            echo 'error while deleteing an answer';
814
        }
815
816
        $sql = sprintf('DELETE FROM %s WHERE faqid = %u', $this->db->prefix('smartfaq_faq'), $faq->getVar('faqid'));
817
818 View Code Duplication
        if (false != $force) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison !== instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
819
            $result = $this->db->queryF($sql);
820
        } else {
821
            $result = $this->db->query($sql);
822
        }
823
        if (!$result) {
824
            return false;
825
        }
826
827
        xoops_groupperm_deletebymoditem($module_id, 'item_read', $faq->faqid());
828
829
        return true;
830
    }
831
832
    /**
833
     * retrieve FAQs from the database
834
     *
835
     * @param  object $criteria  {@link CriteriaElement} conditions to be met
0 ignored issues
show
Documentation introduced by
Should the type for parameter $criteria not be object|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
836
     * @param  bool   $id_as_key use the faqid as key for the array?
837
     * @param  string $notNullFields
838
     * @return array  array of <a href='psi_element://sfFaq'>sfFaq</a> objects
0 ignored issues
show
Documentation introduced by
Should the return type not be false|array?

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...
839
     */
840
    public function &getObjects($criteria = null, $id_as_key = false, $notNullFields = '')
841
    {
842
        $ret   = array();
843
        $limit = $start = 0;
844
        $sql   = 'SELECT * FROM ' . $this->db->prefix('smartfaq_faq');
845
846 View Code Duplication
        if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of returns inconsistent results on some PHP versions for interfaces; you could instead use ReflectionClass::implementsInterface.
Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
847
            $whereClause = $criteria->renderWhere();
848
849
            if ($whereClause !== 'WHERE ()') {
850
                $sql .= ' ' . $criteria->renderWhere();
851
                if (!empty($notNullFields)) {
852
                    $sql .= $this->NotNullFieldClause($notNullFields, true);
853
                }
854
            } elseif (!empty($notNullFields)) {
855
                $sql .= ' WHERE ' . $this->NotNullFieldClause($notNullFields);
856
            }
857
            if ($criteria->getSort() != '') {
858
                $sql .= ' ORDER BY ' . $criteria->getSort() . ' ' . $criteria->getOrder();
859
            }
860
            $limit = $criteria->getLimit();
861
            $start = $criteria->getStart();
862
        } elseif (!empty($notNullFields)) {
863
            $sql .= $sql .= ' WHERE ' . $this->NotNullFieldClause($notNullFields);
864
        }
865
866
        //echo "<br />" . $sql . "<br />";
0 ignored issues
show
Unused Code Comprehensibility introduced by
42% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
867
        $result = $this->db->query($sql, $limit, $start);
868
        if (!$result) {
869
            return false;
870
        }
871
872
        if (count($result) == 0) {
873
            return false;
874
        }
875
876 View Code Duplication
        while ($myrow = $this->db->fetchArray($result)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
877
            $faq = new sfFaq();
878
            $faq->assignVars($myrow);
879
880
            if (!$id_as_key) {
881
                $ret[] = &$faq;
882
            } else {
883
                $ret[$myrow['faqid']] = &$faq;
884
            }
885
            unset($faq);
886
        }
887
888
        return $ret;
889
    }
890
891
    /**
892
     * @param  null   $criteria
893
     * @param  bool   $id_as_key
894
     * @param  string $notNullFields
895
     * @return array|bool
896
     */
897
    public function &getObjectsAdminSide($criteria = null, $id_as_key = false, $notNullFields = '')
898
    {
899
        $ret   = array();
900
        $limit = $start = 0;
901
        $sql   = 'SELECT
902
                            faq.faqid AS faqid,
903
                            faq.categoryid AS categoryid,
904
                            faq.question AS question,
905
                            faq.howdoi AS howdoi,
906
                            faq.diduno AS diduno,
907
                            faq.uid AS uid,
908
                            faq.datesub AS datesub,
909
                            faq.status AS status,
910
                            faq.counter AS counter,
911
                            faq.weight AS weight,
912
                            faq.html AS html,
913
                            faq.smiley AS smiley,
914
                            faq.image AS image,
915
                            faq.linebreak AS linebreak,
916
                            faq.xcodes AS xcodes,
917
                            faq.cancomment AS cancomment,
918
                            faq.comments AS comments,
919
                            faq.notifypub AS notifypub,
920
                            faq.modulelink AS modulelink,
921
                            faq.contextpage AS contextpage,
922
                            faq.exacturl AS exacturl
923
                FROM ' . $this->db->prefix('smartfaq_faq') . ' AS faq INNER JOIN ' . $this->db->prefix('smartfaq_categories') . ' AS category ON faq.categoryid = category.categoryid ';
924
925 View Code Duplication
        if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of returns inconsistent results on some PHP versions for interfaces; you could instead use ReflectionClass::implementsInterface.
Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
926
            $whereClause = $criteria->renderWhere();
927
928
            if ($whereClause !== 'WHERE ()') {
929
                $sql .= ' ' . $criteria->renderWhere();
930
                if (!empty($notNullFields)) {
931
                    $sql .= $this->NotNullFieldClause($notNullFields, true);
932
                }
933
            } elseif (!empty($notNullFields)) {
934
                $sql .= ' WHERE ' . $this->NotNullFieldClause($notNullFields);
935
            }
936
            if ($criteria->getSort() != '') {
937
                $sql .= ' ORDER BY ' . $criteria->getSort() . ' ' . $criteria->getOrder();
938
            }
939
            $limit = $criteria->getLimit();
940
            $start = $criteria->getStart();
941
        } elseif (!empty($notNullFields)) {
942
            $sql .= $sql .= ' WHERE ' . $this->NotNullFieldClause($notNullFields);
943
        }
944
945
        //echo "<br />" . $sql . "<br />";
0 ignored issues
show
Unused Code Comprehensibility introduced by
42% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
946
        $result = $this->db->query($sql, $limit, $start);
947
        if (!$result) {
948
            return false;
949
        }
950
951
        if (count($result) == 0) {
952
            return false;
953
        }
954
955 View Code Duplication
        while ($myrow = $this->db->fetchArray($result)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
956
            $faq = new sfFaq();
957
            $faq->assignVars($myrow);
958
959
            if (!$id_as_key) {
960
                $ret[] = &$faq;
961
            } else {
962
                $ret[$myrow['faqid']] = &$faq;
963
            }
964
            unset($faq);
965
        }
966
967
        return $ret;
968
969
        /*while ($myrow = $this->db->fetchArray($result)) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
970
            $faq = new sfFaq($myrow['faqid']);
971
972
            if (!$id_as_key) {
973
                $ret[] =& $faq;
974
            } else {
975
                $ret[$myrow['faqid']] =& $faq;
976
            }
977
            unset($faq);
978
        }
979
980
        return $ret;*/
981
    }
982
983
    /**
984
     * count FAQs matching a condition
985
     *
986
     * @param  object $criteria {@link CriteriaElement} to match
0 ignored issues
show
Documentation introduced by
Should the type for parameter $criteria not be object|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
987
     * @param  string $notNullFields
988
     * @return int    count of FAQs
989
     */
990
    public function getCount($criteria = null, $notNullFields = '')
991
    {
992
        $sql = 'SELECT COUNT(*) FROM ' . $this->db->prefix('smartfaq_faq');
993
        if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of returns inconsistent results on some PHP versions for interfaces; you could instead use ReflectionClass::implementsInterface.
Loading history...
994
            $whereClause = $criteria->renderWhere();
995
            if ($whereClause !== 'WHERE ()') {
996
                $sql .= ' ' . $criteria->renderWhere();
997
                if (!empty($notNullFields)) {
998
                    $sql .= $this->NotNullFieldClause($notNullFields, true);
999
                }
1000
            } elseif (!empty($notNullFields)) {
1001
                $sql .= ' WHERE ' . $this->NotNullFieldClause($notNullFields);
1002
            }
1003
        } elseif (!empty($notNullFields)) {
1004
            $sql .= ' WHERE ' . $this->NotNullFieldClause($notNullFields);
1005
        }
1006
1007
        //echo "<br />" . $sql . "<br />";
0 ignored issues
show
Unused Code Comprehensibility introduced by
42% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1008
        $result = $this->db->query($sql);
1009
        if (!$result) {
1010
            return 0;
1011
        }
1012
        list($count) = $this->db->fetchRow($result);
1013
1014
        return $count;
1015
    }
1016
1017
    /**
1018
     * @param  int    $categoryid
1019
     * @param  string $status
1020
     * @param  string $notNullFields
1021
     * @return int
1022
     */
1023
    public function getFaqsCount($categoryid = -1, $status = '', $notNullFields = '')
1024
    {
1025
        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...
1026
1027
        //  if ( ($categoryid = -1) && (empty($status) || ($status == -1)) ) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1028
        //return $this->getCount();
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1029
        //}
1030
1031
        $userIsAdmin = sf_userIsAdmin();
1032
        // Categories for which user has access
1033 View Code Duplication
        if (!$userIsAdmin) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1034
            $smartPermHandler = xoops_getModuleHandler('permission', 'smartfaq');
1035
1036
            $categoriesGranted = $smartPermHandler->getPermissions('category');
1037
            $grantedCategories = new Criteria('categoryid', '(' . implode(',', $categoriesGranted) . ')', 'IN');
1038
1039
            $faqsGranted = $smartPermHandler->getPermissions('item');
1040
            $grantedFaq  = new CriteriaCompo();
1041
            $grantedFaq->add(new Criteria('faqid', '(' . implode(',', $faqsGranted) . ')', 'IN'), 'OR');
1042
            // If user is anonymous, check if the FAQ allow partialview
1043
            if (!is_object($xoopsUser)) {
1044
                $grantedFaq->add(new Criteria('partialview', '1'), 'OR');
1045
            }
1046
        }
1047
1048
        if (isset($categoryid) && ($categoryid != -1)) {
1049
            $criteriaCategory = new criteria('categoryid', $categoryid);
1050
        }
1051
1052
        $criteriaStatus = new CriteriaCompo();
1053
        if (!empty($status) && is_array($status)) {
1054
            foreach ($status as $v) {
1055
                $criteriaStatus->add(new Criteria('status', $v), 'OR');
1056
            }
1057
        } elseif (!empty($status) && ($status != -1)) {
1058
            $criteriaStatus->add(new Criteria('status', $status), 'OR');
1059
        }
1060
1061
        $criteriaPermissions = new CriteriaCompo();
1062
        if (!$userIsAdmin) {
1063
            $criteriaPermissions->add($grantedCategories, 'AND');
0 ignored issues
show
Bug introduced by
The variable $grantedCategories does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1064
            $criteriaPermissions->add($grantedFaq, 'AND');
0 ignored issues
show
Bug introduced by
The variable $grantedFaq does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1065
        }
1066
1067
        $criteria = new CriteriaCompo();
1068
        if (!empty($criteriaCategory)) {
1069
            $criteria->add($criteriaCategory);
1070
        }
1071
1072
        if (!empty($criteriaPermissions) && (!$userIsAdmin)) {
1073
            $criteria->add($criteriaPermissions);
1074
        }
1075
1076
        if (!empty($criteriaStatus)) {
1077
            $criteria->add($criteriaStatus);
1078
        }
1079
1080
        return $this->getCount($criteria, $notNullFields);
1081
    }
1082
1083
    /**
1084
     * @return array
1085
     */
1086
    public function getFaqsCountByStatus()
1087
    {
1088
        $sql    = 'SELECT status, COUNT(*) FROM ' . $this->db->prefix('smartfaq_faq') . ' GROUP BY status';
1089
        $result = $this->db->query($sql);
1090
        if (!$result) {
1091
            return array();
1092
        }
1093
        $ret = array();
1094
        while (list($status, $count) = $this->db->fetchRow($result)) {
1095
            $ret[$status] = $count;
1096
        }
1097
1098
        return $ret;
1099
    }
1100
1101
    /**
1102
     * @param  int    $limit
1103
     * @param  int    $start
1104
     * @param  int    $categoryid
1105
     * @param  string $sort
1106
     * @param  string $order
1107
     * @param  bool   $asobject
1108
     * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be false|array?

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...
1109
     */
1110
    public function getAllPublished($limit = 0, $start = 0, $categoryid = -1, $sort = 'datesub', $order = 'DESC', $asobject = true)
1111
    {
1112
        return $this->getFaqs($limit, $start, array(_SF_STATUS_PUBLISHED, _SF_STATUS_NEW_ANSWER), $categoryid, $sort, $order, null, $asobject, null);
1113
    }
1114
1115
    /**
1116
     * @param  int    $limit
1117
     * @param  int    $start
1118
     * @param  string $status
1119
     * @param  int    $categoryid
1120
     * @param  string $sort
1121
     * @param  string $order
1122
     * @param  string $notNullFields
1123
     * @param  bool   $asobject
1124
     * @param  null   $otherCriteria
1125
     * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be false|array?

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...
1126
     */
1127
    public function getFaqs($limit = 0, $start = 0, $status = '', $categoryid = -1, $sort = 'datesub', $order = 'DESC', $notNullFields = '', $asobject = true, $otherCriteria = null)
1128
    {
1129
        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...
1130
        include_once XOOPS_ROOT_PATH . '/modules/smartfaq/include/functions.php';
1131
1132
        //if ( ($categoryid == -1) && (empty($status) || ($status == -1)) && ($limit == 0) && ($start ==0) ) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1133
        //  return $this->getObjects();
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1134
        //}
1135
        $ret         = array();
1136
        $userIsAdmin = sf_userIsAdmin();
1137
        // Categories for which user has access
1138 View Code Duplication
        if (!$userIsAdmin) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1139
            $smartPermHandler = xoops_getModuleHandler('permission', 'smartfaq');
1140
1141
            $categoriesGranted = $smartPermHandler->getPermissions('category');
1142
            $grantedCategories = new Criteria('categoryid', '(' . implode(',', $categoriesGranted) . ')', 'IN');
1143
1144
            $faqsGranted = $smartPermHandler->getPermissions('item');
1145
            $grantedFaq  = new CriteriaCompo();
1146
            $grantedFaq->add(new Criteria('faqid', '(' . implode(',', $faqsGranted) . ')', 'IN'), 'OR');
1147
            // If user is anonymous, check if the FAQ allow partialview
1148
            if (!is_object($xoopsUser)) {
1149
                $grantedFaq->add(new Criteria('partialview', '1'), 'OR');
1150
            }
1151
        }
1152
1153
        if (isset($categoryid) && ($categoryid != -1)) {
1154
            if (is_array($categoryid)) {
1155
                $criteriaCategory = new Criteria('categoryid', '(' . implode(',', $categoryid) . ')', 'IN');
1156
            } else {
1157
                $criteriaCategory = new Criteria('categoryid', (int)$categoryid);
1158
            }
1159
        }
1160
1161 View Code Duplication
        if (!empty($status) && is_array($status)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1162
            $criteriaStatus = new CriteriaCompo();
1163
            foreach ($status as $v) {
1164
                $criteriaStatus->add(new Criteria('status', $v), 'OR');
1165
            }
1166
        } elseif (!empty($status) && ($status != -1)) {
1167
            $criteriaStatus = new CriteriaCompo();
1168
            $criteriaStatus->add(new Criteria('status', $status), 'OR');
1169
        }
1170
1171
        $criteriaPermissions = new CriteriaCompo();
1172
        if (!$userIsAdmin) {
1173
            $criteriaPermissions->add($grantedCategories, 'AND');
0 ignored issues
show
Bug introduced by
The variable $grantedCategories does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1174
            $criteriaPermissions->add($grantedFaq, 'AND');
0 ignored issues
show
Bug introduced by
The variable $grantedFaq does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1175
        }
1176
1177
        $criteria = new CriteriaCompo();
1178
        if (!empty($criteriaCategory)) {
1179
            $criteria->add($criteriaCategory);
1180
        }
1181
1182
        if (!empty($criteriaPermissions) && (!$userIsAdmin)) {
1183
            $criteria->add($criteriaPermissions);
1184
        }
1185
1186
        if (!empty($criteriaStatus)) {
1187
            $criteria->add($criteriaStatus);
1188
        }
1189
1190
        if (!empty($otherCriteria)) {
1191
            $criteria->add($otherCriteria);
1192
        }
1193
1194
        $criteria->setLimit($limit);
1195
        $criteria->setStart($start);
1196
        $criteria->setSort($sort);
1197
        $criteria->setOrder($order);
1198
        $ret = &$this->getObjects($criteria, false, $notNullFields);
1199
1200
        return $ret;
1201
    }
1202
1203
    /**
1204
     * @param  int    $limit
1205
     * @param  int    $start
1206
     * @param  string $status
1207
     * @param  int    $categoryid
1208
     * @param  string $sort
1209
     * @param  string $order
1210
     * @param  bool   $asobject
1211
     * @param  null   $otherCriteria
1212
     * @return array|bool
1213
     */
1214
    public function getFaqsAdminSide($limit = 0, $start = 0, $status = '', $categoryid = -1, $sort = 'datesub', $order = 'DESC', $asobject = true, $otherCriteria = null)
1215
    {
1216
        include_once XOOPS_ROOT_PATH . '/modules/smartfaq/include/functions.php';
1217
1218
        $smartModule = sf_getModuleInfo();
0 ignored issues
show
Unused Code introduced by
$smartModule is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1219
1220
        $ret = array();
1221
1222
        if (isset($categoryid) && ($categoryid != -1)) {
1223
            $criteriaCategory = new criteria('faq.categoryid', $categoryid);
1224
        }
1225
1226 View Code Duplication
        if (!empty($status) && is_array($status)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1227
            $criteriaStatus = new CriteriaCompo();
1228
            foreach ($status as $v) {
1229
                $criteriaStatus->add(new Criteria('faq.status', $v), 'OR');
1230
            }
1231
        } elseif (!empty($status) && ($status != -1)) {
1232
            $criteriaStatus = new CriteriaCompo();
1233
            $criteriaStatus->add(new Criteria('faq.status', $status), 'OR');
1234
        }
1235
1236
        $criteria = new CriteriaCompo();
1237
        if (!empty($criteriaCategory)) {
1238
            $criteria->add($criteriaCategory);
1239
        }
1240
1241
        if (!empty($criteriaStatus)) {
1242
            $criteria->add($criteriaStatus);
1243
        }
1244
1245
        if (!empty($otherCriteria)) {
1246
            $criteria->add($otherCriteria);
1247
        }
1248
1249
        $criteria->setLimit($limit);
1250
        $criteria->setStart($start);
1251
        $criteria->setSort($sort);
1252
        $criteria->setOrder($order);
1253
        $ret = &$this->getObjectsAdminSide($criteria, false);
1254
1255
        return $ret;
1256
    }
1257
1258
    /**
1259
     * @param  string $field
1260
     * @param  string $status
1261
     * @param  int    $category
1262
     * @return bool|mixed
1263
     */
1264
    public function getRandomFaq($field = '', $status = '', $category = -1)
1265
    {
1266
        $ret = false;
1267
1268
        $notNullFields = $field;
1269
1270
        // Getting the number of published FAQ
1271
        $totalFaqs = $this->getFaqsCount(-1, $status, $notNullFields);
1272
1273
        if ($totalFaqs > 0) {
1274
            --$totalFaqs;
1275
            mt_srand((double)microtime() * 1000000);
1276
            $entrynumber = mt_rand(0, $totalFaqs);
1277
            $faq         = $this->getFaqs(1, $entrynumber, $status, -1, 'datesub', 'DESC', $notNullFields);
1278
            if ($faq) {
1279
                $ret = &$faq[0];
1280
            }
1281
        }
1282
1283
        return $ret;
1284
    }
1285
1286
    /**
1287
     * @param  int $limit
1288
     * @return array|bool
1289
     */
1290
    public function getContextualFaqs($limit = 0)
0 ignored issues
show
Coding Style introduced by
getContextualFaqs uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
1291
    {
1292
        $ret = false;
1293
1294
        $otherCriteria = new CriteriaCompo();
1295
        $otherCriteria->add(new Criteria('modulelink', 'None', '<>'));
1296
1297
        $faqsObj = $this->getFaqs(0, 0, array(_SF_STATUS_PUBLISHED, _SF_STATUS_NEW_ANSWER), -1, 'datesub', 'DESC', '', true, $otherCriteria);
1298
1299
        $totalfaqs  = count($faqsObj);
1300
        $randomFaqs = array();
1301
        if ($faqsObj) {
1302
            for ($i = 0; $i < $totalfaqs; ++$i) {
1303
                $display = false;
0 ignored issues
show
Unused Code introduced by
$display is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1304
1305
                $http        = (strpos(XOOPS_URL, 'https://') === false) ? 'http://' : 'https://';
1306
                $phpself     = $_SERVER['PHP_SELF'];
1307
                $httphost    = $_SERVER['HTTP_HOST'];
1308
                $querystring = $_SERVER['QUERY_STRING'];
1309
                if ($querystring != '') {
1310
                    $querystring = '?' . $querystring;
1311
                }
1312
                $currenturl     = $http . $httphost . $phpself . $querystring;
1313
                $fullcontexturl = XOOPS_URL . '/' . $faqsObj[$i]->contextpage();
1314
                switch ($faqsObj[$i]->modulelink()) {
1315
                    case '':
1316
                        $display = false;
1317
                        break;
1318
                    case 'None':
1319
                        $display = false;
1320
                        break;
1321
                    case 'All':
1322
                        $display = true;
1323
                        break;
1324
                    case 'url':
1325
                        if ($faqsObj[$i]->exacturl()) {
1326
                            $display = ($currenturl == $fullcontexturl);
1327
                        } else {
1328
                            $display = (strpos($currenturl, $fullcontexturl) === false);
1329
                        }
1330
                        break;
1331
                    default:
1332
                        if (strpos($currenturl, XOOPS_URL . '/modules/') === false) {
1333
                            $display = false;
1334
                        } else {
1335
                            if (strpos($currenturl, $faqsObj[$i]->modulelink()) === false) {
1336
                                $display = false;
1337
                            } else {
1338
                                $display = true;
1339
                            }
1340
                        }
1341
                        break;
1342
                }
1343
                if ($display) {
1344
                    $randomFaqs[] = &$faqsObj[$i];
1345
                }
1346
            }
1347
        }
1348
1349
        if (count($randomFaqs) > $limit) {
1350
            mt_srand((float)microtime() * 10000000);
1351
            $rand_keys = array_rand($randomFaqs, $limit);
1352
            for ($j = 0, $jMax = count($rand_keys); $j < $jMax; ++$j) {
1353
                $ret[] = &$randomFaqs[$rand_keys[$j]];
1354
            }
1355
        } else {
1356
            $ret = &$randomFaqs;
1357
        }
1358
1359
        return $ret;
1360
    }
1361
1362
    /**
1363
     * @param  array $status
1364
     * @return array
1365
     */
1366
    public function getLastPublishedByCat($status = array(_SF_STATUS_PUBLISHED, _SF_STATUS_NEW_ANSWER))
1367
    {
1368
        $ret       = array();
1369
        $faqclause = '';
1370
        if (!sf_userIsAdmin()) {
1371
            $smartPermHandler = xoops_getModuleHandler('permission', 'smartfaq');
1372
            $items            = $smartPermHandler->getPermissions('item');
1373
            $faqclause        = ' AND faqid IN (' . implode(',', $items) . ')';
1374
        }
1375
1376
        $sql  = "CREATE TEMPORARY TABLE tmp (categoryid INT(8) UNSIGNED NOT NULL,datesub int(11) DEFAULT '0' NOT NULL);";
1377
        $sql2 = ' LOCK TABLES ' . $this->db->prefix('smartfaq_faq') . ' READ;';
1378
        $sql3 = ' INSERT INTO tmp SELECT categoryid, MAX(datesub) FROM ' . $this->db->prefix('smartfaq_faq') . ' WHERE status IN (' . implode(',', $status) . ") $faqclause GROUP BY categoryid;";
1379
        $sql4 = ' SELECT ' . $this->db->prefix('smartfaq_faq') . '.categoryid, faqid, question, uid, ' . $this->db->prefix('smartfaq_faq') . '.datesub FROM ' . $this->db->prefix('smartfaq_faq') . ', tmp
1380
                              WHERE ' . $this->db->prefix('smartfaq_faq') . '.categoryid=tmp.categoryid AND ' . $this->db->prefix('smartfaq_faq') . '.datesub=tmp.datesub;';
1381
        /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
48% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1382
        //Old implementation
1383
        $sql = "SELECT categoryid, faqid, question, uid, MAX(datesub) AS datesub FROM ".$this->db->prefix("smartfaq_faq")."
1384
               WHERE status IN (". implode(',', $status).")";
1385
        $sql .= " GROUP BY categoryid";
1386
        */
1387
        $this->db->queryF($sql);
1388
        $this->db->queryF($sql2);
1389
        $this->db->queryF($sql3);
1390
        $result = $this->db->query($sql4);
1391
        $error  = $this->db->error();
1392
        $this->db->queryF('UNLOCK TABLES;');
1393
        $this->db->queryF('DROP TABLE tmp;');
1394
        if (!$result) {
1395
            trigger_error('Error in getLastPublishedByCat SQL: ' . $error);
1396
1397
            return $ret;
1398
        }
1399 View Code Duplication
        while ($row = $this->db->fetchArray($result)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1400
            $faq = new sfFaq();
1401
            $faq->assignVars($row);
1402
            $ret[$row['categoryid']] = &$faq;
1403
            unset($faq);
1404
        }
1405
1406
        return $ret;
1407
    }
1408
1409
    /**
1410
     * delete FAQs matching a set of conditions
1411
     *
1412
     * @param  object $criteria {@link CriteriaElement}
0 ignored issues
show
Documentation introduced by
Should the type for parameter $criteria not be object|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1413
     * @return bool   FALSE if deletion failed
1414
     */
1415 View Code Duplication
    public function deleteAll($criteria = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1416
    {
1417
        $sql = 'DELETE FROM ' . $this->db->prefix('smartfaq_faq');
1418
        if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of returns inconsistent results on some PHP versions for interfaces; you could instead use ReflectionClass::implementsInterface.
Loading history...
1419
            $sql .= ' ' . $criteria->renderWhere();
1420
        }
1421
        if (!$this->db->query($sql)) {
1422
            return false;
1423
            // TODO : Also delete the permissions related to each FAQ
1424
        }
1425
1426
        return true;
1427
    }
1428
1429
    /**
1430
     * Change a value for FAQ with a certain criteria
1431
     *
1432
     * @param string $fieldname  Name of the field
1433
     * @param string $fieldvalue Value to write
1434
     * @param object $criteria   {@link CriteriaElement}
0 ignored issues
show
Documentation introduced by
Should the type for parameter $criteria not be object|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1435
     *
1436
     * @return bool
1437
     **/
1438 View Code Duplication
    public function updateAll($fieldname, $fieldvalue, $criteria = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1439
    {
1440
        $set_clause = is_numeric($fieldvalue) ? $fieldname . ' = ' . $fieldvalue : $fieldname . ' = ' . $this->db->quoteString($fieldvalue);
1441
        $sql        = 'UPDATE ' . $this->db->prefix('smartfaq_faq') . ' SET ' . $set_clause;
1442
        if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of returns inconsistent results on some PHP versions for interfaces; you could instead use ReflectionClass::implementsInterface.
Loading history...
1443
            $sql .= ' ' . $criteria->renderWhere();
1444
        }
1445
        if (!$this->db->queryF($sql)) {
1446
            return false;
1447
        }
1448
1449
        return true;
1450
    }
1451
1452
    /**
1453
     * @param $faqid
1454
     * @return bool
1455
     */
1456
    public function updateCounter($faqid)
1457
    {
1458
        $sql = 'UPDATE ' . $this->db->prefix('smartfaq_faq') . ' SET counter=counter+1 WHERE faqid = ' . $faqid;
1459
        if ($this->db->queryF($sql)) {
1460
            return true;
1461
        } else {
1462
            return false;
1463
        }
1464
    }
1465
1466
    /**
1467
     * @param  string $notNullFields
1468
     * @param  bool   $withAnd
1469
     * @return string
1470
     */
1471
    public function NotNullFieldClause($notNullFields = '', $withAnd = false)
1472
    {
1473
        $ret = '';
1474
        if ($withAnd) {
1475
            $ret .= ' AND ';
1476
        }
1477
        if (!empty($notNullFields) && is_array($notNullFields)) {
1478
            foreach ($notNullFields as $v) {
1479
                $ret .= " ($v IS NOT NULL AND $v <> ' ' )";
1480
            }
1481
        } elseif (!empty($notNullFields)) {
1482
            $ret .= " ($notNullFields IS NOT NULL AND $notNullFields <> ' ' )";
1483
        }
1484
1485
        return $ret;
1486
    }
1487
1488
    /**
1489
     * @param  array  $queryarray
1490
     * @param  string $andor
1491
     * @param  int    $limit
1492
     * @param  int    $offset
1493
     * @param  int    $userid
1494
     * @return array
1495
     */
1496
    public function getFaqsFromSearch($queryarray = array(), $andor = 'AND', $limit = 0, $offset = 0, $userid = 0)
1497
    {
1498
        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...
1499
1500
        $ret = array();
1501
1502
        $userIsAdmin = sf_userIsAdmin();
1503
1504
        if ($userid != 0) {
1505
            $criteriaUser = new CriteriaCompo();
1506
            $criteriaUser->add(new Criteria('faq.uid', $userid), 'OR');
1507
            $criteriaUser->add(new Criteria('answer.uid', $userid), 'OR');
1508
        }
1509
1510
        if ($queryarray) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $queryarray of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1511
            $criteriaKeywords = new CriteriaCompo();
1512
            for ($i = 0, $iMax = count($queryarray); $i < $iMax; ++$i) {
1513
                $criteriaKeyword = new CriteriaCompo();
1514
                $criteriaKeyword->add(new Criteria('faq.question', '%' . $queryarray[$i] . '%', 'LIKE'), 'OR');
1515
                $criteriaKeyword->add(new Criteria('answer.answer', '%' . $queryarray[$i] . '%', 'LIKE'), 'OR');
1516
                $criteriaKeywords->add($criteriaKeyword, $andor);
1517
                unset($criteriaKeyword);
1518
            }
1519
        }
1520
1521
        // Categories for which user has access
1522
        if (!$userIsAdmin) {
1523
            $smartPermHandler = xoops_getModuleHandler('permission', 'smartfaq');
1524
1525
            $categoriesGranted = $smartPermHandler->getPermissions('category');
1526
            $faqsGranted       = $smartPermHandler->getPermissions('item');
1527
            if (!$categoriesGranted) {
1528
                return $ret;
1529
            }
1530
            if (!$faqsGranted) {
1531
                return $ret;
1532
            }
1533
            $grantedCategories = new Criteria('faq.categoryid', '(' . implode(',', $categoriesGranted) . ')', 'IN');
1534
            $grantedFaq        = new CriteriaCompo();
1535
            $grantedFaq->add(new Criteria('faq.faqid', '(' . implode(',', $faqsGranted) . ')', 'IN'), 'OR');
1536
            // If user is anonymous, check if the FAQ allow partialview
1537
            if (!is_object($xoopsUser)) {
1538
                $grantedFaq->add(new Criteria('partialview', '1'), 'OR');
1539
            }
1540
        }
1541
1542
        $criteriaPermissions = new CriteriaCompo();
1543
        if (!$userIsAdmin) {
1544
            $criteriaPermissions->add($grantedCategories, 'AND');
0 ignored issues
show
Bug introduced by
The variable $grantedCategories does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1545
            $criteriaPermissions->add($grantedFaq, 'AND');
0 ignored issues
show
Bug introduced by
The variable $grantedFaq does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1546
        }
1547
1548
        $criteriaAnswersStatus = new CriteriaCompo();
1549
        $criteriaAnswersStatus->add(new Criteria('answer.status', _SF_AN_STATUS_APPROVED));
1550
1551
        $criteriaFasStatus = new CriteriaCompo();
1552
        $criteriaFasStatus->add(new Criteria('faq.status', _SF_STATUS_OPENED), 'OR');
1553
        $criteriaFasStatus->add(new Criteria('faq.status', _SF_STATUS_PUBLISHED), 'OR');
1554
1555
        $criteria = new CriteriaCompo();
1556
        if (!empty($criteriaUser)) {
1557
            $criteria->add($criteriaUser, 'AND');
1558
        }
1559
1560
        if (!empty($criteriaKeywords)) {
1561
            $criteria->add($criteriaKeywords, 'AND');
1562
        }
1563
1564
        if (!empty($criteriaPermissions) && (!$userIsAdmin)) {
1565
            $criteria->add($criteriaPermissions);
1566
        }
1567
1568
        if (!empty($criteriaAnswersStatus)) {
1569
            $criteria->add($criteriaAnswersStatus, 'AND');
1570
        }
1571
1572
        if (!empty($criteriaFasStatus)) {
1573
            $criteria->add($criteriaFasStatus, 'AND');
1574
        }
1575
1576
        $criteria->setLimit($limit);
1577
        $criteria->setStart($offset);
1578
        $criteria->setSort('faq.datesub');
1579
        $criteria->setOrder('DESC');
1580
1581
        $sql = 'SELECT faq.faqid, faq.question, faq.datesub, faq.uid FROM ' . $this->db->prefix('smartfaq_faq') . ' as faq INNER JOIN ' . $this->db->prefix('smartfaq_answers') . ' as answer ON faq.faqid = answer.faqid';
1582
1583
        if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of returns inconsistent results on some PHP versions for interfaces; you could instead use ReflectionClass::implementsInterface.
Loading history...
1584
            $whereClause = $criteria->renderWhere();
1585
1586 View Code Duplication
            if ($whereClause !== 'WHERE ()') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1587
                $sql .= ' ' . $criteria->renderWhere();
1588
                if ($criteria->getSort() != '') {
1589
                    $sql .= ' ORDER BY ' . $criteria->getSort() . ' ' . $criteria->getOrder();
1590
                }
1591
                $limit = $criteria->getLimit();
1592
                $start = $criteria->getStart();
1593
            }
1594
        }
1595
1596
        //echo "<br />" . $sql . "<br />";
0 ignored issues
show
Unused Code Comprehensibility introduced by
42% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1597
1598
        $result = $this->db->query($sql, $limit, $start);
0 ignored issues
show
Bug introduced by
The variable $start does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1599
        if (!$result) {
1600
            trigger_error('Query did not work in smartfaq', E_USER_WARNING);
1601
1602
            return $ret;
1603
        }
1604
1605
        if (count($result) == 0) {
1606
            return $ret;
1607
        }
1608
1609
        while ($myrow = $this->db->fetchArray($result)) {
1610
            $faq = new sfFaq();
1611
            $faq->assignVars($myrow);
1612
            $ret[] = &$faq;
1613
            unset($faq);
1614
        }
1615
1616
        return $ret;
1617
    }
1618
1619
    /**
1620
     * @param int $cat_id
1621
     * @param     $status
1622
     * @return array
1623
     */
1624
    public function getCountsByCat($cat_id = 0, $status)
1625
    {
1626
        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...
1627
        $ret = array();
1628
        $sql = 'SELECT categoryid, COUNT(*) AS count FROM ' . $this->db->prefix('smartfaq_faq');
1629
        if ((int)$cat_id > 0) {
1630
            $sql .= ' WHERE categoryid = ' . (int)$cat_id;
1631
            $sql .= ' AND status IN (' . implode(',', $status) . ')';
1632
        } else {
1633
            $sql .= ' WHERE status IN (' . implode(',', $status) . ')';
1634
            if (!sf_userIsAdmin()) {
1635
                $smartPermHandler = xoops_getModuleHandler('permission', 'smartfaq');
1636
                $items            = $smartPermHandler->getPermissions('item');
1637
                if (is_object($xoopsUser)) {
1638
                    $sql .= ' AND faqid IN (' . implode(',', $items) . ')';
1639
                } else {
1640
                    $sql .= ' AND (faqid IN (' . implode(',', $items) . ') OR partialview = 1)';
1641
                }
1642
            }
1643
        }
1644
        $sql .= ' GROUP BY categoryid';
1645
1646
        //echo "<br />" . $sql . "<br />";
0 ignored issues
show
Unused Code Comprehensibility introduced by
42% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1647
1648
        $result = $this->db->query($sql);
1649
        if (!$result) {
1650
            return $ret;
1651
        }
1652
        while ($row = $this->db->fetchArray($result)) {
1653
            $ret[$row['categoryid']] = (int)$row['count'];
1654
        }
1655
1656
        return $ret;
1657
    }
1658
}
1659