AnswerHandler   F
last analyzed

Complexity

Total Complexity 60

Size/Duplication

Total Lines 381
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 60
eloc 153
c 1
b 0
f 0
dl 0
loc 381
rs 3.6

14 Methods

Rating   Name   Duplication   Size   Complexity  
A getLastPublishedByFaq() 0 17 3
A delete() 0 19 4
A __construct() 0 10 2
B getObjects() 0 29 7
A deleteAll() 0 11 4
A getAllAnswers() 0 35 5
A deleteFaqAnswers() 0 14 4
A getOfficialAnswer() 0 9 2
A getCount() 0 13 4
B insert() 0 39 9
A get() 0 18 4
A updateAll() 0 13 5
A getCountByFAQ() 0 20 5
A create() 0 8 2

How to fix   Complexity   

Complex Class

Complex classes like AnswerHandler 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 AnswerHandler, 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 Criteria;
12
use CriteriaCompo;
13
use CriteriaElement;
14
use XoopsDatabase;
15
use XoopsModules\Smartfaq;
16
use XoopsObject;
17
use XoopsPersistableObjectHandler;
18
19
/**
20
 * Answers handler class.
21
 * This class is responsible for providing data access mechanisms to the data source
22
 * of Answer class objects.
23
 *
24
 * @author  marcan <[email protected]>
25
 */
26
class AnswerHandler extends XoopsPersistableObjectHandler
27
{
28
    public $helper;
29
30
    /**
31
     * @param \XoopsDatabase|null                $db
32
     * @param \XoopsModules\Smartfaq\Helper|null $helper
33
     */
34
    public function __construct(XoopsDatabase $db = null, \XoopsModules\Smartfaq\Helper $helper = null)
35
    {
36
        /** @var \XoopsModules\Smartfaq\Helper $this ->helper */
37
        if (null === $helper) {
38
            $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...
39
        } else {
40
            $this->helper = $helper;
41
        }
42
        $smartfaqIsAdmin = $this->helper->isUserAdmin();
0 ignored issues
show
Unused Code introduced by
The assignment to $smartfaqIsAdmin is dead and can be removed.
Loading history...
43
        parent::__construct($db, 'smartfaq_answers', Answer::class, 'answerid', 'answer');
44
    }
45
46
    /**
47
     * create a new answer
48
     *
49
     * @param bool $isNew flag the new objects as "new"?
50
     * @return object Answer
51
     */
52
    public function create($isNew = true)
53
    {
54
        $answer = new Smartfaq\Answer();
55
        if ($isNew) {
56
            $answer->setNew();
57
        }
58
59
        return $answer;
60
    }
61
62
    /**
63
     * retrieve an answer
64
     *
65
     * @param int  $id answerid of the answer
66
     * @param null $fields
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $fields is correct as it would always require null to be passed?
Loading history...
67
     * @return mixed reference to the <a href='psi_element://sfAnswer'>sfAnswer</a> object, FALSE if failed
68
     */
69
    public function get($id = null, $fields = null)
70
    {
71
        if ((int)$id > 0) {
72
            $sql = 'SELECT * FROM ' . $this->db->prefix('smartfaq_answers') . ' WHERE answerid=' . $id;
73
            if (!$result = $this->db->query($sql)) {
74
                return false;
75
            }
76
77
            $numrows = $this->db->getRowsNum($result);
78
            if (1 == $numrows) {
79
                $answer = new Smartfaq\Answer();
80
                $answer->assignVars($this->db->fetchArray($result));
81
82
                return $answer;
83
            }
84
        }
85
86
        return false;
87
    }
88
89
    /**
90
     * insert a new answer in the database
91
     *
92
     * @param \XoopsObject $object reference to the <a href='psi_element://sfAnswer'>sfAnswer</a> object
93
     * @param bool         $force
94
     * @return bool        FALSE if failed, TRUE if already present and unchanged or successful
95
     */
96
    public function insert(XoopsObject $object, $force = false)
97
    {
98
        if ('xoopsmodules\smartfaq\answer' !== \mb_strtolower(\get_class($object))) {
99
            return false;
100
        }
101
        if (!$object->isDirty()) {
102
            return true;
103
        }
104
        if (!$object->cleanVars()) {
105
            return false;
106
        }
107
108
        foreach ($object->cleanVars as $k => $v) {
109
            ${$k} = $v;
110
        }
111
112
        if ($object->isNew()) {
113
            $sql = \sprintf('INSERT INTO `%s` (answerid, `status`, faqid, answer, uid, datesub, notifypub) VALUES (NULL, %u, %u, %s, %u, %u, %u)', $this->db->prefix('smartfaq_answers'), $status, $faqid, $this->db->quoteString($answer), $uid, \time(), $notifypub);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $faqid seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $status seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $uid seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $notifypub seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $answer seems to be never defined.
Loading history...
114
        } else {
115
            $sql = \sprintf('UPDATE `%s` SET STATUS = %u, faqid = %s, answer = %s, uid = %u, datesub = %u, notifypub = %u WHERE answerid = %u', $this->db->prefix('smartfaq_answers'), $status, $faqid, $this->db->quoteString($answer), $uid, $datesub, $notifypub, $answerid);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $datesub seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $answerid seems to be never defined.
Loading history...
116
        }
117
118
        if ($force) {
119
            $result = $this->db->queryF($sql);
120
        } else {
121
            $result = $this->db->query($sql);
122
        }
123
124
        if (!$result) {
125
            return false;
126
        }
127
128
        if ($object->isNew()) {
129
            $object->assignVar('answerid', $this->db->getInsertId());
130
        } else {
131
            $object->assignVar('answerid', $answerid);
132
        }
133
134
        return true;
135
    }
136
137
    /**
138
     * delete an answer from the database
139
     *
140
     * @param \XoopsObject $object reference to the answer to delete
141
     * @param bool         $force
142
     * @return bool        FALSE if failed.
143
     */
144
    public function delete(XoopsObject $object, $force = false)
145
    {
146
        if ('xoopsmodules\smartfaq\answer' !== \mb_strtolower(\get_class($object))) {
147
            return false;
148
        }
149
        $sql = \sprintf('DELETE FROM `%s` WHERE answerid = %u', $this->db->prefix('smartfaq_answers'), $object->getVar('answerid'));
0 ignored issues
show
Bug introduced by
It seems like $object->getVar('answerid') 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

149
        $sql = \sprintf('DELETE FROM `%s` WHERE answerid = %u', $this->db->prefix('smartfaq_answers'), /** @scrutinizer ignore-type */ $object->getVar('answerid'));
Loading history...
150
151
        //echo "<br>" . $sql . "<br>";
152
153
        if ($force) {
154
            $result = $this->db->queryF($sql);
155
        } else {
156
            $result = $this->db->query($sql);
157
        }
158
        if (!$result) {
159
            return false;
160
        }
161
162
        return true;
163
    }
164
165
    /**
166
     * delete an answer from the database
167
     *
168
     * @param object $faqObj reference to the answer to delete
169
     * @return bool   FALSE if failed.
170
     * @internal param bool $force
171
     */
172
    public function deleteFaqAnswers($faqObj)
173
    {
174
        if ('xoopsmodules\smartfaq\faq' !== \mb_strtolower(\get_class($faqObj))) {
175
            return false;
176
        }
177
        $answers = $this->getAllAnswers($faqObj->faqid());
178
        $result  = true;
179
        foreach ($answers as $answer) {
180
            if (!$this->delete($answer)) {
181
                $result = false;
182
            }
183
        }
184
185
        return $result;
186
    }
187
188
    /**
189
     * retrieve answers from the database
190
     *
191
     * @param \CriteriaElement|null $criteria  {@link CriteriaElement} conditions to be met
192
     * @param bool                  $id_as_key use the answerid as key for the array?
193
     * @param bool                  $as_object
194
     * @return array           array of <a href='psi_element://sfAnswer'>sfAnswer</a> objects
195
     */
196
    public function &getObjects(CriteriaElement $criteria = null, $id_as_key = false, $as_object = true)
197
    {
198
        $ret   = [];
199
        $limit = $start = 0;
200
        $sql   = 'SELECT * FROM ' . $this->db->prefix('smartfaq_answers');
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
                $answer = new Smartfaq\Answer();
214
                $answer->assignVars($myrow);
215
                if ($id_as_key) {
216
                    $ret[$myrow['answerid']] = $answer;
217
                } else {
218
                    $ret[] = &$answer;
219
                }
220
                unset($answer);
221
            }
222
        }
223
224
        return $ret;
225
    }
226
227
    /**
228
     * retrieve 1 official answer (for now SmartFAQ only allow 1 official answer...)
229
     *
230
     * @param int $faqid
231
     * @return mixed reference to the <a href='psi_element://sfAnswer'>sfAnswer</a> object, FALSE if failed
232
     */
233
    public function getOfficialAnswer($faqid = 0)
234
    {
235
        $theaAnswers = $this->getAllAnswers($faqid, Constants::SF_AN_STATUS_APPROVED, 1, 0);
236
        $ret         = false;
237
        if (1 == \count($theaAnswers)) {
238
            $ret = $theaAnswers[0];
239
        }
240
241
        return $ret;
242
    }
243
244
    /**
245
     * retrieve all answers
246
     *
247
     * @param int       $faqid
248
     * @param int|array $status
249
     * @param int       $limit
250
     * @param int       $start
251
     * @param string    $sort
252
     * @param string    $order
253
     * @return array  array of <a href='psi_element://sfAnswer'>sfAnswer</a> objects
254
     */
255
    public function getAllAnswers(
256
        $faqid = 0,
257
        $status = -1,
258
        $limit = 0,
259
        $start = 0,
260
        $sort = 'datesub',
261
        $order = 'DESC'
262
    ) {
263
        $hasStatusCriteria = false;
264
        $criteriaStatus    = new CriteriaCompo();
265
        if (\is_array($status)) {
266
            $hasStatusCriteria = true;
267
            foreach ($status as $v) {
268
                $criteriaStatus->add(new Criteria('status', $v), 'OR');
269
            }
270
        } elseif (-1 != $status) {
271
            $hasStatusCriteria = true;
272
            $criteriaStatus->add(new Criteria('status', $status), 'OR');
273
        }
274
        $criteriaFaqid = new Criteria('faqid', $faqid);
275
276
        $criteria = new CriteriaCompo();
277
        $criteria->add($criteriaFaqid);
278
279
        if ($hasStatusCriteria) {
280
            $criteria->add($criteriaStatus);
281
        }
282
283
        $criteria->setSort($sort);
284
        $criteria->setOrder($order);
285
        $criteria->setLimit($limit);
286
        $criteria->setStart($start);
287
        $ret = $this->getObjects($criteria);
288
289
        return $ret;
290
    }
291
292
    /**
293
     * count answers matching a condition
294
     *
295
     * @param \CriteriaElement|null $criteria {@link CriteriaElement} to match
296
     * @return int             count of answers
297
     */
298
    public function getCount(CriteriaElement $criteria = null)
299
    {
300
        $sql = 'SELECT COUNT(*) FROM ' . $this->db->prefix('smartfaq_answers');
301
        if (($criteria instanceof \CriteriaCompo) || ($criteria instanceof \Criteria)) {
302
            $sql .= ' ' . $criteria->renderWhere();
303
        }
304
        $result = $this->db->query($sql);
305
        if (!$result) {
306
            return 0;
307
        }
308
        [$count] = $this->db->fetchRow($result);
309
310
        return $count;
311
    }
312
313
    /**
314
     * count answers matching a condition and group by faq ID
315
     *
316
     * @param object $criteria {@link CriteriaElement} to match
317
     * @return array
318
     */
319
    public function getCountByFAQ($criteria = null)
320
    {
321
        $sql = 'SELECT faqid, COUNT(*) FROM ' . $this->db->prefix('smartfaq_answers');
322
        if (($criteria instanceof \CriteriaCompo) || ($criteria instanceof \Criteria)) {
323
            $sql .= ' ' . $criteria->renderWhere();
324
            $sql .= ' ' . $criteria->getGroupby();
325
        }
326
327
        //echo "<br>$sql<br>";
328
329
        $result = $this->db->query($sql);
330
        if (!$result) {
331
            return [];
332
        }
333
        $ret = [];
334
        while ([$id, $count] = $this->db->fetchRow($result)) {
335
            $ret[$id] = $count;
336
        }
337
338
        return $ret;
339
    }
340
341
    /**
342
     * delete answers matching a set of conditions
343
     *
344
     * @param \CriteriaElement|null $criteria {@link CriteriaElement}
345
     * @param bool                  $force
346
     * @param bool                  $asObject
347
     * @return bool            FALSE if deletion failed
348
     */
349
    public function deleteAll(CriteriaElement $criteria = null, $force = true, $asObject = false)
350
    {
351
        $sql = 'DELETE FROM ' . $this->db->prefix('smartfaq_answers');
352
        if (($criteria instanceof \CriteriaCompo) || ($criteria instanceof \Criteria)) {
353
            $sql .= ' ' . $criteria->renderWhere();
354
        }
355
        if (!$this->db->query($sql)) {
356
            return false;
357
        }
358
359
        return true;
360
    }
361
362
    /**
363
     * Change a value for answers with a certain criteria
364
     *
365
     * @param string                $fieldname  Name of the field
366
     * @param string                $fieldvalue Value to write
367
     * @param \CriteriaElement|null $criteria   {@link CriteriaElement}
368
     * @param bool                  $force
369
     * @return bool
370
     */
371
    public function updateAll($fieldname, $fieldvalue, CriteriaElement $criteria = null, $force = false)
372
    {
373
        $set_clause = \is_numeric($fieldvalue) ? $fieldname . ' = ' . $fieldvalue : $fieldname . ' = ' . $this->db->quoteString($fieldvalue);
374
        $sql        = 'UPDATE ' . $this->db->prefix('smartfaq_answers') . ' SET ' . $set_clause;
375
        if (($criteria instanceof \CriteriaCompo) || ($criteria instanceof \Criteria)) {
376
            $sql .= ' ' . $criteria->renderWhere();
377
        }
378
        //echo "<br>" . $sql . "<br>";
379
        if (!$this->db->queryF($sql)) {
380
            return false;
381
        }
382
383
        return true;
384
    }
385
386
    /**
387
     * @param $faqids
388
     * @return array
389
     */
390
    public function getLastPublishedByFaq($faqids)
391
    {
392
        $ret    = [];
393
        $sql    = 'SELECT faqid, answer, uid, datesub FROM ' . $this->db->prefix('smartfaq_answers') . '
394
               WHERE faqid IN (' . \implode(',', $faqids) . ') AND status = ' . Constants::SF_AN_STATUS_APPROVED . ' GROUP BY faqid';
395
        $result = $this->db->query($sql);
396
        if (!$result) {
397
            return $ret;
398
        }
399
        while (false !== ($row = $this->db->fetchArray($result))) {
400
            $answer = new Smartfaq\Answer();
401
            $answer->assignVars($row);
402
            $ret[$row['faqid']] = &$answer;
403
            unset($answer);
404
        }
405
406
        return $ret;
407
    }
408
}
409