CategoryHandler   F
last analyzed

Complexity

Total Complexity 73

Size/Duplication

Total Lines 483
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 73
eloc 214
c 0
b 0
f 0
dl 0
loc 483
rs 2.56

16 Methods

Rating   Name   Duplication   Size   Complexity  
A getCategories() 0 30 3
A getSubCats() 0 17 3
A updateAll() 0 12 5
A get() 0 19 4
A getCount() 0 13 4
B getCategoriesWithOpenQuestion() 0 52 8
B getObjects() 0 29 7
A __construct() 0 14 3
A delete() 0 37 6
B insert() 0 46 9
B getCategoriesWithOpenQuestionsCount() 0 32 8
A getCategoriesCount() 0 18 5
A create() 0 8 2
A faqsCount() 0 9 1
A publishedFaqsCount() 0 3 1
A deleteAll() 0 13 4

How to fix   Complexity   

Complex Class

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

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

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

1
<?php declare(strict_types=1);
2
3
namespace XoopsModules\Smartfaq;
4
5
/**
6
 * Module: SmartFAQ
7
 * Author: The SmartFactory <www.smartfactory.ca>
8
 * Licence: GNU
9
 */
10
11
use XoopsModules\Smartfaq;
12
13
/**
14
 * Categories handler class.
15
 * This class is responsible for providing data access mechanisms to the data source
16
 * of Category class objects.
17
 *
18
 * @author  marcan <[email protected]>
19
 */
20
class CategoryHandler extends \XoopsObjectHandler
21
{
22
    protected $helper;
23
24
    /**
25
     * @param \XoopsDatabase|null                $db
26
     * @param \XoopsModules\Smartfaq\Helper|null $helper
27
     */
28
    public function __construct(\XoopsDatabase $db = null, \XoopsModules\Smartfaq\Helper $helper = null)
29
    {
30
        /** @var \XoopsModules\Smartfaq\Helper $this ->helper */
31
        if (null === $helper) {
32
            $this->helper = \XoopsModules\Smartfaq\Helper::getInstance();
0 ignored issues
show
Bug introduced by
The property helper does not seem to exist on XoopsModules\Smartfaq\Helper.
Loading history...
33
        } else {
34
            $this->helper = $helper;
35
        }
36
37
        if (null === $db) {
38
            $db = \XoopsDatabaseFactory::getDatabaseConnection();
39
        }
40
        $smartfaqIsAdmin = $this->helper->isUserAdmin();
0 ignored issues
show
Unused Code introduced by
The assignment to $smartfaqIsAdmin is dead and can be removed.
Loading history...
41
        parent::__construct($db, 'smartfaq_categories', Category::class, 'categoryid', 'answer');
0 ignored issues
show
Unused Code introduced by
The call to XoopsObjectHandler::__construct() has too many arguments starting with 'smartfaq_categories'. ( Ignorable by Annotation )

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

41
        parent::/** @scrutinizer ignore-call */ 
42
                __construct($db, 'smartfaq_categories', Category::class, 'categoryid', 'answer');

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
42
    }
43
44
    /**
45
     * create a new category
46
     *
47
     * @param bool $isNew flag the new objects as "new"?
48
     * @return object Smartfaq\Category
49
     */
50
    public function create($isNew = true)
51
    {
52
        $category = new Smartfaq\Category();
53
        if ($isNew) {
54
            $category->setNew();
55
        }
56
57
        return $category;
58
    }
59
60
    /**
61
     * retrieve a category
62
     *
63
     * @param int $id categoryid of the category
64
     * @return mixed reference to the {@link Smartfaq\Category} object, FALSE if failed
65
     */
66
    public function get($id)
67
    {
68
        $false = false;
69
        if ((int)$id > 0) {
70
            $sql = 'SELECT * FROM ' . $this->db->prefix('smartfaq_categories') . ' WHERE categoryid=' . $id;
71
            if (!$result = $this->db->query($sql)) {
72
                return $false;
73
            }
74
75
            $numrows = $this->db->getRowsNum($result);
76
            if (1 == $numrows) {
77
                $category = new Smartfaq\Category();
78
                $category->assignVars($this->db->fetchArray($result));
79
80
                return $category;
81
            }
82
        }
83
84
        return $false;
85
    }
86
87
    /**
88
     * insert a new category in the database
89
     *
90
     * @param \XoopsObject $object reference to the {@link Smartfaq\Category}
91
     *                               object
92
     * @param bool         $force
93
     * @return bool        FALSE if failed, TRUE if already present and unchanged or successful
94
     */
95
    public function insert(\XoopsObject $object, $force = false)
96
    {
97
        if ('xoopsmodules\smartfaq\category' !== \mb_strtolower(\get_class($object))) {
98
            return false;
99
        }
100
        if (!$object->isDirty()) {
101
            return true;
102
        }
103
        if (!$object->cleanVars()) {
104
            return false;
105
        }
106
107
        foreach ($object->cleanVars as $k => $v) {
108
            ${$k} = $v;
109
        }
110
111
        if ($object->isNew()) {
112
            $sql = \sprintf('INSERT INTO `%s` (parentid, name, description, total, weight, created) VALUES (%u, %s, %s, %u, %u, %u)', $this->db->prefix('smartfaq_categories'), $parentid, $this->db->quoteString($name), $this->db->quoteString($description), $total, $weight, \time());
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $parentid seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $name seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $description seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $weight seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $total seems to be never defined.
Loading history...
113
        } else {
114
            $sql = \sprintf(
115
                'UPDATE `%s` SET parentid = %u, name = %s, description = %s, total = %s, weight = %u, created = %u WHERE categoryid = %u',
116
                $this->db->prefix('smartfaq_categories'),
117
                $parentid,
118
                $this->db->quoteString($name),
119
                $this->db->quoteString($description),
120
                $total,
121
                $weight,
122
                $created,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $created seems to be never defined.
Loading history...
123
                $objectid
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $objectid does not exist. Did you maybe mean $object?
Loading history...
124
            );
125
        }
126
        if ($force) {
127
            $result = $this->db->queryF($sql);
128
        } else {
129
            $result = $this->db->query($sql);
130
        }
131
        if (!$result) {
132
            return false;
133
        }
134
        if ($object->isNew()) {
135
            $object->assignVar('categoryid', $this->db->getInsertId());
136
        } else {
137
            $object->assignVar('categoryid', $objectid);
138
        }
139
140
        return true;
141
    }
142
143
    /**
144
     * delete a category from the database
145
     *
146
     * @param \XoopsObject $object reference to the category to delete
147
     * @param bool         $force
148
     * @return bool        FALSE if failed.
149
     */
150
    public function delete(\XoopsObject $object, $force = false)
151
    {
152
        if ('xoopsmodules\smartfaq\category' !== \mb_strtolower(\get_class($object))) {
153
            return false;
154
        }
155
156
        // Deleting the FAQs
157
        $faqHandler = new Smartfaq\FaqHandler($this->db);
158
        if (!$faqHandler->deleteAll(new \Criteria('categoryid', $object->categoryid()))) {
0 ignored issues
show
Bug introduced by
The method categoryid() does not exist on XoopsObject. It seems like you code against a sub-type of XoopsObject such as XoopsModules\Smartfaq\Faq or XoopsModules\Smartfaq\Category. ( Ignorable by Annotation )

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

158
        if (!$faqHandler->deleteAll(new \Criteria('categoryid', $object->/** @scrutinizer ignore-call */ categoryid()))) {
Loading history...
159
            return false;
160
        }
161
162
        // Deleteing the sub categories
163
        $subcats = &$this->getCategories(0, 0, $object->categoryid());
164
        foreach ($subcats as $subcat) {
165
            $this->delete($subcat);
166
        }
167
168
        $sql = \sprintf('DELETE FROM `%s` WHERE categoryid = %u', $this->db->prefix('smartfaq_categories'), $object->getVar('categoryid'));
0 ignored issues
show
Bug introduced by
It seems like $object->getVar('categoryid') can also be of type array and array; however, parameter $values of sprintf() does only seem to accept double|integer|string, maybe add an additional type check? ( Ignorable by Annotation )

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

168
        $sql = \sprintf('DELETE FROM `%s` WHERE categoryid = %u', $this->db->prefix('smartfaq_categories'), /** @scrutinizer ignore-type */ $object->getVar('categoryid'));
Loading history...
169
170
        $smartModule = Smartfaq\Utility::getModuleInfo();
171
        $module_id   = $smartModule->getVar('mid');
172
173
        if ($force) {
174
            $result = $this->db->queryF($sql);
175
        } else {
176
            $result = $this->db->query($sql);
177
        }
178
179
        \xoops_groupperm_deletebymoditem($module_id, 'category_read', $object->categoryid());
180
        //xoops_groupperm_deletebymoditem ($module_id, "category_admin", $objectObj->categoryid());
181
182
        if (!$result) {
183
            return false;
184
        }
185
186
        return true;
187
    }
188
189
    /**
190
     * retrieve categories from the database
191
     *
192
     * @param object $criteria  {@link CriteriaElement} conditions to be met
193
     * @param bool   $id_as_key use the categoryid as key for the array?
194
     * @return array  array of {@link XoopsFaq} objects
195
     */
196
    public function getObjects($criteria = null, $id_as_key = false)
197
    {
198
        $ret   = [];
199
        $limit = $start = 0;
200
        $sql   = 'SELECT * FROM ' . $this->db->prefix('smartfaq_categories');
201
        if (($criteria instanceof \CriteriaCompo) || ($criteria instanceof \Criteria)) {
202
            $sql .= ' ' . $criteria->renderWhere();
203
            if ('' != $criteria->getSort()) {
204
                $sql .= ' ORDER BY ' . $criteria->getSort() . ' ' . $criteria->getOrder();
205
            }
206
            $limit = $criteria->getLimit();
207
            $start = $criteria->getStart();
208
        }
209
        //echo "<br>" . $sql . "<br>";
210
        $result = $this->db->query($sql, $limit, $start);
211
        if ($this->db->isResultSet($result)) {
212
            while (false !== ($myrow = $this->db->fetchArray($result))) {
213
                $category = new Smartfaq\Category();
214
                $category->assignVars($myrow);
215
                if ($id_as_key) {
216
                    $ret[$myrow['categoryid']] = $category;
217
                } else {
218
                    $ret[] = $category;
219
                }
220
                unset($category);
221
            }
222
        }
223
224
        return $ret;
225
    }
226
227
    /**
228
     * @param int    $limit
229
     * @param int    $start
230
     * @param int    $parentid
231
     * @param string $sort
232
     * @param string $order
233
     * @param bool   $id_as_key
234
     * @return array
235
     */
236
    public function &getCategories(
237
        $limit = 0,
238
        $start = 0,
239
        $parentid = 0,
240
        $sort = 'weight',
241
        $order = 'ASC',
242
        $id_as_key = true
243
    ) {
244
        //        require_once XOOPS_ROOT_PATH . '/modules/smartfaq/include/functions.php';
245
246
        $criteria = new \CriteriaCompo();
247
248
        $criteria->setSort($sort);
249
        $criteria->setOrder($order);
250
251
        if (-1 != $parentid) {
252
            $criteria->add(new \Criteria('parentid', $parentid));
253
        }
254
        if (!Smartfaq\Utility::userIsAdmin()) {
255
            /** @var Smartfaq\PermissionHandler $smartPermHandler */
256
            $smartPermHandler = Smartfaq\Helper::getInstance()->getHandler('Permission');
257
258
            $categoriesGranted = $smartPermHandler->getPermissions('category');
259
            $criteria->add(new \Criteria('categoryid', '(' . \implode(',', $categoriesGranted) . ')', 'IN'));
260
        }
261
        $criteria->setStart($start);
262
        $criteria->setLimit($limit);
263
        $ret = $this->getObjects($criteria, $id_as_key);
264
265
        return $ret;
266
    }
267
268
    /**
269
     * @param int    $limit
270
     * @param int    $start
271
     * @param int    $parentid
272
     * @param string $sort
273
     * @param string $order
274
     * @return array
275
     */
276
    public function &getCategoriesWithOpenQuestion(
277
        $limit = 0,
278
        $start = 0,
279
        $parentid = 0,
280
        $sort = 'weight',
281
        $order = 'ASC'
282
    ) {
283
        //        require_once XOOPS_ROOT_PATH . '/modules/smartfaq/include/functions.php';
284
285
        $criteria = new \CriteriaCompo();
286
287
        $criteria->setSort($sort);
288
        $criteria->setOrder($order);
289
290
        if (-1 != $parentid) {
291
            $criteria->add(new \Criteria('c.parentid', $parentid));
292
        }
293
        if (!Smartfaq\Utility::userIsAdmin()) {
294
            /** @var Smartfaq\PermissionHandler $smartPermHandler */
295
            $smartPermHandler = Smartfaq\Helper::getInstance()->getHandler('Permission');
296
297
            $categoriesGranted = $smartPermHandler->getPermissions('category');
298
            $criteria->add(new \Criteria('categoryid', '(' . \implode(',', $categoriesGranted) . ')', 'IN'));
299
        }
300
301
        $criteria->add(new \Criteria('f.status', Constants::SF_STATUS_OPENED));
302
        $criteria->setStart($start);
303
        $criteria->setLimit($limit);
304
305
        $ret   = [];
306
        $limit = $start = 0;
307
        $sql   = 'SELECT DISTINCT c.categoryid, c.parentid, c.name, c.description, c.total, c.weight, c.created FROM ' . $this->db->prefix('smartfaq_categories') . ' AS c INNER JOIN ' . $this->db->prefix('smartfaq_faq') . ' AS f ON c.categoryid = f.categoryid';
308
        if (($criteria instanceof \CriteriaCompo) || ($criteria instanceof \Criteria)) {
0 ignored issues
show
introduced by
$criteria is always a sub-type of CriteriaCompo.
Loading history...
309
            $sql .= ' ' . $criteria->renderWhere();
310
            if ('' != $criteria->getSort()) {
311
                $sql .= ' ORDER BY ' . $criteria->getSort() . ' ' . $criteria->getOrder();
312
            }
313
            $limit = $criteria->getLimit();
314
            $start = $criteria->getStart();
315
        }
316
        //echo "<br>" . $sql . "<br>";
317
        $result = $this->db->query($sql, $limit, $start);
318
        if ($this->db->isResultSet($result)) {
319
            while (false !== ($myrow = $this->db->fetchArray($result))) {
320
                $category = new Smartfaq\Category();
321
                $category->assignVars($myrow);
322
                $ret[] = $category;
323
                unset($category);
324
            }
325
        }
326
327
        return $ret;
328
    }
329
330
    /**
331
     * count Categories matching a condition
332
     *
333
     * @param object $criteria {@link CriteriaElement} to match
334
     * @return int    count of categories
335
     */
336
    public function getCount($criteria = null)
337
    {
338
        $sql = 'SELECT COUNT(*) FROM ' . $this->db->prefix('smartfaq_categories');
339
        if (($criteria instanceof \CriteriaCompo) || ($criteria instanceof \Criteria)) {
340
            $sql .= ' ' . $criteria->renderWhere();
341
        }
342
        $result = $this->db->query($sql);
343
        if (!$result) {
344
            return 0;
345
        }
346
        [$count] = $this->db->fetchRow($result);
347
348
        return $count;
349
    }
350
351
    /**
352
     * @param int $parentid
353
     * @return int
354
     */
355
    public function getCategoriesCount($parentid = 0)
356
    {
357
        if (-1 == $parentid) {
358
            return $this->getCount();
359
        }
360
        $criteria = new \CriteriaCompo();
361
        if (isset($parentid) && (-1 != $parentid)) {
362
            $criteria->add(new \Criteria('parentid', $parentid));
363
            if (!Smartfaq\Utility::userIsAdmin()) {
364
                /** @var Smartfaq\PermissionHandler $smartPermHandler */
365
                $smartPermHandler = Smartfaq\Helper::getInstance()->getHandler('Permission');
366
367
                $categoriesGranted = $smartPermHandler->getPermissions('category');
368
                $criteria->add(new \Criteria('categoryid', '(' . \implode(',', $categoriesGranted) . ')', 'IN'));
369
            }
370
        }
371
372
        return $this->getCount($criteria);
373
    }
374
375
    /**
376
     * @param int $parentid
377
     * @return int
378
     */
379
    public function getCategoriesWithOpenQuestionsCount($parentid = 0)
380
    {
381
        if (-1 == $parentid) {
382
            return $this->getCount();
383
        }
384
        $criteria = new \CriteriaCompo();
385
        if (isset($parentid) && (-1 != $parentid)) {
386
            $criteria->add(new \Criteria('parentid', $parentid));
387
            if (!Smartfaq\Utility::userIsAdmin()) {
388
                /** @var Smartfaq\PermissionHandler $smartPermHandler */
389
                $smartPermHandler = Smartfaq\Helper::getInstance()->getHandler('Permission');
390
391
                $categoriesGranted = $smartPermHandler->getPermissions('category');
392
                $criteria->add(new \Criteria('categoryid', '(' . \implode(',', $categoriesGranted) . ')', 'IN'));
393
            }
394
        }
395
396
        $criteria->add(new \Criteria('f.status', Constants::SF_STATUS_OPENED));
397
398
        $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';
399
400
        if (($criteria instanceof \CriteriaCompo) || ($criteria instanceof \Criteria)) {
0 ignored issues
show
introduced by
$criteria is always a sub-type of CriteriaCompo.
Loading history...
401
            $sql .= ' ' . $criteria->renderWhere();
402
        }
403
404
        $result = $this->db->query($sql);
405
        if (!$result) {
406
            return 0;
407
        }
408
        [$count] = $this->db->fetchRow($result);
409
410
        return $count;
411
    }
412
413
    /**
414
     * @param $categories
415
     * @return array
416
     */
417
    public function getSubCats($categories)
418
    {
419
        $criteria = new \CriteriaCompo(new \Criteria('parentid', '(' . \implode(',', \array_keys($categories)) . ')', 'IN'));
420
        $ret      = [];
421
        if (!Smartfaq\Utility::userIsAdmin()) {
422
            /** @var Smartfaq\PermissionHandler $smartPermHandler */
423
            $smartPermHandler = Smartfaq\Helper::getInstance()->getHandler('Permission');
424
425
            $categoriesGranted = $smartPermHandler->getPermissions('category');
426
            $criteria->add(new \Criteria('categoryid', '(' . \implode(',', $categoriesGranted) . ')', 'IN'));
427
        }
428
        $subcats = $this->getObjects($criteria, true);
429
        foreach ($subcats as $subcat_id => $subcat) {
430
            $ret[$subcat->getVar('parentid')][$subcat->getVar('categoryid')] = $subcat;
431
        }
432
433
        return $ret;
434
    }
435
436
    /**
437
     * delete categories matching a set of conditions
438
     *
439
     * @param object $criteria {@link CriteriaElement}
440
     * @return bool   FALSE if deletion failed
441
     */
442
    public function deleteAll($criteria = null)
443
    {
444
        $sql = 'DELETE FROM ' . $this->db->prefix('smartfaq_categories');
445
        if (($criteria instanceof \CriteriaCompo) || ($criteria instanceof \Criteria)) {
446
            $sql .= ' ' . $criteria->renderWhere();
447
        }
448
        if (!$this->db->query($sql)) {
449
            return false;
450
            // TODO : Also delete the permissions related to each FAQ
451
            // TODO : What about sub-categories???
452
        }
453
454
        return true;
455
    }
456
457
    /**
458
     * Change a value for categories with a certain criteria
459
     *
460
     * @param string                $fieldname  Name of the field
461
     * @param string                $fieldvalue Value to write
462
     * @param \CriteriaElement|null $criteria   {@link CriteriaElement}
463
     *
464
     * @return bool
465
     */
466
    public function updateAll($fieldname, $fieldvalue, \CriteriaElement $criteria = null)
467
    {
468
        $set_clause = \is_numeric($fieldvalue) ? $fieldname . ' = ' . $fieldvalue : $fieldname . ' = ' . $this->db->quoteString($fieldvalue);
469
        $sql        = 'UPDATE ' . $this->db->prefix('smartfaq_categories') . ' SET ' . $set_clause;
470
        if (($criteria instanceof \CriteriaCompo) || ($criteria instanceof \Criteria)) {
471
            $sql .= ' ' . $criteria->renderWhere();
472
        }
473
        if (!$this->db->queryF($sql)) {
474
            return false;
475
        }
476
477
        return true;
478
    }
479
480
    /**
481
     * @param int $cat_id
482
     * @return mixed
483
     */
484
    public function publishedFaqsCount($cat_id = 0)
485
    {
486
        return $this->faqsCount($cat_id, $status = [Constants::SF_STATUS_PUBLISHED, Constants::SF_STATUS_NEW_ANSWER]);
0 ignored issues
show
Bug introduced by
$status = array(XoopsMod...::SF_STATUS_NEW_ANSWER) of type array<integer,integer> is incompatible with the type string expected by parameter $status of XoopsModules\Smartfaq\CategoryHandler::faqsCount(). ( Ignorable by Annotation )

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

486
        return $this->faqsCount($cat_id, /** @scrutinizer ignore-type */ $status = [Constants::SF_STATUS_PUBLISHED, Constants::SF_STATUS_NEW_ANSWER]);
Loading history...
487
    }
488
489
    /**
490
     * @param int    $cat_id
491
     * @param string $status
492
     * @return mixed
493
     */
494
    public function faqsCount($cat_id = 0, $status = '')
495
    {
496
        global $xoopsUser;
497
        //        require_once XOOPS_ROOT_PATH . '/modules/smartfaq/include/functions.php';
498
499
        /** @var Smartfaq\FaqHandler $faqHandler */
500
        $faqHandler = Smartfaq\Helper::getInstance()->getHandler('Faq');
501
502
        return $faqHandler->getCountsByCat($cat_id, $status);
503
    }
504
}
505