Completed
Branch master (c92e39)
by Michael
02:32
created

sfCategoryHandler   C

Complexity

Total Complexity 70

Size/Duplication

Total Lines 456
Duplicated Lines 20.83 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
dl 95
loc 456
rs 5.6163
c 0
b 0
f 0
wmc 70
lcom 1
cbo 2

15 Methods

Rating   Name   Duplication   Size   Complexity  
A create() 0 9 2
A get() 0 20 4
D insert() 5 39 9
B delete() 5 38 6
C getObjects() 18 32 7
B getCategories() 0 30 3
B getCategoriesWithOpenQuestion() 8 58 8
A getCount() 14 14 4
B getCategoriesCount() 9 18 5
C getCategoriesWithOpenQuestionsCount() 9 32 8
A getSubCats() 0 17 3
A deleteAll() 14 14 4
B updateAll() 13 13 5
A publishedFaqsCount() 0 4 1
A faqsCount() 0 9 1

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

1
<?php
2
3
/**
4
 * Module: SmartFAQ
5
 * Author: The SmartFactory <www.smartfactory.ca>
6
 * Licence: GNU
7
 */
8
// 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...
9
10
class sfCategory 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...
11
{
12
    /**
13
     * @var array
14
     * @access private
15
     */
16
    private $groups_read = null;
17
18
    /**
19
     * @var array
20
     * @access private
21
     */
22
    private $groups_admin = null;
0 ignored issues
show
Unused Code introduced by
The property $groups_admin 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...
23
24
    /**
25
     * constructor
26
     * @param null $id
27
     */
28
    public function __construct($id = null)
29
    {
30
        $this->db = XoopsDatabaseFactory::getDatabaseConnection();
31
        $this->initVar('categoryid', XOBJ_DTYPE_INT, null, false);
32
        $this->initVar('parentid', XOBJ_DTYPE_INT, null, false);
33
        $this->initVar('name', XOBJ_DTYPE_TXTBOX, null, true, 100);
34
        $this->initVar('description', XOBJ_DTYPE_TXTAREA, null, false, 255);
35
        $this->initVar('total', XOBJ_DTYPE_INT, 1, false);
36
        $this->initVar('weight', XOBJ_DTYPE_INT, 1, false);
37
        $this->initVar('created', XOBJ_DTYPE_INT, null, false);
38
        $this->initVar('last_faq', XOBJ_DTYPE_INT);
39
40
        //not persistent values
41
        $this->initVar('faqcount', XOBJ_DTYPE_INT, 0, false);
42
        $this->initVar('last_faqid', XOBJ_DTYPE_INT);
43
        $this->initVar('last_question_link', XOBJ_DTYPE_TXTBOX);
44
45
        if (isset($id)) {
46
            if (is_array($id)) {
47
                $this->assignVars($id);
48
            } else {
49
                $categoryHandler = new sfCategoryHandler($this->db);
50
                $category        =& $categoryHandler->get($id);
51
                foreach ($category->vars as $k => $v) {
52
                    $this->assignVar($k, $v['value']);
53
                }
54
                $this->assignOtherProperties();
55
            }
56
        }
57
    }
58
59
    /**
60
     * @return bool
61
     */
62
    public function notLoaded()
63
    {
64
        return ($this->getVar('categoryid') == -1);
65
    }
66
67
    public function assignOtherProperties()
68
    {
69
        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...
70
        $smartModule = sf_getModuleInfo();
71
        $module_id   = $smartModule->getVar('mid');
72
73
        $gpermHandler = xoops_getHandler('groupperm');
74
75
        $this->groups_read = $gpermHandler->getGroupIds('category_read', $this->categoryid(), $module_id);
76
    }
77
78
    /**
79
     * @return bool
80
     */
81 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...
82
    {
83
        include_once XOOPS_ROOT_PATH . '/modules/smartfaq/include/functions.php';
84
85
        $userIsAdmin = sf_userIsAdmin();
86
        if ($userIsAdmin) {
87
            return true;
88
        }
89
90
        $smartPermHandler = xoops_getModuleHandler('permission', 'smartfaq');
91
92
        $categoriesGranted = $smartPermHandler->getPermissions('category');
93
        if (in_array($this->categoryid(), $categoriesGranted)) {
94
            $ret = true;
95
        }
96
97
        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...
98
    }
99
100
    /**
101
     * @return mixed
102
     */
103
    public function categoryid()
104
    {
105
        return $this->getVar('categoryid');
106
    }
107
108
    /**
109
     * @return mixed
110
     */
111
    public function parentid()
112
    {
113
        return $this->getVar('parentid');
114
    }
115
116
    /**
117
     * @param  string $format
118
     * @return mixed
119
     */
120 View Code Duplication
    public function name($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...
121
    {
122
        $ret = $this->getVar('name', $format);
123
        if (($format === 's') || ($format === 'S') || ($format === 'show')) {
124
            $myts = MyTextSanitizer::getInstance();
125
            $ret  = $myts->displayTarea($ret);
126
        }
127
128
        return $ret;
129
    }
130
131
    /**
132
     * @param  string $format
133
     * @return mixed
134
     */
135
    public function description($format = 'S')
136
    {
137
        return $this->getVar('description', $format);
138
    }
139
140
    /**
141
     * @return mixed
142
     */
143
    public function weight()
144
    {
145
        return $this->getVar('weight');
146
    }
147
148
    /**
149
     * @param  bool $withAllLink
150
     * @param  bool $open
151
     * @return mixed|string
152
     */
153
    public function getCategoryPath($withAllLink = false, $open = false)
154
    {
155
        $filename = 'category.php';
156
        if ($open !== false) {
157
            $filename = 'open_category.php';
158
        }
159
        if ($withAllLink) {
160
            $ret = "<a href='" . XOOPS_URL . '/modules/smartfaq/' . $filename . '?categoryid=' . $this->categoryid() . "'>" . $this->name() . '</a>';
161
        } else {
162
            $ret = $this->name();
163
        }
164
        $parentid        = $this->parentid();
165
        $categoryHandler = sf_gethandler('category');
166
        if ($parentid != 0) {
167
            $parentObj = $categoryHandler->get($parentid);
168
            if ($parentObj->notLoaded()) {
169
                exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method getCategoryPath() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
170
            }
171
            $parentid = $parentObj->parentid();
0 ignored issues
show
Unused Code introduced by
$parentid 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...
172
            $ret      = $parentObj->getCategoryPath(true, $open) . ' > ' . $ret;
173
        }
174
175
        return $ret;
176
    }
177
178
    /**
179
     * @return array
180
     */
181
    public function getGroups_read()
182
    {
183
        if (count($this->groups_read) < 1) {
184
            $this->assignOtherProperties();
185
        }
186
187
        return $this->groups_read;
188
    }
189
190
    /**
191
     * @param array $groups_read
192
     */
193
    public function setGroups_read($groups_read = array('0'))
194
    {
195
        $this->groups_read = $groups_read;
196
    }
197
198
    /**
199
     * @param  bool $sendNotifications
200
     * @param  bool $force
201
     * @return bool
202
     */
203
    public function store($sendNotifications = true, $force = true)
204
    {
205
        $categoryHandler = new sfCategoryHandler($this->db);
206
207
        $ret = $categoryHandler->insert($this, $force);
208
        if ($sendNotifications && $ret && $this->isNew()) {
209
            $this->sendNotifications();
210
        }
211
        $this->unsetNew();
212
213
        return $ret;
214
    }
215
216
    public function sendNotifications()
217
    {
218
        $smartModule = sf_getModuleInfo();
219
220
        $myts                = MyTextSanitizer::getInstance();
221
        $notificationHandler = xoops_getHandler('notification');
0 ignored issues
show
Unused Code introduced by
$notificationHandler 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...
222
223
        $tags                  = array();
224
        $tags['MODULE_NAME']   = $myts->htmlSpecialChars($smartModule->getVar('name'));
225
        $tags['CATEGORY_NAME'] = $this->name();
226
        $tags['CATEGORY_URL']  = XOOPS_URL . '/modules/' . $smartModule->getVar('dirname') . '/category.php?categoryid=' . $this->categoryid();
227
228
        $notificationHandler = xoops_getHandler('notification');
229
        $notificationHandler->triggerEvent('global_faq', 0, 'category_created', $tags);
230
    }
231
232
    /**
233
     * @param  array $category
234
     * @param  bool  $open
235
     * @return array
236
     */
237
    public function toArray($category = array(), $open = false)
238
    {
239
        $category['categoryid'] = $this->categoryid();
240
        $category['name']       = $this->name();
241
        if ($open !== false) {
242
            $category['categorylink'] = "<a href='" . XOOPS_URL . '/modules/smartfaq/open_category.php?categoryid=' . $this->categoryid() . "'>" . $this->name() . '</a>';
243
        } else {
244
            $category['categorylink'] = "<a href='" . XOOPS_URL . '/modules/smartfaq/category.php?categoryid=' . $this->categoryid() . "'>" . $this->name() . '</a>';
245
        }
246
        $category['total']       = $this->getVar('faqcount');
247
        $category['description'] = $this->description();
248
249
        if ($this->getVar('last_faqid') > 0) {
250
            $category['last_faqid']         = $this->getVar('last_faqid', 'n');
251
            $category['last_question_link'] = $this->getVar('last_question_link', 'n');
252
        }
253
254
        return $category;
255
    }
256
}
257
258
/**
259
 * Categories handler class.
260
 * This class is responsible for providing data access mechanisms to the data source
261
 * of Category class objects.
262
 *
263
 * @author  marcan <[email protected]>
264
 * @package SmartFAQ
265
 */
266
class sfCategoryHandler 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...
267
{
268
    /**
269
     * create a new category
270
     *
271
     * @param  bool $isNew flag the new objects as "new"?
272
     * @return object sfCategory
273
     */
274
    public function &create($isNew = true)
275
    {
276
        $category = new sfCategory();
277
        if ($isNew) {
278
            $category->setNew();
279
        }
280
281
        return $category;
282
    }
283
284
    /**
285
     * retrieve a category
286
     *
287
     * @param  int $id categoryid of the category
288
     * @return mixed reference to the {@link sfCategory} object, FALSE if failed
289
     */
290
    public function &get($id)
291
    {
292
        $false = false;
293
        if ((int)$id > 0) {
294
            $sql = 'SELECT * FROM ' . $this->db->prefix('smartfaq_categories') . ' WHERE categoryid=' . $id;
295
            if (!$result = $this->db->query($sql)) {
296
                return $false;
297
            }
298
299
            $numrows = $this->db->getRowsNum($result);
300
            if ($numrows == 1) {
301
                $category = new sfCategory();
302
                $category->assignVars($this->db->fetchArray($result));
303
304
                return $category;
305
            }
306
        }
307
308
        return $false;
309
    }
310
311
    /**
312
     * insert a new category in the database
313
     *
314
     * @param  XoopsObject $category reference to the {@link sfCategory} object
315
     * @param  bool        $force
316
     * @return bool        FALSE if failed, TRUE if already present and unchanged or successful
317
     */
318
    public function insert(XoopsObject $category, $force = false)
319
    {
320
        if (strtolower(get_class($category)) !== 'sfcategory') {
321
            return false;
322
        }
323
        if (!$category->isDirty()) {
324
            return true;
325
        }
326
        if (!$category->cleanVars()) {
327
            return false;
328
        }
329
330
        foreach ($category->cleanVars as $k => $v) {
331
            ${$k} = $v;
332
        }
333
334
        if ($category->isNew()) {
335
            $sql = sprintf('INSERT INTO %s (categoryid, parentid, name, description, total, weight, created) VALUES (NULL, %u, %s, %s, %u, %u, %u)', $this->db->prefix('smartfaq_categories'),
336
                           $parentid, $this->db->quoteString($name), $this->db->quoteString($description), $total, $weight, time());
0 ignored issues
show
Bug introduced by
The variable $parentid 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 $name 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 $description 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 $total 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...
337
        } else {
338
            $sql = sprintf('UPDATE %s SET parentid = %u, name = %s, description = %s, total = %s, weight = %u, created = %u WHERE categoryid = %u', $this->db->prefix('smartfaq_categories'), $parentid,
339
                           $this->db->quoteString($name), $this->db->quoteString($description), $total, $weight, $created, $categoryid);
0 ignored issues
show
Bug introduced by
The variable $created 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 $categoryid does not exist. Did you mean $category?

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

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

Loading history...
340
        }
341 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...
342
            $result = $this->db->queryF($sql);
343
        } else {
344
            $result = $this->db->query($sql);
345
        }
346
        if (!$result) {
347
            return false;
348
        }
349
        if ($category->isNew()) {
350
            $category->assignVar('categoryid', $this->db->getInsertId());
351
        } else {
352
            $category->assignVar('categoryid', $categoryid);
0 ignored issues
show
Bug introduced by
The variable $categoryid does not exist. Did you mean $category?

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

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

Loading history...
353
        }
354
355
        return true;
356
    }
357
358
    /**
359
     * delete a category from the database
360
     *
361
     * @param  XoopsObject $category reference to the category to delete
362
     * @param  bool        $force
363
     * @return bool        FALSE if failed.
364
     */
365
    public function delete(XoopsObject $category, $force = false)
366
    {
367
        if (strtolower(get_class($category)) !== 'sfcategory') {
368
            return false;
369
        }
370
371
        // Deleting the FAQs
372
        $faqHandler = new sfFaqHandler($this->db);
373
        if (!$faqHandler->deleteAll(new Criteria('categoryid', $category->categoryid()))) {
374
            return false;
375
        }
376
377
        // Deleteing the sub categories
378
        $subcats =& $this->getCategories(0, 0, $category->categoryid());
379
        foreach ($subcats as $subcat) {
380
            $this->delete($subcat);
381
        }
382
383
        $sql = sprintf('DELETE FROM %s WHERE categoryid = %u', $this->db->prefix('smartfaq_categories'), $category->getVar('categoryid'));
384
385
        $smartModule = sf_getModuleInfo();
386
        $module_id   = $smartModule->getVar('mid');
387
388 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...
389
            $result = $this->db->queryF($sql);
390
        } else {
391
            $result = $this->db->query($sql);
392
        }
393
394
        xoops_groupperm_deletebymoditem($module_id, 'category_read', $category->categoryid());
395
        //xoops_groupperm_deletebymoditem ($module_id, "category_admin", $categoryObj->categoryid());
0 ignored issues
show
Unused Code Comprehensibility introduced by
69% 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...
396
397
        if (!$result) {
398
            return false;
399
        }
400
401
        return true;
402
    }
403
404
    /**
405
     * retrieve categories from the database
406
     *
407
     * @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...
408
     * @param  bool   $id_as_key use the categoryid as key for the array?
409
     * @return array  array of {@link XoopsFaq} objects
410
     */
411
    public function getObjects($criteria = null, $id_as_key = false)
412
    {
413
        $ret   = array();
414
        $limit = $start = 0;
415
        $sql   = 'SELECT * FROM ' . $this->db->prefix('smartfaq_categories');
416 View Code Duplication
        if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
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...
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...
417
            $sql .= ' ' . $criteria->renderWhere();
418
            if ($criteria->getSort() != '') {
419
                $sql .= ' ORDER BY ' . $criteria->getSort() . ' ' . $criteria->getOrder();
420
            }
421
            $limit = $criteria->getLimit();
422
            $start = $criteria->getStart();
423
        }
424
        //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...
425
        $result = $this->db->query($sql, $limit, $start);
426
        if (!$result) {
427
            return $ret;
428
        }
429
430 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...
431
            $category = new sfCategory();
432
            $category->assignVars($myrow);
433
            if (!$id_as_key) {
434
                $ret[] = $category;
435
            } else {
436
                $ret[$myrow['categoryid']] = $category;
437
            }
438
            unset($category);
439
        }
440
441
        return $ret;
442
    }
443
444
    /**
445
     * @param  int    $limit
446
     * @param  int    $start
447
     * @param  int    $parentid
448
     * @param  string $sort
449
     * @param  string $order
450
     * @param  bool   $id_as_key
451
     * @return array
452
     */
453
    public function &getCategories(
454
        $limit = 0,
455
        $start = 0,
456
        $parentid = 0,
457
        $sort = 'weight',
458
        $order = 'ASC',
459
        $id_as_key = true
460
    ) {
461
        include_once XOOPS_ROOT_PATH . '/modules/smartfaq/include/functions.php';
462
463
        $criteria = new CriteriaCompo();
464
465
        $criteria->setSort($sort);
466
        $criteria->setOrder($order);
467
468
        if ($parentid != -1) {
469
            $criteria->add(new Criteria('parentid', $parentid));
470
        }
471
        if (!sf_userIsAdmin()) {
472
            $smartPermHandler = xoops_getModuleHandler('permission', 'smartfaq');
473
474
            $categoriesGranted = $smartPermHandler->getPermissions('category');
475
            $criteria->add(new Criteria('categoryid', '(' . implode(',', $categoriesGranted) . ')', 'IN'));
476
        }
477
        $criteria->setStart($start);
478
        $criteria->setLimit($limit);
479
        $ret = $this->getObjects($criteria, $id_as_key);
480
481
        return $ret;
482
    }
483
484
    /**
485
     * @param  int    $limit
486
     * @param  int    $start
487
     * @param  int    $parentid
488
     * @param  string $sort
489
     * @param  string $order
490
     * @return array
491
     */
492
    public function &getCategoriesWithOpenQuestion(
493
        $limit = 0,
494
        $start = 0,
495
        $parentid = 0,
496
        $sort = 'weight',
497
        $order = 'ASC'
498
    ) {
499
        include_once XOOPS_ROOT_PATH . '/modules/smartfaq/include/functions.php';
500
501
        $criteria = new CriteriaCompo();
502
503
        $criteria->setSort($sort);
504
        $criteria->setOrder($order);
505
506
        if ($parentid != -1) {
507
            $criteria->add(new Criteria('c.parentid', $parentid));
508
        }
509
        if (!sf_userIsAdmin()) {
510
            $smartPermHandler = xoops_getModuleHandler('permission', 'smartfaq');
511
512
            $categoriesGranted = $smartPermHandler->getPermissions('category');
513
            $criteria->add(new Criteria('categoryid', '(' . implode(',', $categoriesGranted) . ')', 'IN'));
514
        }
515
516
        $criteria->add(new Criteria('f.status', _SF_STATUS_OPENED));
517
        $criteria->setStart($start);
518
        $criteria->setLimit($limit);
519
520
        $ret   = array();
521
        $limit = $start = 0;
522
        $sql   = 'SELECT DISTINCT c.categoryid, c.parentid, c.name, c.description, c.total, c.weight, c.created FROM '
523
                 . $this->db->prefix('smartfaq_categories')
524
                 . ' AS c INNER JOIN '
525
                 . $this->db->prefix('smartfaq_faq')
526
                 . ' AS f ON c.categoryid = f.categoryid';
527 View Code Duplication
        if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
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...
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...
528
            $sql .= ' ' . $criteria->renderWhere();
529
            if ($criteria->getSort() != '') {
530
                $sql .= ' ORDER BY ' . $criteria->getSort() . ' ' . $criteria->getOrder();
531
            }
532
            $limit = $criteria->getLimit();
533
            $start = $criteria->getStart();
534
        }
535
        //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...
536
        $result = $this->db->query($sql, $limit, $start);
537
        if (!$result) {
538
            return $ret;
539
        }
540
541
        while ($myrow = $this->db->fetchArray($result)) {
542
            $category = new sfCategory();
543
            $category->assignVars($myrow);
544
            $ret[] = $category;
545
            unset($category);
546
        }
547
548
        return $ret;
549
    }
550
551
    /**
552
     * count Categories matching a condition
553
     *
554
     * @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...
555
     * @return int    count of categories
556
     */
557 View Code Duplication
    public function getCount($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...
558
    {
559
        $sql = 'SELECT COUNT(*) FROM ' . $this->db->prefix('smartfaq_categories');
560
        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...
561
            $sql .= ' ' . $criteria->renderWhere();
562
        }
563
        $result = $this->db->query($sql);
564
        if (!$result) {
565
            return 0;
566
        }
567
        list($count) = $this->db->fetchRow($result);
568
569
        return $count;
570
    }
571
572
    /**
573
     * @param  int $parentid
574
     * @return int
575
     */
576
    public function getCategoriesCount($parentid = 0)
577
    {
578
        if ($parentid == -1) {
579
            return $this->getCount();
580
        }
581
        $criteria = new CriteriaCompo();
582 View Code Duplication
        if (isset($parentid) && ($parentid != -1)) {
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...
583
            $criteria->add(new criteria('parentid', $parentid));
584
            if (!sf_userIsAdmin()) {
585
                $smartPermHandler = xoops_getModuleHandler('permission', 'smartfaq');
586
587
                $categoriesGranted = $smartPermHandler->getPermissions('category');
588
                $criteria->add(new Criteria('categoryid', '(' . implode(',', $categoriesGranted) . ')', 'IN'));
589
            }
590
        }
591
592
        return $this->getCount($criteria);
593
    }
594
595
    /**
596
     * @param  int $parentid
597
     * @return int
598
     */
599
    public function getCategoriesWithOpenQuestionsCount($parentid = 0)
600
    {
601
        if ($parentid == -1) {
602
            return $this->getCount();
603
        }
604
        $criteria = new CriteriaCompo();
605 View Code Duplication
        if (isset($parentid) && ($parentid != -1)) {
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...
606
            $criteria->add(new criteria('parentid', $parentid));
607
            if (!sf_userIsAdmin()) {
608
                $smartPermHandler = xoops_getModuleHandler('permission', 'smartfaq');
609
610
                $categoriesGranted = $smartPermHandler->getPermissions('category');
611
                $criteria->add(new Criteria('categoryid', '(' . implode(',', $categoriesGranted) . ')', 'IN'));
612
            }
613
        }
614
615
        $criteria->add(new Criteria('f.status', _SF_STATUS_OPENED));
616
617
        $sql = 'SELECT COUNT(c.categoryid) FROM ' . $this->db->prefix('smartfaq_categories') . ' AS c INNER JOIN ' . $this->db->prefix('smartfaq_faq') . ' AS f ON c.categoryid = f.categoryid';
618
619
        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...
620
            $sql .= ' ' . $criteria->renderWhere();
621
        }
622
623
        $result = $this->db->query($sql);
624
        if (!$result) {
625
            return 0;
626
        }
627
        list($count) = $this->db->fetchRow($result);
628
629
        return $count;
630
    }
631
632
    /**
633
     * @param $categories
634
     * @return array
635
     */
636
    public function getSubCats($categories)
637
    {
638
        $criteria = new CriteriaCompo(new Criteria('parentid', '(' . implode(',', array_keys($categories)) . ')'), 'IN');
639
        $ret      = array();
640
        if (!sf_userIsAdmin()) {
641
            $smartPermHandler = xoops_getModuleHandler('permission', 'smartfaq');
642
643
            $categoriesGranted = $smartPermHandler->getPermissions('category');
644
            $criteria->add(new Criteria('categoryid', '(' . implode(',', $categoriesGranted) . ')', 'IN'));
645
        }
646
        $subcats = $this->getObjects($criteria, true);
647
        foreach ($subcats as $subcat_id => $subcat) {
648
            $ret[$subcat->getVar('parentid')][$subcat->getVar('categoryid')] = $subcat;
649
        }
650
651
        return $ret;
652
    }
653
654
    /**
655
     * delete categories matching a set of conditions
656
     *
657
     * @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...
658
     * @return bool   FALSE if deletion failed
659
     */
660 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...
661
    {
662
        $sql = 'DELETE FROM ' . $this->db->prefix('smartfaq_categories');
663
        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...
664
            $sql .= ' ' . $criteria->renderWhere();
665
        }
666
        if (!$this->db->query($sql)) {
667
            return false;
668
            // TODO : Also delete the permissions related to each FAQ
669
            // TODO : What about sub-categories???
670
        }
671
672
        return true;
673
    }
674
675
    /**
676
     * Change a value for categories with a certain criteria
677
     *
678
     * @param string $fieldname  Name of the field
679
     * @param string $fieldvalue Value to write
680
     * @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...
681
     *
682
     * @return bool
683
     **/
684 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...
685
    {
686
        $set_clause = is_numeric($fieldvalue) ? $fieldname . ' = ' . $fieldvalue : $fieldname . ' = ' . $this->db->quoteString($fieldvalue);
687
        $sql        = 'UPDATE ' . $this->db->prefix('smartfaq_categories') . ' SET ' . $set_clause;
688
        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...
689
            $sql .= ' ' . $criteria->renderWhere();
690
        }
691
        if (!$this->db->queryF($sql)) {
692
            return false;
693
        }
694
695
        return true;
696
    }
697
698
    /**
699
     * @param  int $cat_id
700
     * @return mixed
701
     */
702
    public function publishedFaqsCount($cat_id = 0)
703
    {
704
        return $this->faqsCount($cat_id, $status = array(_SF_STATUS_PUBLISHED, _SF_STATUS_NEW_ANSWER));
705
    }
706
707
    /**
708
     * @param  int    $cat_id
709
     * @param  string $status
710
     * @return mixed
711
     */
712
    public function faqsCount($cat_id = 0, $status = '')
713
    {
714
        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...
715
        include_once XOOPS_ROOT_PATH . '/modules/smartfaq/include/functions.php';
716
717
        $faqHandler = sf_gethandler('faq');
718
719
        return $faqHandler->getCountsByCat($cat_id, $status);
720
    }
721
}
722