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

class/answer.php (20 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
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');
10
11
// Answers status
12
define('_SF_AN_STATUS_NOTSET', -1);
13
define('_SF_AN_STATUS_PROPOSED', 0);
14
define('_SF_AN_STATUS_APPROVED', 1);
15
define('_SF_AN_STATUS_REJECTED', 2);
16
17
// Notification Events
18
define('_SF_NOT_ANSWER_APPROVED', 3);
19
define('_SF_NOT_ANSWER_REJECTED', 4);
20
21
/**
22
 * Class sfAnswer
23
 */
24
class sfAnswer extends XoopsObject
25
{
26
    public $attachment_array = array();
27
28
    /**
29
     * constructor
30
     * @param null $id
31
     */
32
    public function __construct($id = null)
33
    {
34
        $this->db = XoopsDatabaseFactory::getDatabaseConnection();
35
        $this->initVar('answerid', XOBJ_DTYPE_INT, null, false);
36
        $this->initVar('status', XOBJ_DTYPE_INT, -1, false);
37
        $this->initVar('faqid', XOBJ_DTYPE_INT, null, false);
38
        $this->initVar('answer', XOBJ_DTYPE_TXTAREA, null, true);
39
        $this->initVar('uid', XOBJ_DTYPE_INT, 0, false);
40
        $this->initVar('datesub', XOBJ_DTYPE_INT, null, false);
41
        $this->initVar('notifypub', XOBJ_DTYPE_INT, 0, false);
42
43
        $this->initVar('attachment', XOBJ_DTYPE_TXTAREA, '');
44
45
        $this->initVar('dohtml', XOBJ_DTYPE_INT, 1, false);
46
        $this->initVar('doxcode', XOBJ_DTYPE_INT, 1, false);
47
        $this->initVar('dosmiley', XOBJ_DTYPE_INT, 1, false);
48
        $this->initVar('doimage', XOBJ_DTYPE_INT, 0, false);
49
        $this->initVar('dobr', XOBJ_DTYPE_INT, 1, false);
50
51
        // for backward compatibility
52
        if (isset($id)) {
53
            if (is_array($id)) {
54
                $this->assignVars($id);
55
            } else {
56
                $answerHandler = new sfAnswerHandler($this->db);
57
                $answer        = $answerHandler->get($id);
58
                foreach ($answer->vars as $k => $v) {
59
                    $this->assignVar($k, $v['value']);
60
                }
61
            }
62
        }
63
    }
64
65
    // ////////////////////////////////////////////////////////////////////////////////////
66
    // attachment functions    TODO: there should be a file/attachment management class
67
    /**
68
     * @return array|mixed|null
69
     */
70
    public function getAttachment()
71
    {
72
        if (count($this->attachment_array)) {
73
            return $this->attachment_array;
74
        }
75
        $attachment = $this->getVar('attachment');
76
        if (empty($attachment)) {
77
            $this->attachment_array = null;
78
        } else {
79
            $this->attachment_array = @unserialize(base64_decode($attachment));
80
        }
81
82
        return $this->attachment_array;
83
    }
84
85
    /**
86
     * @param $attach_key
87
     * @return bool
88
     */
89
    public function incrementDownload($attach_key)
90
    {
91
        if (!$attach_key) {
92
            return false;
93
        }
94
        $this->attachment_array[(string)$attach_key]['num_download']++;
95
96
        return $this->attachment_array[(string)$attach_key]['num_download'];
97
    }
98
99
    /**
100
     * @return bool
101
     */
102
    public function saveAttachment()
103
    {
104
        $attachment_save = '';
105 View Code Duplication
        if (is_array($this->attachment_array) && count($this->attachment_array) > 0) {
106
            $attachment_save = base64_encode(serialize($this->attachment_array));
107
        }
108
        $this->setVar('attachment', $attachment_save);
109
        $sql = 'UPDATE ' . $GLOBALS['xoopsDB']->prefix('smartfaq_answers') . ' SET attachment=' . $GLOBALS['xoopsDB']->quoteString($attachment_save) . ' WHERE post_id = ' . $this->getVar('answerid');
110
        if (!$result = $GLOBALS['xoopsDB']->queryF($sql)) {
111
            //xoops_error($GLOBALS["xoopsDB"]->error());
112
            return false;
113
        }
114
115
        return true;
116
    }
117
118
    /**
119
     * @param  null $attach_array
120
     * @return bool
121
     */
122
    public function deleteAttachment($attach_array = null)
123
    {
124
        global $xoopsModuleConfig;
125
126
        $attach_old = $this->getAttachment();
127
        if (!is_array($attach_old) || count($attach_old) < 1) {
128
            return true;
129
        }
130
        $this->attachment_array = array();
131
132
        if ($attach_array === null) {
133
            $attach_array = array_keys($attach_old);
134
        } // to delete all!
135
        if (!is_array($attach_array)) {
136
            $attach_array = array($attach_array);
137
        }
138
139
        foreach ($attach_old as $key => $attach) {
140
            if (in_array($key, $attach_array)) {
141
                @unlink(XOOPS_ROOT_PATH . '/' . $xoopsModuleConfig['dir_attachments'] . '/' . $attach['name_saved']);
142
                @unlink(XOOPS_ROOT_PATH . '/' . $xoopsModuleConfig['dir_attachments'] . '/thumbs/' . $attach['name_saved']); // delete thumbnails
143
                continue;
144
            }
145
            $this->attachment_array[$key] = $attach;
146
        }
147
        $attachment_save = '';
148 View Code Duplication
        if (is_array($this->attachment_array) && count($this->attachment_array) > 0) {
149
            $attachment_save = base64_encode(serialize($this->attachment_array));
150
        }
151
        $this->setVar('attachment', $attachment_save);
152
153
        return true;
154
    }
155
156
    /**
157
     * @param  string $name_saved
158
     * @param  string $name_display
159
     * @param  string $mimetype
160
     * @param  int    $num_download
161
     * @return bool
162
     */
163
    public function setAttachment($name_saved = '', $name_display = '', $mimetype = '', $num_download = 0)
164
    {
165
        static $counter = 0;
166
        $this->attachment_array = $this->getAttachment();
167
        if ($name_saved) {
168
            $key                          = (string)(time() + ($counter++));
169
            $this->attachment_array[$key] = array(
170
                'name_saved'   => $name_saved,
171
                'name_display' => isset($name_display) ? $name_display : $name_saved,
172
                'mimetype'     => $mimetype,
173
                'num_download' => isset($num_download) ? (int)$num_download : 0
174
            );
175
        }
176
        $attachment_save = null;
177
        if (is_array($this->attachment_array)) {
178
            $attachment_save = base64_encode(serialize($this->attachment_array));
179
        }
180
        $this->setVar('attachment', $attachment_save);
181
182
        return true;
183
    }
184
185
    /**
186
     * TODO: refactor
187
     * @param  bool $asSource
188
     * @return string
189
     */
190
    public function displayAttachment($asSource = false)
191
    {
192
        global $xoopsModule, $xoopsModuleConfig;
193
194
        $post_attachment = '';
195
        $attachments     = $this->getAttachment();
196
        if (is_array($attachments) && count($attachments) > 0) {
197
            $iconHandler = sf_getIconHandler();
198
            $mime_path   = $iconHandler->getPath('mime');
199
            include_once XOOPS_ROOT_PATH . '/modules/' . $xoopsModule->getVar('dirname', 'n') . '/include/functions.image.php';
200
            $image_extensions = array('jpg', 'jpeg', 'gif', 'png', 'bmp'); // need improve !!!
201
            $post_attachment  .= '<br><strong>' . _MD_ATTACHMENT . '</strong>:';
202
            $post_attachment  .= '<br><hr size="1" noshade="noshade" /><br>';
203
            foreach ($attachments as $key => $att) {
204
                $file_extension = ltrim(strrchr($att['name_saved'], '.'), '.');
205
                $filetype       = $file_extension;
206
                if (file_exists(XOOPS_ROOT_PATH . '/' . $mime_path . '/' . $filetype . '.gif')) {
207
                    $icon_filetype = XOOPS_URL . '/' . $mime_path . '/' . $filetype . '.gif';
208
                } else {
209
                    $icon_filetype = XOOPS_URL . '/' . $mime_path . '/unknown.gif';
210
                }
211
                $file_size = @filesize(XOOPS_ROOT_PATH . '/' . $xoopsModuleConfig['dir_attachments'] . '/' . $att['name_saved']);
212
                $file_size = number_format($file_size / 1024, 2) . ' KB';
213
                if ($xoopsModuleConfig['media_allowed'] && in_array(strtolower($file_extension), $image_extensions)) {
214
                    $post_attachment .= '<br><img src="' . $icon_filetype . '" alt="' . $filetype . '" /><strong>&nbsp; ' . $att['name_display'] . '</strong> <small>(' . $file_size . ')</small>';
215
                    $post_attachment .= '<br>' . sf_attachmentImage($att['name_saved']);
216
                    $isDisplayed     = true;
217
                } else {
218
                    global $xoopsUser;
219
                    if (empty($xoopsModuleConfig['show_userattach'])) {
220
                        $post_attachment .= '<a href="'
221
                                            . XOOPS_URL
222
                                            . '/modules/'
223
                                            . $xoopsModule->getVar('dirname', 'n')
224
                                            . '/dl_attachment.php?attachid='
225
                                            . $key
226
                                            . '&amp;post_id='
227
                                            . $this->getVar('post_id')
228
                                            . '"> <img src="'
229
                                            . $icon_filetype
230
                                            . '" alt="'
231
                                            . $filetype
232
                                            . '" /> '
233
                                            . $att['name_display']
234
                                            . '</a> '
235
                                            . _MD_FILESIZE
236
                                            . ': '
237
                                            . $file_size
238
                                            . '; '
239
                                            . _MD_HITS
240
                                            . ': '
241
                                            . $att['num_download'];
242
                    } elseif ($xoopsUser && $xoopsUser->uid() > 0 && $xoopsUser->isactive()) {
243
                        $post_attachment .= '<a href="'
244
                                            . XOOPS_URL
245
                                            . '/modules/'
246
                                            . $xoopsModule->getVar('dirname', 'n')
247
                                            . '/dl_attachment.php?attachid='
248
                                            . $key
249
                                            . '&amp;post_id='
250
                                            . $this->getVar('post_id')
251
                                            . '"> <img src="'
252
                                            . $icon_filetype
253
                                            . '" alt="'
254
                                            . $filetype
255
                                            . '" /> '
256
                                            . $att['name_display']
257
                                            . '</a> '
258
                                            . _MD_FILESIZE
259
                                            . ': '
260
                                            . $file_size
261
                                            . '; '
262
                                            . _MD_HITS
263
                                            . ': '
264
                                            . $att['num_download'];
265
                    } else {
266
                        $post_attachment .= _MD_NEWBB_SEENOTGUEST;
267
                    }
268
                }
269
                $post_attachment .= '<br>';
270
            }
271
        }
272
273
        return $post_attachment;
274
    }
275
    // attachment functions
276
    // ////////////////////////////////////////////////////////////////////////////////////
277
278
    /**
279
     * @param  bool $force
280
     * @return bool
281
     */
282
    public function store($force = true)
283
    {
284
        $answerHandler = new sfAnswerHandler($this->db);
285
286
        if ($this->status() == _SF_AN_STATUS_APPROVED) {
287
            $criteria = new CriteriaCompo(new criteria('faqid', $this->faqid()));
288
            $answerHandler->updateAll('status', _SF_AN_STATUS_REJECTED, $criteria);
289
        }
290
291
        return $answerHandler->insert($this, $force);
292
    }
293
294
    /**
295
     * @return mixed
296
     */
297
    public function answerid()
298
    {
299
        return $this->getVar('answerid');
300
    }
301
302
    /**
303
     * @return mixed
304
     */
305
    public function faqid()
306
    {
307
        return $this->getVar('faqid');
308
    }
309
310
    /**
311
     * @param  string $format
312
     * @return mixed
313
     */
314
    public function answer($format = 'S')
315
    {
316
        return $this->getVar('answer', $format);
317
    }
318
319
    /**
320
     * @return mixed
321
     */
322
    public function uid()
323
    {
324
        return $this->getVar('uid');
325
    }
326
327
    /**
328
     * @param  string $dateFormat
329
     * @param  string $format
330
     * @return string
331
     */
332 View Code Duplication
    public function datesub($dateFormat = 'none', $format = 'S')
333
    {
334
        if ($dateFormat === 'none') {
335
            $smartModuleConfig = sf_getModuleConfig();
336
            $dateFormat        = $smartModuleConfig['dateformat'];
337
        }
338
339
        return formatTimestamp($this->getVar('datesub', $format), $dateFormat);
340
    }
341
342
    /**
343
     * @return mixed
344
     */
345
    public function status()
346
    {
347
        return $this->getVar('status');
348
    }
349
350
    /**
351
     * @return bool
352
     */
353
    public function notLoaded()
354
    {
355
        return ($this->getVar('answerid') == -1);
356
    }
357
358
    /**
359
     * @param array $notifications
360
     */
361
    public function sendNotifications($notifications = array())
362
    {
363
        $smartModule = sf_getModuleInfo();
364
365
        $myts                = MyTextSanitizer::getInstance();
366
        $notificationHandler = xoops_getHandler('notification');
367
368
        $faqObj = new sfFaq($this->faqid());
369
370
        $tags                  = array();
371
        $tags['MODULE_NAME']   = $myts->displayTarea($smartModule->getVar('name'));
372
        $tags['FAQ_NAME']      = $faqObj->question();
373
        $tags['FAQ_URL']       = XOOPS_URL . '/modules/' . $smartModule->getVar('dirname') . '/faq.php?faqid=' . $faqObj->faqid();
374
        $tags['CATEGORY_NAME'] = $faqObj->getCategoryName();
375
        $tags['CATEGORY_URL']  = XOOPS_URL . '/modules/' . $smartModule->getVar('dirname') . '/category.php?categoryid=' . $faqObj->categoryid();
376
        $tags['FAQ_QUESTION']  = $faqObj->question();
377
378
        // TODO : Not sure about the 'formpreview' ...
379
        $tags['FAQ_ANSWER'] = $this->answer('formpreview');
380
        $tags['DATESUB']    = $this->datesub();
381
382
        foreach ($notifications as $notification) {
383
            switch ($notification) {
384
                case _SF_NOT_ANSWER_APPROVED:
385
                    // This notification is not working for PM, but is for email... and I don't understand why???
386
                    $notificationHandler->triggerEvent('faq', $this->answerid(), 'answer_approved', $tags);
387
388
                    break;
389
390
                case -1:
391
                default:
392
                    break;
393
            }
394
        }
395
    }
396
}
397
398
/**
399
 * Answers handler class.
400
 * This class is responsible for providing data access mechanisms to the data source
401
 * of Answer class objects.
402
 *
403
 * @author  marcan <[email protected]>
404
 * @package SmartFAQ
405
 */
406
class sfAnswerHandler extends XoopsPersistableObjectHandler
407
{
408
409
    /**
410
     * create a new answer
411
     *
412
     * @param  bool $isNew flag the new objects as "new"?
413
     * @return object sfAnswer
414
     */
415
    public function create($isNew = true)
416
    {
417
        $answer = new sfAnswer();
418
        if ($isNew) {
419
            $answer->setNew();
420
        }
421
422
        return $answer;
423
    }
424
425
    /**
426
     * retrieve an answer
427
     *
428
     * @param  int  $id answerid of the answer
429
     * @param  null $fields
430
     * @return mixed reference to the <a href='psi_element://sfAnswer'>sfAnswer</a> object, FALSE if failed
431
     */
432 View Code Duplication
    public function get($id = null, $fields = null)
433
    {
434
        if ((int)$id > 0) {
435
            $sql = 'SELECT * FROM ' . $this->db->prefix('smartfaq_answers') . ' WHERE answerid=' . $id;
436
            if (!$result = $this->db->query($sql)) {
437
                return false;
438
            }
439
440
            $numrows = $this->db->getRowsNum($result);
441
            if ($numrows == 1) {
442
                $answer = new sfAnswer();
443
                $answer->assignVars($this->db->fetchArray($result));
444
445
                return $answer;
446
            }
447
        }
448
449
        return false;
450
    }
451
452
    /**
453
     * insert a new answer in the database
454
     *
455
     * @param  XoopsObject $answerObj reference to the <a href='psi_element://sfAnswer'>sfAnswer</a> object
456
     * @param  bool        $force
457
     * @return bool        FALSE if failed, TRUE if already present and unchanged or successful
458
     */
459
    public function insert(XoopsObject $answerObj, $force = false)
460
    {
461
        if (strtolower(get_class($answerObj)) !== 'sfanswer') {
462
            return false;
463
        }
464
        if (!$answerObj->isDirty()) {
465
            return true;
466
        }
467
        if (!$answerObj->cleanVars()) {
468
            return false;
469
        }
470
471
        foreach ($answerObj->cleanVars as $k => $v) {
472
            ${$k} = $v;
473
        }
474
475
        if ($answerObj->isNew()) {
476
            $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,
0 ignored issues
show
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...
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...
477
                           $this->db->quoteString($answer), $uid, time(), $notifypub);
0 ignored issues
show
The variable $answer does not exist. Did you mean $answerObj?

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...
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...
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...
478
        } else {
479
            $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,
480
                           $this->db->quoteString($answer), $uid, $datesub, $notifypub, $answerid);
0 ignored issues
show
The variable $answer does not exist. Did you mean $answerObj?

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...
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...
The variable $answerid 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...
481
        }
482
483 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...
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...
484
            $result = $this->db->queryF($sql);
485
        } else {
486
            $result = $this->db->query($sql);
487
        }
488
489
        if (!$result) {
490
            return false;
491
        }
492
493
        if ($answerObj->isNew()) {
494
            $answerObj->assignVar('answerid', $this->db->getInsertId());
495
        } else {
496
            $answerObj->assignVar('answerid', $answerid);
497
        }
498
499
        return true;
500
    }
501
502
    /**
503
     * delete an answer from the database
504
     *
505
     * @param  XoopsObject $answer reference to the answer to delete
506
     * @param  bool        $force
507
     * @return bool        FALSE if failed.
508
     */
509
    public function delete(XoopsObject $answer, $force = false)
510
    {
511
        if (strtolower(get_class($answer)) !== 'sfanswer') {
512
            return false;
513
        }
514
        $sql = sprintf('DELETE FROM %s WHERE answerid = %u', $this->db->prefix('smartfaq_answers'), $answer->getVar('answerid'));
515
516
        //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...
517
518 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...
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...
519
            $result = $this->db->queryF($sql);
520
        } else {
521
            $result = $this->db->query($sql);
522
        }
523
        if (!$result) {
524
            return false;
525
        }
526
527
        return true;
528
    }
529
530
    /**
531
     * delete an answer from the database
532
     *
533
     * @param  object $faqObj reference to the answer to delete
534
     * @return bool   FALSE if failed.
535
     * @internal param bool $force
536
     */
537
    public function deleteFaqAnswers($faqObj)
538
    {
539
        if (strtolower(get_class($faqObj)) !== 'sffaq') {
540
            return false;
541
        }
542
        $answers = $this->getAllAnswers($faqObj->faqid());
543
        $result  = true;
544
        foreach ($answers as $answer) {
545
            if (!$this->delete($answer)) {
546
                $result = false;
547
            }
548
        }
549
550
        return $result;
551
    }
552
553
    /**
554
     * retrieve answers from the database
555
     *
556
     * @param  CriteriaElement $criteria  {@link CriteriaElement} conditions to be met
557
     * @param  bool            $id_as_key use the answerid as key for the array?
558
     * @param  bool            $as_object
559
     * @return array           array of <a href='psi_element://sfAnswer'>sfAnswer</a> objects
560
     */
561
    public function &getObjects(CriteriaElement $criteria = null, $id_as_key = false, $as_object = true)
562
    {
563
        $ret   = array();
564
        $limit = $start = 0;
565
        $sql   = 'SELECT * FROM ' . $this->db->prefix('smartfaq_answers');
566 View Code Duplication
        if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
0 ignored issues
show
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...
567
            $sql .= ' ' . $criteria->renderWhere();
568
            if ($criteria->getSort() != '') {
569
                $sql .= ' ORDER BY ' . $criteria->getSort() . ' ' . $criteria->getOrder();
570
            }
571
            $limit = $criteria->getLimit();
572
            $start = $criteria->getStart();
573
        }
574
        //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...
575
        $result = $this->db->query($sql, $limit, $start);
576
        if (!$result) {
577
            return $ret;
578
        }
579 View Code Duplication
        while ($myrow = $this->db->fetchArray($result)) {
580
            $answer = new sfAnswer();
581
            $answer->assignVars($myrow);
582
            if (!$id_as_key) {
583
                $ret[] =& $answer;
584
            } else {
585
                $ret[$myrow['answerid']] =& $answer;
586
            }
587
            unset($answer);
588
        }
589
590
        return $ret;
591
    }
592
593
    /**
594
     * retrieve 1 official answer (for now SmartFAQ only allow 1 official answer...)
595
     *
596
     * @param  int $faqid
597
     * @return mixed reference to the <a href='psi_element://sfAnswer'>sfAnswer</a> object, FALSE if failed
598
     */
599
    public function getOfficialAnswer($faqid = 0)
600
    {
601
        $theaAnswers = $this->getAllAnswers($faqid, _SF_AN_STATUS_APPROVED, 1, 0);
602
        $ret         = false;
603
        if (count($theaAnswers) == 1) {
604
            $ret = $theaAnswers[0];
605
        }
606
607
        return $ret;
608
    }
609
610
    /**
611
     * retrieve all answers
612
     *
613
     * @param  int    $faqid
614
     * @param  int    $status
615
     * @param  int    $limit
616
     * @param  int    $start
617
     * @param  string $sort
618
     * @param  string $order
619
     * @return array  array of <a href='psi_element://sfAnswer'>sfAnswer</a> objects
620
     */
621
    public function getAllAnswers(
622
        $faqid = 0,
623
        $status = -1,
624
        $limit = 0,
625
        $start = 0,
626
        $sort = 'datesub',
627
        $order = 'DESC'
628
    ) {
629
        $hasStatusCriteria = false;
630
        $criteriaStatus    = new CriteriaCompo();
631
        if (is_array($status)) {
632
            $hasStatusCriteria = true;
633
            foreach ($status as $v) {
634
                $criteriaStatus->add(new Criteria('status', $v), 'OR');
635
            }
636
        } elseif ($status != -1) {
637
            $hasStatusCriteria = true;
638
            $criteriaStatus->add(new Criteria('status', $status), 'OR');
639
        }
640
        $criteriaFaqid = new Criteria('faqid', $faqid);
641
642
        $criteria = new CriteriaCompo();
643
        $criteria->add($criteriaFaqid);
644
645
        if ($hasStatusCriteria) {
646
            $criteria->add($criteriaStatus);
647
        }
648
649
        $criteria->setSort($sort);
650
        $criteria->setOrder($order);
651
        $criteria->setLimit($limit);
652
        $criteria->setStart($start);
653
        $ret =& $this->getObjects($criteria);
654
655
        return $ret;
656
    }
657
658
    /**
659
     * count answers matching a condition
660
     *
661
     * @param  CriteriaElement $criteria {@link CriteriaElement} to match
662
     * @return int             count of answers
663
     */
664 View Code Duplication
    public function getCount(CriteriaElement $criteria = null)
665
    {
666
        $sql = 'SELECT COUNT(*) FROM ' . $this->db->prefix('smartfaq_answers');
667
        if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
0 ignored issues
show
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...
668
            $sql .= ' ' . $criteria->renderWhere();
669
        }
670
        $result = $this->db->query($sql);
671
        if (!$result) {
672
            return 0;
673
        }
674
        list($count) = $this->db->fetchRow($result);
675
676
        return $count;
677
    }
678
679
    /**
680
     * count answers matching a condition and group by faq ID
681
     *
682
     * @param  object $criteria {@link CriteriaElement} to match
0 ignored issues
show
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...
683
     * @return array
684
     */
685
    public function getCountByFAQ($criteria = null)
686
    {
687
        $sql = 'SELECT faqid, COUNT(*) FROM ' . $this->db->prefix('smartfaq_answers');
688
        if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
0 ignored issues
show
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
            $sql .= ' ' . $criteria->getGroupby();
691
        }
692
693
        //echo "<br>$sql<br>";
694
695
        $result = $this->db->query($sql);
696
        if (!$result) {
697
            return array();
698
        }
699
        $ret = array();
700
        while (list($id, $count) = $this->db->fetchRow($result)) {
701
            $ret[$id] = $count;
702
        }
703
704
        return $ret;
705
    }
706
707
    /**
708
     * delete answers matching a set of conditions
709
     *
710
     * @param  CriteriaElement $criteria {@link CriteriaElement}
711
     * @param  bool            $force
712
     * @param  bool            $asObject
713
     * @return bool            FALSE if deletion failed
714
     */
715
    public function deleteAll(CriteriaElement $criteria = null, $force = true, $asObject = false)
716
    {
717
        $sql = 'DELETE FROM ' . $this->db->prefix('smartfaq_answers');
718
        if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
0 ignored issues
show
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...
719
            $sql .= ' ' . $criteria->renderWhere();
720
        }
721
        if (!$this->db->query($sql)) {
722
            return false;
723
        }
724
725
        return true;
726
    }
727
728
    /**
729
     * Change a value for answers with a certain criteria
730
     *
731
     * @param  string          $fieldname  Name of the field
732
     * @param  string          $fieldvalue Value to write
733
     * @param  CriteriaElement $criteria   {@link CriteriaElement}
734
     * @param  bool            $force
735
     * @return bool
736
     */
737 View Code Duplication
    public function updateAll($fieldname, $fieldvalue, CriteriaElement $criteria = null, $force = false)
738
    {
739
        $set_clause = is_numeric($fieldvalue) ? $fieldname . ' = ' . $fieldvalue : $fieldname . ' = ' . $this->db->quoteString($fieldvalue);
740
        $sql        = 'UPDATE ' . $this->db->prefix('smartfaq_answers') . ' SET ' . $set_clause;
741
        if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
0 ignored issues
show
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...
742
            $sql .= ' ' . $criteria->renderWhere();
743
        }
744
        //echo "<br>" . $sql . "<br>";
745
        if (!$this->db->queryF($sql)) {
746
            return false;
747
        }
748
749
        return true;
750
    }
751
752
    /**
753
     * @param $faqids
754
     * @return array
755
     */
756
    public function getLastPublishedByFaq($faqids)
757
    {
758
        $ret    = array();
759
        $sql    = 'SELECT faqid, answer, uid, datesub FROM ' . $this->db->prefix('smartfaq_answers') . '
760
               WHERE faqid IN (' . implode(',', $faqids) . ') AND status = ' . _SF_AN_STATUS_APPROVED . ' GROUP BY faqid';
761
        $result = $this->db->query($sql);
762
        if (!$result) {
763
            return $ret;
764
        }
765 View Code Duplication
        while ($row = $this->db->fetchArray($result)) {
766
            $answer = new sfAnswer();
767
            $answer->assignVars($row);
768
            $ret[$row['faqid']] =& $answer;
769
            unset($answer);
770
        }
771
772
        return $ret;
773
    }
774
}
775