TopicRenderer   F
last analyzed

Complexity

Total Complexity 212

Size/Duplication

Total Lines 1132
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 610
c 3
b 0
f 0
dl 0
loc 1132
rs 1.99
wmc 212

23 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A init() 0 4 1
A getInstance() 0 8 2
A buildTypes() 0 22 5
A setVarsFromRequest() 0 20 5
F myParseStatus() 0 145 51
B parseVars() 0 29 8
B getSort() 0 99 9
B buildSelection() 0 31 7
F renderTopics() 0 268 46
A getHeader() 0 14 1
B buildPagenav() 0 26 7
A getTypes() 0 15 4
A getStatus() 0 34 2
B buildHeaders() 0 24 7
A getCount() 0 29 4
A buildCurrent() 0 18 5
C setVar() 0 38 13
A buildSearch() 0 8 1
A setVars() 0 10 3
D parseVar() 0 80 22
A buildFilters() 0 19 4
A getFromKeys() 0 13 4

How to fix   Complexity   

Complex Class

Complex classes like TopicRenderer 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 TopicRenderer, and based on these observations, apply Extract Interface, too.

1
<?php declare(strict_types=1);
2
3
namespace XoopsModules\Newbb;
4
5
/**
6
 * NewBB,  the forum module for XOOPS project
7
 *
8
 * @copyright      XOOPS Project (https://xoops.org)
9
 * @license        GNU GPL 2.0 or later (https://www.gnu.org/licenses/gpl-2.0.html)
10
 * @author         Taiwen Jiang (phppp or D.J.) <[email protected]>
11
 * @since          4.00
12
 */
13
14
use Xmf\Request;
15
use XoopsModules\Newbb;
16
17
/**
18
 * Topic Renderer
19
 *
20
 * @author    D.J. (phppp)
21
 * @copyright copyright &copy; Xoops Project
22
 */
23
class TopicRenderer
24
{
25
    public array $vars = [];
26
    /**
27
     * reference to moduleConfig
28
     */
29
    public array $config;
30
    /**
31
     * Current user has no access to current page
32
     */
33
    private bool $noperm = false;
34
    /**
35
     * For multiple forums
36
     */
37
    public bool $is_multiple = false;
38
    /**
39
     * force to parse vars (run against static vars) irmtfan
40
     */
41
    public bool $force = false;
42
    /**
43
     * Vistitor's level: 0 - anonymous; 1 - user; 2 - moderator or admin
44
     */
45
    public int   $userlevel = 0;
46
    public array $query     = [];
47
    /**
48
     *  reference to an object handler
49
     *
50
     * @var \XoopsObjectHandler|\XoopsPersistableObjectHandler
51
     */
52
    private $handler;
53
    /**
54
     * Requested page
55
     */
56
    private string $page = 'list.topic.php';
57
    /**
58
     * query variables
59
     */
60
    private array $args = ['forum', 'uid', 'lastposter', 'type', 'status', 'mode', 'sort', 'order', 'start', 'since'];
61
    /**
62
     * Constructor
63
     */
64
    //    public function TopicRenderer()
65
    public function __construct()
66
    {
67
        $this->handler = Helper::getInstance()->getHandler('Topic');
68
    }
69
70
    /**
71
     * Access the only instance of this class
72
     * @return TopicRenderer
73
     */
74
    public static function getInstance(): TopicRenderer
75
    {
76
        static $instance;
77
        if (null === $instance) {
78
            $instance = new self();
79
        }
80
81
        return $instance;
82
    }
83
84
    public function init(): void
85
    {
86
        $this->noperm = false;
87
        $this->query  = [];
88
    }
89
90
    /**
91
     * @param string       $var    
92
     * @param string|mixed[] $val
93
     * @return mixed[]|int|string
94
     */
95
    public function setVar(string $var, $val)
96
    {
97
        switch ($var) {
98
            case 'forum':
99
                if (\is_numeric($val)) {
100
                    $val = (int)$val;
101
                    // START irmtfan - if the forum is array
102
                } elseif (\is_array($val)) {
103
                    $val = \implode('|', $val);
104
                    //} elseif (!empty($val)) {
105
                    //    $val = implode("|", array_map("intval", explode(", ", $val)));
106
                }
107
                // END irmtfan - if the forum is array
108
                break;
109
            case 'type':
110
            case 'mode':
111
            case 'order':
112
            case 'start':
113
            case 'since':
114
                $val = (int)$val;
115
                break;
116
            case 'uid': // irmtfan add multi topic poster
117
            case 'lastposter': // irmtfan add multi lastposter
118
                break;
119
            case 'status':
120
                // START irmtfan to accept multiple status
121
                $val = \is_array($val) ? $val : [$val];
122
                $val = \implode(',', $val);
123
                //$val = (in_array($val, array_keys($this->getStatus( $this->userlevel ))) ) ? $val : "all"; //irmtfan no need to check if status is empty or not
124
                //if ($val === "all" && !$this->is_multiple) $val = ""; irmtfan commented because it is done in sort
125
                // END irmtfan to accept multiple status
126
		$this->vars[$var] = $val;
127
                break;
128
            default:
129
                break;
130
        }
131
132
        return $val;
133
    }
134
135
    /**
136
     * @param array $vars
137
     */
138
    public function setVars(array $vars = []): void
139
    {
140
        $this->init();
141
142
        foreach ($vars as $var => $val) {
143
            if (!\in_array($var, $this->args, true)) {
144
                continue;
145
            }
146
        }
147
        $this->parseVars();
148
    }
149
150
    /**
151
     * @param string $hash request hash, i.e. get, post
152
     */
153
    public function setVarsFromRequest(string $hash = 'get'): void
154
    {
155
        $this->init();
156
157
        foreach ($this->args as $var) {
158
            if (Request::hasVar($var, $hash)) {
159
                continue;
160
            }
161
            switch ($var) {
162
                case 'forum':
163
                case 'status':
164
                  //  $this->setVar($var, Request::getArray($var, [], $hash));
165
			    $this->setVar('status', Request::getArray('status', [], $hash));
166
                    break;
167
                default:
168
                    $this->setVar($var, Request::getString($var, '', $hash));
169
                    break;
170
            }
171
        }
172
        $this->parseVars();
173
    }
174
175
    /**
176
     * @param string|null $status
177
     */
178
    public function myParseStatus(string $status = null): void
179
    {
180
        switch ($status) {
181
            case 'digest':
182
                $this->query['where'][] = 't.topic_digest = 1';
183
                break;
184
            case 'undigest':
185
                $this->query['where'][] = 't.topic_digest = 0';
186
                break;
187
            case 'sticky':
188
                $this->query['where'][] = 't.topic_sticky = 1';
189
                break;
190
            case 'unsticky':
191
                $this->query['where'][] = 't.topic_sticky = 0';
192
                break;
193
            case 'lock':
194
                $this->query['where'][] = 't.topic_status = 1';
195
                break;
196
            case 'unlock':
197
                $this->query['where'][] = 't.topic_status = 0';
198
                break;
199
            case 'poll':
200
                $this->query['where'][] = 't.topic_haspoll = 1';
201
                break;
202
            case 'unpoll':
203
                $this->query['where'][] = 't.topic_haspoll = 0';
204
                break;
205
            case 'voted':
206
                $this->query['where'][] = 't.votes > 0';
207
                break;
208
            case 'unvoted':
209
                $this->query['where'][] = 't.votes < 1';
210
                break;
211
            case 'replied':
212
                $this->query['where'][] = 't.topic_replies > 0';
213
                break;
214
            case 'unreplied':
215
                $this->query['where'][] = 't.topic_replies < 1';
216
                break;
217
            case 'viewed':
218
                $this->query['where'][] = 't.topic_views > 0';
219
                break;
220
            case 'unviewed':
221
                $this->query['where'][] = 't.topic_views < 1';
222
                break;
223
            case 'read':
224
                // Skip
225
                if (empty($this->config['read_mode'])) {
226
                    // Use database
227
                } elseif (2 == $this->config['read_mode']) {
228
                    // START irmtfan use read_uid to find the unread posts when the user is logged in
229
                    $read_uid = \is_object($GLOBALS['xoopsUser']) ? $GLOBALS['xoopsUser']->getVar('uid') : 0;
230
                    if (!empty($read_uid)) {
231
                        $this->query['join'][]  = 'LEFT JOIN ' . $this->handler->db->prefix('newbb_reads_topic') . ' AS r ON r.read_item = t.topic_id AND r.uid = ' . $read_uid . ' ';
232
                        $this->query['where'][] = 'r.post_id = t.topic_last_post_id';
233
                    }
234
235
                    // END irmtfan change criteria to get from uid p.uid = last post submit user id
236
                    // User cookie
237
                } elseif (1 == $this->config['read_mode']) {
238
                    // START irmtfan fix read_mode = 1 bugs - for all users (member and anon)
239
                    $startdate = !empty($this->vars['since']) ? (\time() - \newbbGetSinceTime($this->vars['since'])) : 0;
240
                    $lastvisit = \max($GLOBALS['last_visit'], $startdate);
241
                    if ($lastvisit) {
242
                        $readmode1query = '';
243
                        if ($lastvisit > $startdate) {
244
                            $readmode1query = 'p.post_time < ' . $lastvisit;
245
                        }
246
                        $topics         = [];
247
                        $topic_lastread = \newbbGetCookie('LT', true);
248
                        if ((is_countable($topic_lastread) ? \count($topic_lastread) : 0) > 0) {
0 ignored issues
show
Bug introduced by
It seems like $topic_lastread can also be of type string; however, parameter $value of count() does only seem to accept Countable|array, 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

248
                        if ((is_countable($topic_lastread) ? \count(/** @scrutinizer ignore-type */ $topic_lastread) : 0) > 0) {
Loading history...
249
                            foreach ($topic_lastread as $id => $time) {
250
                                if ($time > $lastvisit) {
251
                                    $topics[] = $id;
252
                                }
253
                            }
254
                        }
255
                        if (\count($topics) > 0) {
256
                            $topicquery = ' t.topic_id IN (' . \implode(',', $topics) . ')';
257
                            // because it should be OR
258
                            $readmode1query = ($readmode1query !== '' && $readmode1query !== '0') ? '(' . $readmode1query . ' OR ' . $topicquery . ')' : $topicquery;
259
                        }
260
                        $this->query['where'][] = $readmode1query;
261
                    }
262
                    // END irmtfan fix read_mode = 1 bugs - for all users (member and anon)
263
                }
264
                break;
265
            case 'unread':
266
                // Skip
267
                if (empty($this->config['read_mode'])) {
268
                    // Use database
269
                } elseif (2 == $this->config['read_mode']) {
270
                    // START irmtfan use read_uid to find the unread posts when the user is logged in
271
                    $read_uid = \is_object($GLOBALS['xoopsUser']) ? $GLOBALS['xoopsUser']->getVar('uid') : 0;
272
                    if (!empty($read_uid)) {
273
                        $this->query['join'][]  = 'LEFT JOIN ' . $this->handler->db->prefix('newbb_reads_topic') . ' AS r ON r.read_item = t.topic_id AND r.uid = ' . $read_uid . ' ';
274
                        $this->query['where'][] = '(r.read_id IS NULL OR r.post_id < t.topic_last_post_id)';
275
                    }
276
277
                    // END irmtfan change criteria to get from uid p.uid = last post submit user id
278
                    // User cookie
279
                } elseif (1 == $this->config['read_mode']) {
280
                    // START irmtfan fix read_mode = 1 bugs - for all users (member and anon)
281
                    $startdate = !empty($this->vars['since']) ? (\time() - \newbbGetSinceTime($this->vars['since'])) : 0;
282
                    $lastvisit = \max($GLOBALS['last_visit'], $startdate);
283
                    if ($lastvisit) {
284
                        if ($lastvisit > $startdate) {
285
                            $this->query['where'][] = 'p.post_time > ' . $lastvisit;
286
                        }
287
                        $topics         = [];
288
                        $topic_lastread = \newbbGetCookie('LT', true);
289
                        if ((is_countable($topic_lastread) ? \count($topic_lastread) : 0) > 0) {
290
                            foreach ($topic_lastread as $id => $time) {
291
                                if ($time > $lastvisit) {
292
                                    $topics[] = $id;
293
                                }
294
                            }
295
                        }
296
                        if (\count($topics) > 0) {
297
                            $this->query['where'][] = ' t.topic_id NOT IN (' . \implode(',', $topics) . ')';
298
                        }
299
                    }
300
                    // END irmtfan fix read_mode = 1 bugs - for all users (member and anon)
301
                }
302
                break;
303
            case 'pending':
304
                if ($this->userlevel < 2) {
305
                    $this->noperm = true;
306
                } else {
307
                    $this->query['where'][] = 't.approved = 0';
308
                }
309
                break;
310
            case 'deleted':
311
                if ($this->userlevel < 2) {
312
                    $this->noperm = true;
313
                } else {
314
                    $this->query['where'][] = 't.approved = -1';
315
                }
316
                break;
317
            case 'all': // For viewall.php; do not display sticky topics at first
318
            case 'active': // same as 'all'
319
                $this->query['where'][] = 't.approved = 1';
320
                break;
321
            default: // irmtfan do nothing
322
                break;
323
        }
324
    }
325
326
    /**
327
     * @param string $var
328
     * @param string|int|array|null $val
329
     */
330
    public function parseVar(string $var, $val): void
331
    {
332
        switch ($var) {
333
            case 'forum':
334
                /** @var ForumHandler $forumHandler */ $forumHandler = \XoopsModules\Newbb\Helper::getInstance()->getHandler('Forum');
335
                // START irmtfan - get forum Ids by values. parse positive values to forum IDs and negative values to category IDs. value=0 => all valid forums
336
                // Get accessible forums
337
                $accessForums = $forumHandler->getIdsByValues(\array_map('\intval', @\explode('|', (string)$val)));
338
                // Filter specified forums if any
339
                //if (!empty($val) && $_forums = @explode('|', $val)) {
340
                //$accessForums = array_intersect($accessForums, array_map('intval', $_forums));
341
                //}
342
                $this->vars['forum'] = $this->setVar('forum', $accessForums);
343
                // END irmtfan - get forum Ids by values. parse positive values to forum IDs and negative values to category IDs. value=0 => all valid forums
344
345
                if ($accessForums === []) {
346
                    $this->noperm = true;
347
                    // irmtfan - it just return return the forum_id only when the forum_id is the first allowed forum - no need for this code implode is enough removed.
348
                    //} elseif (count($accessForums) === 1) {
349
                    //$this->query["where"][] = "t.forum_id = " . $accessForums[0];
350
                } else {
351
                    $this->query['where'][] = 't.forum_id IN ( ' . \implode(', ', $accessForums) . ' )';
352
                }
353
                break;
354
            case 'uid': // irmtfan add multi topic poster
355
                if (-1 !== $val) {
356
                    $val                    = \implode(',', \array_map('\intval', \explode(',', $val)));
0 ignored issues
show
Bug introduced by
It seems like $val can also be of type array and null; however, parameter $string of explode() does only seem to accept 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

356
                    $val                    = \implode(',', \array_map('\intval', \explode(',', /** @scrutinizer ignore-type */ $val)));
Loading history...
357
                    $this->query['where'][] = 't.topic_poster IN ( ' . $val . ' )';
358
                }
359
                break;
360
            case 'lastposter': // irmtfan add multi lastposter
361
                if (-1 !== $val) {
362
                    $val                    = \implode(',', \array_map('\intval', \explode(',', $val)));
363
                    $this->query['where'][] = 'p.uid IN ( ' . $val . ' )';
364
                }
365
                break;
366
            case 'since':
367
                if (!empty($val)) {
368
                    // START irmtfan if unread && read_mode = 1 and last_visit > startdate do not add where query | to accept multiple status
369
                    $startdate = \time() - \newbbGetSinceTime($val);
370
                    if (\in_array('unread', \explode(',', (string) $this->vars['status']), true) && 1 == $this->config['read_mode']
371
                        && $GLOBALS['last_visit'] > $startdate) {
372
                        break;
373
                    }
374
                    // irmtfan digest_time | to accept multiple status
375
                    if (\in_array('digest', \explode(',', (string) $this->vars['status']), true)) {
376
                        $this->query['where'][] = 't.digest_time > ' . $startdate;
377
                    }
378
                    // irmtfan - should be >= instead of =
379
                    $this->query['where'][] = 'p.post_time >= ' . $startdate;
380
                    // END irmtfan if unread && read_mode = 1 and last_visit > startdate do not add where query
381
                }
382
                break;
383
            case 'type':
384
                if (!empty($val)) {
385
                    $this->query['where'][] = 't.type_id = ' . $val;
0 ignored issues
show
Bug introduced by
Are you sure $val of type array|integer|string can be used in concatenation? ( Ignorable by Annotation )

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

385
                    $this->query['where'][] = 't.type_id = ' . /** @scrutinizer ignore-type */ $val;
Loading history...
386
                }
387
                break;
388
            case 'status':
389
                // START irmtfan to accept multiple status
390
                $val = \explode(',', $val);
391
                // irmtfan - add 'all' to always parse t.approved = 1
392
                if (0 === \count(\array_intersect($val, ['all', 'active', 'pending', 'deleted']))) {
393
                    $val[] = 'all';
394
                }
395
                foreach ($val as $key => $status) {
396
                    $this->myParseStatus($status);
397
                }
398
                // END irmtfan to accept multiple status
399
                break;
400
            case 'sort':
401
                $sort = $this->getSort($val, 'sort');
0 ignored issues
show
Bug introduced by
It seems like $val can also be of type array; however, parameter $header of XoopsModules\Newbb\TopicRenderer::getSort() does only seem to accept null|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

401
                $sort = $this->getSort(/** @scrutinizer ignore-type */ $val, 'sort');
Loading history...
402
                if ($sort) {
403
                    $this->query['sort'][] = $sort . (empty($this->vars['order']) ? ' DESC' : ' ASC');
0 ignored issues
show
Bug introduced by
Are you sure $sort of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

403
                    $this->query['sort'][] = /** @scrutinizer ignore-type */ $sort . (empty($this->vars['order']) ? ' DESC' : ' ASC');
Loading history...
404
                } else { // irmtfan if sort is not in the list
405
                    $this->query['sort'][] = 't.topic_last_post_id' . (empty($this->vars['order']) ? ' DESC' : ' ASC');
406
                }
407
                break;
408
            default:
409
                break;
410
        }
411
    }
412
413
    /**
414
     * @return true
415
     */
416
    public function parseVars(): bool
417
    {
418
        static $parsed;
419
        // irmtfan - force to parse vars (run against static vars)
420
        if (null !== $parsed && !$this->force) {
421
            return true;
422
        }
423
424
        if (!isset($this->vars['forum'])) {
425
            $this->vars['forum'] = null;
426
        }
427
        //irmtfan parse status for rendering topic correctly - if empty($_GET(status)) it will show all topics include deleted and pendings. 'all' instead of all
428
        if (!isset($this->vars['status'])) {
429
            $this->vars['status'] = 'all';
430
        }
431
        // irmtfan if sort is not set or is empty get a default sort- if empty($_GET(sort)) | if sort=null eg: /list.topic.php?sort=
432
        if (empty($this->vars['sort'])) {
433
            $this->vars['sort'] = 'lastpost';
434
        } // use lastpost instead of sticky
435
436
        foreach ($this->vars as $var => $val) {
437
            $this->parseVar($var, $val);
438
            if (empty($val)) {
439
                unset($this->vars[$var]);
440
            }
441
        }
442
        $parsed = true;
443
444
        return true;
445
    }
446
447
    /**
448
     * @param string|null $header
449
     * @param string|null $var
450
     * @return array|string|null
451
     */
452
    public function getSort(string $header = null, string $var = null)
453
    {
454
        $headers = [
455
            'topic'           => [
456
                'title' => \_MD_NEWBB_TOPICS,
457
                'sort'  => 't.topic_title',
458
            ],
459
            'forum'           => [
460
                'title' => \_MD_NEWBB_FORUM,
461
                'sort'  => 't.forum_id',
462
            ],
463
            'poster'          => [
464
                'title' => \_MD_NEWBB_TOPICPOSTER, /*irmtfan _MD_NEWBB_POSTER to _MD_NEWBB_TOPICPOSTER*/
465
                'sort'  => 't.topic_poster',
466
            ],
467
            'replies'         => [
468
                'title' => \_MD_NEWBB_REPLIES,
469
                'sort'  => 't.topic_replies',
470
            ],
471
            'views'           => [
472
                'title' => \_MD_NEWBB_VIEWS,
473
                'sort'  => 't.topic_views',
474
            ],
475
            'lastpost'        => [ // irmtfan show topic_page_jump_icon smarty
476
                                   'title' => \_MD_NEWBB_LASTPOST,
477
                                   /*irmtfan _MD_NEWBB_DATE to _MD_NEWBB_LASTPOSTTIME again change to _MD_LASTPOST*/
478
                                   'sort'  => 't.topic_last_post_id',
479
            ],
480
            // START irmtfan add more sorts
481
            'lastposttime'    => [ // irmtfan same as lastpost
482
                                   'title' => \_MD_NEWBB_LASTPOSTTIME,
483
                                   'sort'  => 't.topic_last_post_id',
484
            ],
485
            'lastposter'      => [ // irmtfan
486
                                   'title' => \_MD_NEWBB_POSTER,
487
                                   'sort'  => 'p.uid', // poster uid
488
            ],
489
            'lastpostmsgicon' => [ // irmtfan
490
                                   'title' => \_MD_NEWBB_MESSAGEICON,
491
                                   'sort'  => 'p.icon', // post message icon
492
            ],
493
            'ratings'         => [
494
                'title' => \_MD_NEWBB_RATINGS,
495
                'sort'  => 't.rating', // irmtfan t.topic_rating to t.rating
496
            ],
497
            'votes'           => [
498
                'title' => \_MD_NEWBB_VOTES,
499
                'sort'  => 't.votes',
500
            ],
501
            'publish'         => [
502
                'title' => \_MD_NEWBB_TOPICTIME,
503
                'sort'  => 't.topic_id',
504
            ],
505
            'digest'          => [
506
                'title' => \_MD_NEWBB_DIGEST,
507
                'sort'  => 't.digest_time',
508
            ],
509
            'sticky'          => [
510
                'title' => \_MD_NEWBB_STICKY,
511
                'sort'  => 't.topic_sticky',
512
            ],
513
            'lock'            => [
514
                'title' => \_MD_NEWBB_LOCK,
515
                'sort'  => 't.topic_status',
516
            ],
517
            'poll'            => [
518
                'title' => \_MD_NEWBB_POLL_POLL,
519
                'sort'  => 't.poll_id',
520
            ],
521
        ];
522
        $types   = $this->getTypes();
523
        if (!empty($types)) {
524
            $headers['type'] = [
525
                'title' => \_MD_NEWBB_TYPE,
526
                'sort'  => 't.type_id',
527
            ];
528
        }
529
        if (2 === $this->userlevel) {
530
            $headers['approve'] = [
531
                'title' => \_MD_NEWBB_APPROVE,
532
                'sort'  => 't.approved',
533
            ];
534
        }
535
        // END irmtfan add more sorts
536
        if (empty($header) && empty($var)) {
537
            return $headers;
538
        }
539
        if (!empty($var) && !empty($header)) {
540
            return @$headers[$header][$var];
541
        }
542
        if (empty($var)) {
543
            return @$headers[$header];
544
        }
545
        $ret = null;
546
        foreach (\array_keys($headers) as $key) {
547
            $ret[$key] = @$headers[$key][$var];
548
        }
549
550
        return $ret;
551
    }
552
553
    // START irmtfan add Display topic headers function
554
    /**
555
     * @param string|null $header
556
     * @return array
557
     */
558
    public function getHeader(string $header = null): array
559
    {
560
        $headersSort = $this->getSort('', 'title');
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $headersSort is correct as $this->getSort('', 'title') targeting XoopsModules\Newbb\TopicRenderer::getSort() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
561
        // additional headers - important: those cannot be in sort anyway
562
        $headers = \array_merge(
563
            $headersSort,
0 ignored issues
show
Bug introduced by
$headersSort of type null is incompatible with the type array expected by parameter $arrays of array_merge(). ( Ignorable by Annotation )

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

563
            /** @scrutinizer ignore-type */ $headersSort,
Loading history...
564
            [
565
                'attachment' => \_MD_NEWBB_TOPICSHASATT, // show attachment smarty
566
                'read'       => \_MD_NEWBB_MARK_UNREAD . '|' . \_MD_NEWBB_MARK_READ, // read/unread show topic_folder smarty
567
                'pagenav'    => \_MD_NEWBB_PAGENAV_DISPLAY, // show topic_page_jump smarty - sort by topic_replies?
568
            ]
569
        );
570
571
        return $this->getFromKeys($headers, $header);
572
    }
573
574
    // END irmtfan add Display topic headers function
575
    /**
576
     * @param int|null     $type
577
     * @param null|string $status
578
     *
579
     * @return array
580
     */
581
    public function getStatus(int $type = null, string $status = null): array
582
    {
583
        $links       = [
584
            //""            => "", /* irmtfan remove empty array */
585
            'all'       => _ALL,
586
            'digest'    => \_MD_NEWBB_DIGEST,
587
            'undigest'  => \_MD_NEWBB_UNDIGEST, // irmtfan add
588
            'sticky'    => \_MD_NEWBB_STICKY, // irmtfan add
589
            'unsticky'  => \_MD_NEWBB_UNSTICKY, // irmtfan add
590
            'lock'      => \_MD_NEWBB_LOCK, // irmtfan add
591
            'unlock'    => \_MD_NEWBB_UNLOCK, // irmtfan add
592
            'poll'      => \_MD_NEWBB_TOPICHASPOLL, // irmtfan add
593
            'unpoll'    => \_MD_NEWBB_TOPICHASNOTPOLL, // irmtfan add
594
            'voted'     => \_MD_NEWBB_VOTED, // irmtfan add
595
            'unvoted'   => \_MD_NEWBB_UNVOTED, // irmtfan add
596
            'viewed'    => \_MD_NEWBB_VIEWED, // irmtfan add
597
            'unviewed'  => \_MD_NEWBB_UNVIEWED, // irmtfan add
598
            'replied'   => \_MD_NEWBB_REPLIED, // irmtfan add
599
            'unreplied' => \_MD_NEWBB_UNREPLIED,
600
            'read'      => \_MD_NEWBB_READ, // irmtfan add
601
            'unread'    => \_MD_NEWBB_UNREAD,
602
        ];
603
        $links_admin = [
604
            'active'  => \_MD_NEWBB_TYPE_ADMIN,
605
            'pending' => \_MD_NEWBB_TYPE_PENDING,
606
            'deleted' => \_MD_NEWBB_TYPE_DELETED,
607
        ];
608
609
        // all status, for admin
610
        if ($type > 1) {
611
            $links = \array_merge($links, $links_admin); // irmtfan to accept multiple status
612
        }
613
614
        return $this->getFromKeys($links, $status); // irmtfan to accept multiple status
615
    }
616
617
    /**
618
     * @param \Smarty $xoopsTpl
619
     * @throws \RuntimeException
620
     */
621
    public function buildSelection(\Smarty $xoopsTpl): void
622
    {
623
        $selection         = ['action' => $this->page];
624
        $selection['vars'] = $this->vars;
625
        require_once \dirname(__DIR__) . '/include/functions.forum.php';
626
        $forum_selected     = empty($this->vars['forum']) ? null : \explode('|', (string) @$this->vars['forum']);
627
        $selection['forum'] = '<select name="forum[]" multiple="multiple">';
628
        $selection['forum'] .= '<option value="0">' . \_MD_NEWBB_ALL . '</option>';
629
        $selection['forum'] .= \newbbForumSelectBox($forum_selected);
630
        $selection['forum'] .= '</select>';
631
632
        $sort_selected     = $this->vars['sort'];
633
        $sorts             = $this->getSort('', 'title');
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $sorts is correct as $this->getSort('', 'title') targeting XoopsModules\Newbb\TopicRenderer::getSort() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
634
        $selection['sort'] = "<select name='sort'>";
635
        if (!\is_array($sorts)) {
0 ignored issues
show
introduced by
The condition is_array($sorts) is always false.
Loading history...
636
            throw new \RuntimeException('$sorts must be an array.');
637
        }
638
        foreach ($sorts as $sort => $title) {
639
            $selection['sort'] .= "<option value='" . $sort . "' " . (($sort == $sort_selected) ? " selected='selected'" : '') . '>' . $title . '</option>';
640
        }
641
        $selection['sort'] .= '</select>';
642
643
        $selection['order'] = "<select name='order'>";
644
        $selection['order'] .= "<option value='0' " . (empty($this->vars['order']) ? " selected='selected'" : '') . '>' . _DESCENDING . '</option>';
645
        $selection['order'] .= "<option value='1' " . (!empty($this->vars['order']) ? " selected='selected'" : '') . '>' . _ASCENDING . '</option>';
646
        $selection['order'] .= '</select>';
647
648
        $since              = $this->vars['since'] ?? $this->config['since_default'];
649
        $selection['since'] = \newbbSinceSelectBox($since);
650
651
        $xoopsTpl->assign_by_ref('selection', $selection);
652
    }
653
654
    /**
655
     * @param \Smarty $xoopsTpl
656
     */
657
    public function buildSearch(\Smarty $xoopsTpl): void
658
    {
659
        $search             = [];
660
        $search['forum']    = @$this->vars['forum'];
661
        $search['since']    = @$this->vars['since'];
662
        $search['searchin'] = 'both';
663
664
        $xoopsTpl->assign_by_ref('search', $search);
665
    }
666
667
    /**
668
     * @param \Smarty $xoopsTpl
669
     * @throws \RuntimeException
670
     */
671
    public function buildHeaders(\Smarty $xoopsTpl): void
672
    {
673
        $headers_data = [];
674
        $args = [];
675
        foreach ($this->vars as $var => $val) {
676
            if ('sort' === $var || 'order' === $var) {
677
                continue;
678
            }
679
            $args[] = "{$var}={$val}";
680
        }
681
682
        $headers = $this->getSort('', 'title');
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $headers is correct as $this->getSort('', 'title') targeting XoopsModules\Newbb\TopicRenderer::getSort() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
683
        if (!\is_array($headers)) {
0 ignored issues
show
introduced by
The condition is_array($headers) is always false.
Loading history...
684
            throw new \RuntimeException('$headers must be an array.');
685
        }
686
        foreach ($headers as $header => $title) {
687
            $_args = ["sort={$header}"];
688
            if (@$this->vars['sort'] == $header) {
689
                $_args[] = 'order=' . ((@$this->vars['order'] + 1) % 2);
690
            }
691
            $headers_data[$header]['title'] = $title;
692
            $headers_data[$header]['link']  = $this->page . '?' . \implode('&amp;', \array_merge($args, $_args));
693
        }
694
        $xoopsTpl->assign_by_ref('headers', $headers_data);
695
    }
696
697
    /**
698
     * @param \Smarty $xoopsTpl
699
     */
700
    public function buildFilters(\Smarty $xoopsTpl): void
701
    {
702
        $args = [];
703
        foreach ($this->vars as $var => $val) {
704
            if ('status' === $var) {
705
                continue;
706
            }
707
            $args[] = "{$var}={$val}";
708
        }
709
710
        $links = $this->getStatus($this->userlevel);
711
712
        $status = [];
713
        foreach ($links as $link => $title) {
714
            $_args                  = ["status={$link}"];
715
            $status[$link]['title'] = $title;
716
            $status[$link]['link']  = $this->page . '?' . \implode('&amp;', [...$args, ...$_args]);
717
        }
718
        $xoopsTpl->assign_by_ref('filters', $status);
719
    }
720
721
    /**
722
     * @param int|null $type_id
723
     * @return mixed
724
     */
725
    public function getTypes(int $type_id = null)
726
    {
727
        static $types;
728
        if (!isset($types)) {
729
            /** @var TypeHandler $typeHandler */
730
            $typeHandler = Helper::getInstance()->getHandler('Type');
731
732
            $types = $typeHandler->getByForum(\explode('|', (string)@$this->vars['forum']));
733
        }
734
735
        if (($type_id === null || $type_id === 0)) {
736
            return $types;
737
        }
738
739
        return @$types[$type_id];
740
    }
741
742
    /**
743
     * @param \Smarty $xoopsTpl
744
     *
745
     * @return true
746
     */
747
    public function buildTypes(\Smarty $xoopsTpl): ?bool
748
    {
749
        $status = [];
750
        if (!$types = $this->getTypes()) {
751
            return true;
752
        }
753
754
        $args = [];
755
        foreach ($this->vars as $var => $val) {
756
            if ('type' === $var) {
757
                continue;
758
            }
759
            $args[] = "{$var}={$val}";
760
        }
761
762
        foreach ($types as $id => $type) {
763
            $_args                = ["type={$id}"];
764
            $status[$id]['title'] = $type['type_name'];
765
            $status[$id]['link']  = $this->page . '?' . \implode('&amp;', [...$args, ...$_args]);
766
        }
767
        $xoopsTpl->assign_by_ref('types', $status);
768
        return true;
769
    }
770
771
    /**
772
     * @param \Smarty $xoopsTpl
773
     *
774
     * @return true
775
     */
776
    public function buildCurrent(\Smarty $xoopsTpl): bool
777
    {
778
        if (empty($this->vars['status']) && !$this->is_multiple) {
779
            return true;
780
        }
781
782
        $args = [];
783
        foreach ($this->vars as $var => $val) {
784
            $args[] = "{$var}={$val}";
785
        }
786
787
        $status          = [];
788
        $status['title'] = \implode(',', $this->getStatus($this->userlevel, $this->vars['status'])); // irmtfan to accept multiple status
789
        //$status['link'] = $this->page.(empty($this->vars['status']) ? '' : '?status='.$this->vars['status']);
790
        $status['link'] = $this->page . ($args === [] ? '' : '?' . \implode('&amp;', $args));
791
792
        $xoopsTpl->assign_by_ref('current', $status);
793
        return true;
794
    }
795
796
    /**
797
     * @param \Smarty $xoopsTpl
798
     */
799
    public function buildPagenav(\Smarty $xoopsTpl): void
800
    {
801
        $count_topic = $this->getCount();
802
        if ($count_topic > $this->config['topics_per_page']) {
803
            $args = [];
804
            foreach ($this->vars as $var => $val) {
805
                if ('start' === $var) {
806
                    continue;
807
                }
808
                $args[] = "{$var}={$val}";
809
            }
810
            require_once $GLOBALS['xoops']->path('class/pagenav.php');
811
            $nav = new \XoopsPageNav($count_topic, $this->config['topics_per_page'], @$this->vars['start'], 'start', \implode('&amp;', $args));
812
            if (isset($GLOBALS['xoopsModuleConfig']['do_rewrite'])) {
813
                $nav->url = \formatURL(Request::getString('SERVER_NAME', '', 'SERVER')) . ' /' . $nav->url;
814
            }
815
            if ('select' === $this->config['pagenav_display']) {
816
                $navi = $nav->renderSelect();
817
            } elseif ('image' === $this->config['pagenav_display']) {
818
                $navi = $nav->renderImageNav(4);
819
            } else {
820
                $navi = $nav->renderNav(4);
821
            }
822
            $xoopsTpl->assign('pagenav', $navi);
823
        } else {
824
            $xoopsTpl->assign('pagenav', '');
825
        }
826
    }
827
828
    /**
829
     * @return int
830
     */
831
    public function getCount(): int
832
    {
833
        if ($this->noperm) {
834
            return 0;
835
        }
836
837
        $selects = [];
838
        $froms   = [];
839
        $joins   = [];
840
        $wheres  = [];
841
842
        // topic fields
843
        $selects[] = 'COUNT(*)';
844
845
        $froms[]  = $this->handler->db->prefix('newbb_topics') . ' AS t ';
846
        $joins[]  = 'LEFT JOIN ' . $this->handler->db->prefix('newbb_posts') . ' AS p ON p.post_id = t.topic_last_post_id';
847
        $wheres[] = '1 = 1';
848
849
        $sql = '    SELECT ' . \implode(', ', $selects) . '     FROM ' . \implode(', ', $froms) . '        ' . \implode(' ', $joins) . (!empty($this->query['join']) ? '        ' . \implode(' ', $this->query['join']) : '') . // irmtfan bug fix: Undefined index: join when post_excerpt = 0
850
               '     WHERE ' . \implode(' AND ', $wheres) . '        AND ' . @\implode(' AND ', @$this->query['where']);
851
852
        $result = $this->handler->db->query($sql);
853
        if (!$this->handler->db->isResultSet($result)) {
854
            //            \trigger_error("Query Failed! SQL: $sql- Error: " . $this->handler->db->error(), E_USER_ERROR);
855
            return 0;
856
        }
857
        [$count] = $this->handler->db->fetchRow($result);
858
859
        return (int)$count;
860
    }
861
862
    /**
863
     * @param \Smarty|null $xoopsTpl
864
     * @return array|void
865
     */
866
    public function renderTopics(\Smarty $xoopsTpl = null)
867
    {
868
        $myts = \MyTextSanitizer::getInstance(); // irmtfan Instanciate
869
870
        $ret = [];
871
        //$this->parseVars();
872
873
        if ($this->noperm) {
874
            if (\is_object($xoopsTpl)) {
875
                $xoopsTpl->assign_by_ref('topics', $ret);
876
877
                return;
878
            }
879
880
            return $ret;
881
        }
882
883
        $selects = [];
884
        $froms   = [];
885
        $joins   = [];
886
        $wheres  = [];
887
888
        // topic fields
889
        $selects[] = 't.*';
890
        // post fields
891
        $selects[] = 'p.post_time as last_post_time, p.poster_name as last_poster_name, p.icon, p.post_id, p.uid';
892
893
        $froms[]  = $this->handler->db->prefix('newbb_topics') . ' AS t ';
894
        $joins[]  = 'LEFT JOIN ' . $this->handler->db->prefix('newbb_posts') . ' AS p ON p.post_id = t.topic_last_post_id';
895
        $wheres[] = '1 = 1';
896
897
        if (!empty($this->config['post_excerpt'])) {
898
            $selects[]             = 'p.post_karma, p.require_reply, pt.post_text';
899
            $this->query['join'][] = 'LEFT JOIN ' . $this->handler->db->prefix('newbb_posts_text') . ' AS pt ON pt.post_id = t.topic_last_post_id';
900
        }
901
        //if (empty($this->query["sort"])) $this->query["sort"][] = 't.topic_last_post_id DESC'; // irmtfan commented no need
902
903
        $sql = '    SELECT ' . \implode(', ', $selects) . '     FROM ' . \implode(', ', $froms) . '        ' . \implode(' ', $joins) . (!empty($this->query['join']) ? '        ' . \implode(' ', $this->query['join']) : '') . // irmtfan bug fix: Undefined index join when post_excerpt = 0
904
               '     WHERE ' . \implode(' AND ', $wheres) . '        AND ' . @\implode(' AND ', @$this->query['where']) . '     ORDER BY ' . \implode(', ', $this->query['sort']);
905
906
        $result = $this->handler->db->query($sql, $this->config['topics_per_page'], @$this->vars['start']);
907
        if (!$this->handler->db->isResultSet($result)) {
908
            if (\is_object($xoopsTpl)) {
909
                $xoopsTpl->assign_by_ref('topics', $ret);
910
911
                return;
912
            }
913
914
            return $ret;
915
        }
916
917
        require_once \dirname(__DIR__) . '/include/functions.render.php';
918
        require_once \dirname(__DIR__) . '/include/functions.session.php';
919
        require_once \dirname(__DIR__) . '/include/functions.time.php';
920
        require_once \dirname(__DIR__) . '/include/functions.read.php';
921
        require_once \dirname(__DIR__) . '/include/functions.topic.php';
922
923
        $sticky    = 0;
924
        $topics    = [];
925
        $posters   = [];
926
        $reads     = [];
927
        $types     = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $types is dead and can be removed.
Loading history...
928
        $forums    = [];
929
        $anonymous = \htmlspecialchars((string)$GLOBALS['xoopsConfig']['anonymous'], \ENT_QUOTES | \ENT_HTML5);
930
931
        while (false !== ($myrow = $this->handler->db->fetchArray($result))) {
932
            if ($myrow['topic_sticky']) {
933
                ++$sticky;
934
            }
935
936
            // ------------------------------------------------------
937
            // START irmtfan remove topic_icon hardcode smarty
938
            // topic_icon: just regular topic_icon
939
            if (!empty($myrow['icon'])) {
940
                $topic_icon = '<img style="text-align:middle;" src="' . XOOPS_URL . '/images/subject/' . \htmlspecialchars((string)$myrow['icon'], \ENT_QUOTES | \ENT_HTML5) . '" alt="" >';
941
            } else {
942
                $topic_icon = '<img style="text-align:middle;" src="' . XOOPS_URL . '/images/icons/no_posticon.gif" alt="" >';
943
            }
944
            // END irmtfan remove topic_icon hardcode smarty
945
946
            // ------------------------------------------------------
947
            // rating_img
948
            $rating = \number_format($myrow['rating'] / 2, 0);
949
            // irmtfan - add alt key for rating
950
            if ($rating < 1) {
951
                $rating_img = \newbbDisplayImage('blank');
952
            } else {
953
                $rating_img = \newbbDisplayImage('rate' . $rating, \constant('_MD_NEWBB_RATE' . $rating));
954
            }
955
956
            // ------------------------------------------------------
957
            // topic_page_jump
958
            $topic_page_jump      = '';
959
            $topic_page_jump_icon = '';
0 ignored issues
show
Unused Code introduced by
The assignment to $topic_page_jump_icon is dead and can be removed.
Loading history...
960
            $totalpages           = \ceil(($myrow['topic_replies'] + 1) / $this->config['posts_per_page']);
961
            if ($totalpages > 1) {
962
                $topic_page_jump .= '&nbsp;&nbsp;';
963
                $append          = false;
964
                for ($i = 1; $i <= $totalpages; ++$i) {
965
                    if ($i > 3 && $i < $totalpages) {
966
                        if (!$append) {
967
                            $topic_page_jump .= '...';
968
                            $append          = true;
969
                        }
970
                    } else {
971
                        $topic_page_jump .= '[<a href="' . XOOPS_URL . '/modules/newbb/viewtopic.php?topic_id=' . $myrow['topic_id'] . '&amp;start=' . (($i - 1) * $this->config['posts_per_page']) . '">' . $i . '</a>]';
972
                        // irmtfan remove here and move
973
                        //$topic_page_jump_icon = "<a href='" . XOOPS_URL . "/modules/newbb/viewtopic.php?topic_id=" . $myrow['topic_id'] . "&amp;start=" . (($i - 1) * $this->config['posts_per_page']) . "" . "'>" . newbbDisplayImage('document',_MD_NEWBB_GOTOLASTPOST) . '</a>';
974
                    }
975
                }
976
            }
977
            // BigKev73 - Added to make jump ICON, jump and scroll to the correct "last post"
978
            $topic_page_jump_icon = "<a href='" . XOOPS_URL . '/modules/newbb/viewtopic.php?topic_id=' . $myrow['topic_id'] . '&amp;post_id=' . $myrow['topic_last_post_id'] . '#forumpost=' . $myrow['topic_last_post_id'] . "'>" . \newbbDisplayImage('lastposticon', \_MD_NEWBB_GOTOLASTPOST) . '</a>';
979
980
            // irmtfan - move here for both topics with and without pages - change topic_id to post_id
981
            //$topic_page_jump_icon = "<a href='" . XOOPS_URL . '/modules/newbb/viewtopic.php?post_id=' . $myrow['topic_last_post_id'] . '' . "'>" . newbbDisplayImage('lastposticon', _MD_NEWBB_GOTOLASTPOST) . '</a>';
982
983
            // ------------------------------------------------------
984
            // => topic array
985
986
            $topic_title = \htmlspecialchars((string)$myrow['topic_title'], \ENT_QUOTES | \ENT_HTML5);
987
            // irmtfan use topic_title_excerpt for block topic title length
988
            $topic_title_excerpt = $topic_title;
989
            if (!empty($this->config['topic_title_excerpt'])) {
990
                $topic_title_excerpt = \xoops_substr($topic_title, 0, $this->config['topic_title_excerpt']);
991
            }
992
            // irmtfan hardcode class commented
993
            //if ($myrow['topic_digest']) {
994
            //   $topic_title = "<span class='digest'>" . $topic_title . "</span>";
995
            //}
996
997
            if (empty($this->config['post_excerpt'])) {
998
                $topic_excerpt = '';
999
            } elseif (($myrow['post_karma'] > 0 || $myrow['require_reply'] > 0) && !\newbbIsAdmin($myrow['forum_id'])) {
1000
                $topic_excerpt = '';
1001
            } else {
1002
                $topic_excerpt = \xoops_substr(\newbbHtml2text($myts->displayTarea($myrow['post_text'])), 0, $this->config['post_excerpt']);
1003
                $topic_excerpt = \str_replace('[', '&#91;', \htmlspecialchars((string) $topic_excerpt, \ENT_QUOTES | \ENT_HTML5));
1004
            }
1005
1006
            $topics[$myrow['topic_id']] = [
1007
                'topic_id'               => $myrow['topic_id'],
1008
                'topic_icon'             => $topic_icon,
1009
                'type_id'                => $myrow['type_id'],
1010
                'topic_title_excerpt'    => $topic_title_excerpt,
1011
                //irmtfan use topic_title_excerpt
1012
                //'topic_link'    => XOOPS_URL . '/modules/newbb/viewtopic.php?topic_id=' . $myrow['topic_id'], // . '&amp;forum=' . $myrow['forum_id'], // irmtfan comment
1013
                'topic_link'             => 'viewtopic.php?topic_id=' . $myrow['topic_id'],
1014
                // irmtfan remove hardcode link
1015
                'rating_img'             => $rating_img,
1016
                'votes'                  => $myrow['votes'],
1017
                //irmtfan added
1018
                'topic_page_jump'        => $topic_page_jump,
1019
                'topic_page_jump_icon'   => $topic_page_jump_icon,
1020
                'topic_replies'          => $myrow['topic_replies'],
1021
                'topic_poster_uid'       => $myrow['topic_poster'],
1022
                'topic_poster_name'      => !empty($myrow['poster_name']) ? \htmlspecialchars((string)$myrow['poster_name'], \ENT_QUOTES | \ENT_HTML5) : $anonymous,
1023
                'topic_views'            => $myrow['topic_views'],
1024
                'topic_time'             => \newbbFormatTimestamp((int)$myrow['topic_time']),
1025
                'topic_last_post_id'     => $myrow['topic_last_post_id'],
1026
                //irmtfan added
1027
                'topic_last_posttime'    => \newbbFormatTimestamp((int)$myrow['last_post_time']),
1028
                'topic_last_poster_uid'  => $myrow['uid'],
1029
                'topic_last_poster_name' => !empty($myrow['last_poster_name']) ? \htmlspecialchars((string)$myrow['last_poster_name'], \ENT_QUOTES | \ENT_HTML5) : $anonymous,
1030
                'topic_forum'            => $myrow['forum_id'],
1031
                'topic_excerpt'          => $topic_excerpt,
1032
                'sticky'                 => $myrow['topic_sticky'] ? \newbbDisplayImage('topic_sticky', \_MD_NEWBB_TOPICSTICKY) : '',
1033
                // irmtfan bug fixed
1034
                'lock'                   => $myrow['topic_status'] ? \newbbDisplayImage('topic_locked', \_MD_NEWBB_TOPICLOCK) : '',
1035
                //irmtfan added
1036
                'digest'                 => $myrow['topic_digest'] ? \newbbDisplayImage('topic_digest', \_MD_NEWBB_TOPICDIGEST) : '',
1037
                //irmtfan added
1038
                'poll'                   => $myrow['topic_haspoll'] ? \newbbDisplayImage('poll', \_MD_NEWBB_TOPICHASPOLL) : '',
1039
                //irmtfan added
1040
                'approve'                => $myrow['approved'],
1041
                //irmtfan added
1042
            ];
1043
1044
            /* users */
1045
            $posters[$myrow['topic_poster']] = 1;
1046
            $posters[$myrow['uid']]          = 1;
1047
            // reads
1048
            if (!empty($this->config['read_mode'])) {
1049
                $reads[$myrow['topic_id']] = (1 == $this->config['read_mode']) ? $myrow['last_post_time'] : $myrow['topic_last_post_id'];
1050
            }
1051
            // types
1052
            if (!empty($myrow['type_id'])) {
1053
                //$types[$myrow['type_id']] = 1;
1054
            }
1055
            // forums
1056
            $forums[$myrow['forum_id']] = 1;
1057
        }
1058
        $posters_name = \newbbGetUnameFromIds(\array_keys($posters), (bool)$this->config['show_realname'], true);
1059
        $topic_isRead = \newbbIsRead('topic', $reads);
1060
        /*
1061
        $type_list = [];
1062
        if (count($types) > 0) {
1063
            $typeHandler =  Newbb\Helper::getInstance()->getHandler('Type');
1064
            $type_list = $typeHandler->getAll(new \Criteria("type_id", "(".implode(", ", array_keys($types)).")", "IN"), null, false);
1065
        }
1066
        */
1067
        $type_list = $this->getTypes();
1068
        /** @var ForumHandler $forumHandler */
1069
        $forumHandler = Helper::getInstance()->getHandler('Forum');
1070
1071
        if (\count($forums) > 0) {
1072
            $forum_list = $forumHandler->getAll(new \Criteria('forum_id', '(' . \implode(', ', \array_keys($forums)) . ')', 'IN'), ['forum_name', 'hot_threshold'], false);
1073
        } else {
1074
            $forum_list = $forumHandler->getAll();
1075
        }
1076
1077
        foreach (\array_keys($topics) as $id) {
1078
            $topics[$id]['topic_read']       = empty($topic_isRead[$id]) ? 0 : 1; // add topic-read/topic-new smarty variable
1079
            $topics[$id]['topic_forum_link'] = '<a href="' . XOOPS_URL . '/modules/newbb/viewforum.php?forum=' . $topics[$id]['topic_forum'] . '">' . $forum_list[$topics[$id]['topic_forum']]['forum_name'] . '</a>';
1080
1081
            //irmtfan use topic_title_excerpt -- add else
1082
            if (!empty($topics[$id]['type_id']) && isset($type_list[$topics[$id]['type_id']])) {
1083
                $topics[$id]['topic_title'] = \getTopicTitle($topics[$id]['topic_title_excerpt'], $type_list[$topics[$id]['type_id']]['type_name'], $type_list[$topics[$id]['type_id']]['type_color']);
1084
            } else {
1085
                $topics[$id]['topic_title'] = $topics[$id]['topic_title_excerpt'];
1086
            }
1087
            $topics[$id]['topic_poster']      = !empty($posters_name[$topics[$id]['topic_poster_uid']]) ? $posters_name[$topics[$id]['topic_poster_uid']] : $topics[$id]['topic_poster_name'];
1088
            $topics[$id]['topic_last_poster'] = !empty($posters_name[$topics[$id]['topic_last_poster_uid']]) ? $posters_name[$topics[$id]['topic_last_poster_uid']] : $topics[$id]['topic_last_poster_name'];
1089
            // ------------------------------------------------------
1090
            // START irmtfan remove hardcodes from topic_folder smarty
1091
            // topic_folder: priority: newhot -> hot/new -> regular
1092
            //list($topic_status, $topic_digest, $topic_replies) = $topics[$id]["stats"]; irmtfan
1093
            // START irmtfan - add topic_folder_text for alt
1094
            //if ($topics[$id]["lock"] === 1) {
1095
            //    $topic_folder = 'topic_locked';
1096
            //    $topic_folder_text = _MD_NEWBB_TOPICLOCKED;
1097
            //} else {
1098
            //if ($topic_digest) {
1099
            //    $topic_folder = 'topic_digest';
1100
            //    $topic_folder_text = _MD_NEWBB_TOPICDIGEST;
1101
            if ($topics[$id]['topic_replies'] >= $forum_list[$topics[$id]['topic_forum']]['hot_threshold']) {
1102
                $topic_folder      = empty($topic_isRead[$id]) ? 'topic_hot_new' : 'topic_hot';
1103
                $topic_folder_text = empty($topic_isRead[$id]) ? \_MD_NEWBB_MORETHAN : \_MD_NEWBB_MORETHAN2;
1104
            } else {
1105
                $topic_folder      = empty($topic_isRead[$id]) ? 'topic_new' : 'topic';
1106
                $topic_folder_text = empty($topic_isRead[$id]) ? \_MD_NEWBB_NEWPOSTS : \_MD_NEWBB_NONEWPOSTS;
1107
            }
1108
            //}
1109
            // END irmtfan remove hardcodes from topic_folder smarty
1110
            $topics[$id]['topic_folder'] = \newbbDisplayImage($topic_folder, $topic_folder_text);
1111
            // END irmtfan - add topic_folder_text for alt
1112
1113
            unset($topics[$id]['topic_poster_name'], $topics[$id]['topic_last_poster_name']); // irmtfan remove $topics[$id]["stats"] because it is not exist now
1114
        }
1115
1116
        if (\count($topics) > 0) {
1117
            $sql    = ' SELECT DISTINCT topic_id FROM ' . $this->handler->db->prefix('newbb_posts') . " WHERE attachment != ''" . ' AND topic_id IN (' . \implode(',', \array_keys($topics)) . ')';
1118
            $result = $this->handler->db->query($sql);
1119
            if ($this->handler->db->isResultSet($result)) {
1120
                while ([$topic_id] = $this->handler->db->fetchRow($result)) {
1121
                    $topics[$topic_id]['attachment'] = '&nbsp;' . \newbbDisplayImage('attachment', \_MD_NEWBB_TOPICSHASATT);
1122
                }
1123
            }
1124
        }
1125
1126
        if (\is_object($xoopsTpl)) {
1127
            $xoopsTpl->assign_by_ref('sticky', $sticky);
1128
            $xoopsTpl->assign_by_ref('topics', $topics);
1129
1130
            return;
1131
        }
1132
1133
        return [$topics, $sticky];
1134
    }
1135
1136
    // START irmtfan to create an array from selected keys of an array
1137
    /**
1138
     * @param array       $array
1139
     * @param array|string|null   $keys
1140
     * @return array
1141
     */
1142
    public function getFromKeys(array $array, $keys = null): array
1143
    {
1144
        if (empty($keys)) {
1145
            return $array;
1146
        } // all keys
1147
        $keyarr = \is_string($keys) ? \explode(',', $keys) : $keys;
1148
        $keyarr = \array_intersect(\array_keys($array), $keyarr); // keys should be in array
1149
        $ret    = [];
1150
        foreach ($keyarr as $key) {
1151
            $ret[$key] = $array[$key];
1152
        }
1153
1154
        return $ret;
1155
    }
1156
    // END irmtfan to create an array from selected keys of an array
1157
}
1158