TopicHandler   F
last analyzed

Complexity

Total Complexity 96

Size/Duplication

Total Lines 596
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 263
c 2
b 0
f 0
dl 0
loc 596
rs 2
wmc 96

21 Methods

Rating   Name   Duplication   Size   Complexity  
A get() 0 17 6
A __construct() 0 3 1
B insert() 0 19 7
A getNextPostId() 0 12 2
A showTreeItem() 0 25 5
A getTopPost() 0 22 2
A getPermission() 0 23 6
B getByMove() 0 19 7
A approve() 0 23 4
B findPollModule() 0 41 10
A getByPost() 0 15 2
A getPostCount() 0 20 3
A getActivePolls() 0 12 3
A cleanOrphan() 0 7 1
A delete() 0 19 6
B synchronization() 0 36 10
A getPostTree() 0 10 1
B getAllPosts() 0 51 10
A cleanExpires() 0 15 4
A getAllPosters() 0 15 4
A getTopPostId() 0 12 2

How to fix   Complexity   

Complex Class

Complex classes like TopicHandler 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 TopicHandler, 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 XoopsModules\Newbb\{
15
    Topic
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, XoopsModules\Newbb\Topic. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
16
};
17
use XoopsModules\Tag\{
18
    Helper as TagHelper
19
};
20
21
\defined('NEWBB_FUNCTIONS_INI') || require $GLOBALS['xoops']->path('modules/newbb/include/functions.ini.php');
22
23
/**
24
 * Class TopicHandler
25
 */
26
final class TopicHandler extends \XoopsPersistableObjectHandler
27
{
28
    /**
29
     * @param \XoopsDatabase|null $db
30
     */
31
    public function __construct(\XoopsDatabase $db = null)
32
    {
33
        parent::__construct($db, 'newbb_topics', Topic::class, 'topic_id', 'topic_title');
34
    }
35
36
    /**
37
     * @param mixed $id ID
38
     * @param null|array $fields  fields to fetch
39
     * @return mixed|null XoopsObject
40
     */
41
    public function get($id = null, $fields = null) //get($id, $var = null)
42
    {
43
        $var  = $fields;
44
        $ret  = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $ret is dead and can be removed.
Loading history...
45
        $tags = $var;
46
        if (!empty($var) && \is_string($var)) {
0 ignored issues
show
introduced by
The condition is_string($var) is always false.
Loading history...
47
            $tags = [$var];
48
        }
49
        if (!$topicObject = parent::get($id, $tags)) {
50
            return null;
51
        }
52
        $ret = $topicObject;
53
        if (!empty($var) && \is_string($var)) {
0 ignored issues
show
introduced by
The condition is_string($var) is always false.
Loading history...
54
            $ret = @$topicObject->getVar($var);
55
        }
56
57
        return $ret;
58
    }
59
60
    /**
61
     * insert an object into the database
62
     *
63
     * @param  \XoopsObject $object {@link \XoopsObject} reference to object
64
     * @param  bool        $force  flag to force the query execution despite security settings
65
     * @return mixed       object ID
66
     */
67
    public function insert(\XoopsObject $object, $force = true)
68
    {
69
        $topic = $object;
70
        if (!$topic->getVar('topic_time')) {
71
            $topic->setVar('topic_time', \time());
72
        }
73
        if (!parent::insert($topic, $force) || !$topic->getVar('approved')) {
74
            return $topic->getVar('topic_id');
75
        }
76
77
        $newbbConfig = \newbbLoadConfig();
78
        if (!empty($newbbConfig['do_tag']) && \class_exists('XoopsModules\Tag\FormTag')) {
79
            $tagHandler = TagHelper::getInstance()->getHandler('Tag');
80
            if ($tagHandler) {
0 ignored issues
show
introduced by
$tagHandler is of type XoopsModules\Tag\TagHandler, thus it always evaluated to true.
Loading history...
81
                $tagHandler->updateByItem($topic->getVar('topic_tags', 'n'), $topic->getVar('topic_id'), 'newbb');
82
            }
83
        }
84
85
        return $topic->getVar('topic_id');
86
    }
87
88
    /**
89
     * @param object|Topic $object
90
     * @param bool  $force
91
     * @return bool
92
     */
93
    public function approve(object $object, bool $force = false): bool
94
    {
95
        $topic_id = $object->getVar('topic_id');
96
        if ($force) {
97
            $sql = 'UPDATE ' . $this->db->prefix('newbb_topics') . " SET approved = -1 WHERE topic_id = {$topic_id}";
98
        } else {
99
            $sql = 'UPDATE ' . $this->db->prefix('newbb_topics') . " SET approved = 1 WHERE topic_id = {$topic_id}";
100
        }
101
        if (!$result = $this->db->queryF($sql)) {
0 ignored issues
show
Unused Code introduced by
The assignment to $result is dead and can be removed.
Loading history...
102
            //xoops_error($this->db->error());
103
            return false;
104
        }
105
        $postHandler = Helper::getInstance()->getHandler('Post');
106
        $postsObject = $postHandler->getAll(new \Criteria('topic_id', $topic_id));
107
        foreach (\array_keys($postsObject) as $post_id) {
108
            $postHandler->approve($postsObject[$post_id]);
109
        }
110
        unset($postsObject);
111
        /** @var \XoopsModules\Newbb\StatsHandler $statsHandler */
112
        $statsHandler = Helper::getInstance()->getHandler('Stats');
113
        $statsHandler->update($object->getVar('forum_id'), 'topic');
114
115
        return true;
116
    }
117
118
    /**
119
     * get previous/next topic
120
     *
121
     * @param int $topic_id     current topic ID
122
     * @param int $action
123
     *                          <ul>
124
     *                          <li> -1: previous </li>
125
     *                          <li> 0: current </li>
126
     *                          <li> 1: next </li>
127
     *                          </ul>
128
     * @param int $forum_id     the scope for moving
129
     *                          <ul>
130
     *                          <li> >0 : inside the forum </li>
131
     *                          <li> <= 0: global </li>
132
     *                          </ul>
133
     * @return \XoopsObject|null
134
     */
135
    public function &getByMove(int $topic_id, int $action, int $forum_id = 0)
136
    {
137
        $topic = null;
138
        if (!empty($action)) {
139
            $sql    = 'SELECT * FROM ' . $this->table . ' WHERE 1=1' . (($forum_id > 0) ? ' AND forum_id=' . (int)$forum_id : '') . ' AND topic_id ' . (($action > 0) ? '>' : '<') . (int)$topic_id . ' ORDER BY topic_id ' . (($action > 0) ? 'ASC' : 'DESC') . ' LIMIT 1';
140
            $result = $this->db->query($sql);
141
            if ($this->db->isResultSet($result)) {
142
                $row = $this->db->fetchArray($result);
143
                if ($row) {
144
                    $topic = $this->create(false);
145
                    $topic->assignVars($row);
146
147
                    return $topic;
148
                }
149
            }
150
        }
151
        $topic = $this->get($topic_id);
152
153
        return $topic;
154
    }
155
156
    /**
157
     * @param int $post_id
158
     * @return null|\XoopsObject
159
     */
160
    public function &getByPost(int $post_id): ?\XoopsObject
161
    {
162
        $topic  = null;
163
        $sql    = 'SELECT t.* FROM ' . $this->db->prefix('newbb_topics') . ' t, ' . $this->db->prefix('newbb_posts') . ' p
164
                WHERE t.topic_id = p.topic_id AND p.post_id = ' . (int)$post_id;
165
        $result = $this->db->query($sql);
166
        if (!$this->db->isResultSet($result)) {
167
            //xoops_error($this->db->error());
168
            return $topic;
169
        }
170
        $row   = $this->db->fetchArray($result);
171
        $topic = $this->create(false);
172
        $topic->assignVars($row);
173
174
        return $topic;
175
    }
176
177
    /**
178
     * @param Topic  $topic
179
     * @param string $type
180
     * @return int
181
     */
182
    public function getPostCount(Topic $topic, string $type = ''): int
183
    {
184
        switch ($type) {
185
            case 'pending':
186
                $approved = 0;
187
                break;
188
            case 'deleted':
189
                $approved = -1;
190
                break;
191
            default:
192
                $approved = 1;
193
                break;
194
        }
195
        $criteria = new \CriteriaCompo(new \Criteria('topic_id', $topic->getVar('topic_id')));
0 ignored issues
show
Bug introduced by
It seems like $topic->getVar('topic_id') can also be of type array and array; however, parameter $value of Criteria::__construct() 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

195
        $criteria = new \CriteriaCompo(new \Criteria('topic_id', /** @scrutinizer ignore-type */ $topic->getVar('topic_id')));
Loading history...
196
        $criteria->add(new \Criteria('approved', $approved));
197
        /** @var PostHandler $postHandler */
198
        $postHandler = Helper::getInstance()->getHandler('Post');
199
        $count       = $postHandler->getCount($criteria);
200
201
        return $count;
202
    }
203
204
    /**
205
     * @param int $topic_id
206
     * @return null|Post
207
     */
208
    public function &getTopPost(int $topic_id): ?Post
209
    {
210
        $post = null;
211
        $sql  = 'SELECT p.*, t.* FROM ' . $this->db->prefix('newbb_posts') . ' p,
212
            ' . $this->db->prefix('newbb_posts_text') . ' t
213
            WHERE
214
            p.topic_id = ' . $topic_id . ' AND p.pid = 0
215
            AND t.post_id = p.post_id';
216
217
        $result = $this->db->query($sql);
218
        if (!$this->db->isResultSet($result)) {
219
            //xoops_error($this->db->error());
220
            return $post;
221
        }
222
        /** @var PostHandler $postHandler */
223
        $postHandler = Helper::getInstance()->getHandler('Post');
224
        $myrow       = $this->db->fetchArray($result);
225
        /** @var Post $post */
226
        $post = $postHandler->create(false);
227
        $post->assignVars($myrow);
228
229
        return $post;
230
    }
231
232
    /**
233
     * @param int $topic_id
234
     * @return bool|int
235
     */
236
    public function getTopPostId(int $topic_id)
237
    {
238
        $sql    = 'SELECT MIN(post_id) AS post_id FROM ' . $this->db->prefix('newbb_posts') . ' WHERE topic_id = ' . $topic_id . ' AND pid = 0';
239
        $result = $this->db->query($sql);
240
        if (!$this->db->isResultSet($result)) {
241
//            \trigger_error("Query Failed! SQL: $sql- Error: " . $xoopsDB->error(), E_USER_ERROR);
242
            //xoops_error($this->db->error());
243
            return false;
244
        }
245
        [$post_id] = $this->db->fetchRow($result);
246
247
        return $post_id;
248
    }
249
250
    //Added by BigKev to get the next unread post ID based on the $lastreadpost_id
251
    /**
252
     * @param int $topic_id
253
     * @param int $lastreadpost_id
254
     * @return false|mixed
255
     */
256
    public function getNextPostId(int $topic_id, int $lastreadpost_id)
257
    {
258
        $sql    = 'SELECT MIN(post_id) AS post_id FROM ' . $this->db->prefix('newbb_posts') . ' WHERE topic_id = ' . $topic_id . ' AND post_id > ' . $lastreadpost_id . ' ORDER BY post_id LIMIT 1';
259
        $result = $this->db->query($sql);
260
        if (!$this->db->isResultSet($result)) {
261
            //            \trigger_error("Query Failed! SQL: $sql- Error: " . $xoopsDB->error(), E_USER_ERROR);
262
            //xoops_error($this->db->error());
263
            return false;
264
        }
265
        [$post_id] = $this->db->fetchRow($result);
266
267
        return $post_id;
268
    }
269
270
    /**
271
     * @param Topic  $topic
272
     * @param string $order
273
     * @param int    $perpage
274
     * @param int    $start
275
     * @param int    $post_id
276
     * @param string $type
277
     * @return array
278
     */
279
    public function &getAllPosts(Topic $topic, string $order = 'ASC', int $perpage = 10, int &$start = 0, int $post_id = 0, string $type = ''): array
280
    {
281
        $ret     = [];
282
        $perpage = ((int)$perpage > 0) ? (int)$perpage : (empty($GLOBALS['xoopsModuleConfig']['posts_per_page']) ? 10 : $GLOBALS['xoopsModuleConfig']['posts_per_page']);
283
        $start   = (int)$start;
284
        switch ($type) {
285
            case 'pending':
286
                $approveCriteria = ' AND p.approved = 0';
287
                break;
288
            case 'deleted':
289
                $approveCriteria = ' AND p.approved = -1';
290
                break;
291
            default:
292
                $approveCriteria = ' AND p.approved = 1';
293
                break;
294
        }
295
296
        if ($post_id) {
297
            if ('DESC' === $order) {
298
                $operator_for_position = '>';
299
            } else {
300
                $order                 = 'ASC';
301
                $operator_for_position = '<';
302
            }
303
            //$approveCriteria = ' AND approved = 1'; // any others?
304
            $sql    = 'SELECT COUNT(*) FROM ' . $this->db->prefix('newbb_posts') . ' AS p WHERE p.topic_id=' . (int)$topic->getVar('topic_id') . $approveCriteria . " AND p.post_id $operator_for_position $post_id";
305
            $result = $this->db->query($sql);
306
            if (!$this->db->isResultSet($result)) {
307
                //            \trigger_error("Query Failed! SQL: $sql- Error: " . $xoopsDB->error(), E_USER_ERROR);
308
                //xoops_error($this->db->error());
309
                return $ret;
310
            }
311
            [$position] = $this->db->fetchRow($result);
312
            $start = (int)($position / $perpage) * $perpage;
313
        }
314
315
        $sql    = 'SELECT p.*, t.* FROM ' . $this->db->prefix('newbb_posts') . ' p, ' . $this->db->prefix('newbb_posts_text') . ' t WHERE p.topic_id=' . $topic->getVar('topic_id') . ' AND p.post_id = t.post_id' . $approveCriteria . " ORDER BY p.post_id $order";
316
        $result = $this->db->query($sql, $perpage, $start);
317
        if (!$this->db->isResultSet($result)) {
318
            //xoops_error($this->db->error());
319
            return $ret;
320
        }
321
        $postHandler = Helper::getInstance()->getHandler('Post');
322
        while (false !== ($myrow = $this->db->fetchArray($result))) {
323
            $post = $postHandler->create(false);
324
            $post->assignVars($myrow);
325
            $ret[$myrow['post_id']] = $post;
326
            unset($post);
327
        }
328
329
        return $ret;
330
    }
331
332
    /**
333
     * @param array $postArray
334
     * @param int   $pid
335
     * @return mixed
336
     */
337
    public function &getPostTree(array $postArray, int $pid = 0)
338
    {
339
        $postsArray = null;
340
        //        require_once $GLOBALS['xoops']->path('modules/newbb/class/Tree.php');
341
        $newbbTree = new Tree('newbb_posts');
342
        $newbbTree->setPrefix('&nbsp;&nbsp;');
343
        $newbbTree->setPostArray($postArray);
344
        $newbbTree->getPostTree($postsArray, $pid);
345
346
        return $postsArray;
347
    }
348
349
    /**
350
     * @param Topic $topic
351
     * @param array $postArray
352
     * @return array
353
     */
354
    public function showTreeItem(Topic $topic, array &$postArray): array
355
    {
356
        global $viewtopic_users, $myts;
357
358
        $postArray['post_time'] = \newbbFormatTimestamp($postArray['post_time']);
359
360
        if (!empty($postArray['icon'])) {
361
            $postArray['icon'] = '<img src="' . XOOPS_URL . '/images/subject/' . \htmlspecialchars((string)$postArray['icon'], \ENT_QUOTES | \ENT_HTML5) . '" alt="" >';
362
        } else {
363
            $postArray['icon'] = '<a name="' . $postArray['post_id'] . '"><img src="' . XOOPS_URL . '/images/icons/no_posticon.gif" alt="" ></a>';
364
        }
365
366
        $postArray['subject'] = '<a href="viewtopic.php?viewmode=thread&amp;topic_id=' . $topic->getVar('topic_id') . '&amp;forum=' . $postArray['forum_id'] . '&amp;post_id=' . $postArray['post_id'] . '">' . $postArray['subject'] . '</a>';
367
368
        $isActiveUser = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $isActiveUser is dead and can be removed.
Loading history...
369
        if (isset($viewtopic_users[$postArray['uid']]['name'])) {
370
            $postArray['poster'] = $viewtopic_users[$postArray['uid']]['name'];
371
            if ($postArray['uid'] > 0) {
372
                $postArray['poster'] = '<a href="' . XOOPS_URL . '/userinfo.php?uid=' . $postArray['uid'] . '">' . $viewtopic_users[$postArray['uid']]['name'] . '</a>';
373
            }
374
        } else {
375
            $postArray['poster'] = empty($postArray['poster_name']) ? \htmlspecialchars((string)$GLOBALS['xoopsConfig']['anonymous'], \ENT_QUOTES | \ENT_HTML5) : $postArray['poster_name'];
376
        }
377
378
        return $postArray;
379
    }
380
381
    /**
382
     * @param Topic $topic
383
     * @param bool  $isApproved
384
     * @return array
385
     */
386
    public function getAllPosters(Topic $topic, bool $isApproved = true): array
387
    {
388
        $ret = [];
389
        $sql = 'SELECT DISTINCT uid FROM ' . $this->db->prefix('newbb_posts') . '  WHERE topic_id=' . $topic->getVar('topic_id') . ' AND uid>0';
390
        if ($isApproved) {
391
            $sql .= ' AND approved = 1';
392
        }
393
        $result = $this->db->query($sql);
394
        if ($this->db->isResultSet($result)) {
395
            while (false !== ($myrow = $this->db->fetchArray($result))) {
396
                $ret[] = $myrow['uid'];
397
            }
398
        }
399
400
        return $ret;
401
    }
402
403
    /**
404
     * @param \XoopsObject $object Topic
405
     * @param bool               $force
406
     * @return bool
407
     */
408
    public function delete(\XoopsObject $object, $force = true): bool
409
    {
410
        $topic = $object;
411
        $topicId = \is_object($topic) ? $topic->getVar('topic_id') : (int)$topic;
412
        if (empty($topicId)) {
413
            return false;
414
        }
415
        $postObject = $this->getTopPost($topicId);
416
        /** @var PostHandler $postHandler */
417
        $postHandler = Helper::getInstance()->getHandler('Post');
418
        $postHandler->myDelete($postObject, false, $force);
0 ignored issues
show
Bug introduced by
It seems like $postObject can also be of type null; however, parameter $post of XoopsModules\Newbb\PostHandler::myDelete() does only seem to accept XoopsModules\Newbb\Post, 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

418
        $postHandler->myDelete(/** @scrutinizer ignore-type */ $postObject, false, $force);
Loading history...
419
420
        $newbbConfig = \newbbLoadConfig();
421
        /** @var \XoopsModules\Tag\TagHandler $tagHandler */
422
        if (!empty($newbbConfig['do_tag']) && \class_exists('TagFormTag') && $tagHandler = TagHelper::getInstance()->getHandler('Tag')) { //@xoops_getModuleHandler('tag', 'tag', true)) {
423
            $tagHandler->updateByItem([], $topicId, 'newbb');
424
        }
425
426
        return true;
427
    }
428
429
    // get permission
430
    // parameter: $type: 'post', 'view',  'reply', 'edit', 'delete', 'addpoll', 'vote', 'attach'
431
    // $gperm_names = "'forum_can_post', 'forum_can_view', 'forum_can_reply', 'forum_can_edit', 'forum_can_delete', 'forum_can_addpoll', 'forum_can_vote', 'forum_can_attach', 'forum_can_noapprove'";
432
433
    /**
434
     * @param int|Forum $forum
435
     * @param int|null  $topic_locked
436
     * @param string    $type
437
     * @return bool
438
     */
439
    public function getPermission($forum, ?int $topic_locked = null, string $type = 'view'): bool
440
    {
441
        $topic_locked ??= 0;
442
        static $_cachedTopicPerms;
443
        require_once \dirname(__DIR__) . '/include/functions.user.php';
444
        if (\newbbIsAdmin($forum)) {
445
            return true;
446
        }
447
448
        $forum_id = \is_object($forum) ? $forum->getVar('forum_id') : (int)$forum;
449
        if ($forum_id < 1) {
450
            return false;
451
        }
452
453
        if ($topic_locked && 'view' !== $type) {
454
            $permission = false;
455
        } else {
456
            /** var PermissionHandler $permHandler */
457
            $permHandler = Helper::getInstance()->getHandler('Permission');
458
            $permission  = $permHandler->getPermission('forum', $type, $forum_id);
459
        }
460
461
        return $permission;
462
    }
463
464
    /**
465
     * clean orphan items from database
466
     *
467
     * @param string $table_link
468
     * @param string $field_link
469
     * @param string $field_object
470
     * @return bool   true on success
471
     */
472
    public function cleanOrphan($table_link = '', $field_link = '', $field_object = ''): bool //cleanOrphan()
473
    {
474
        $this->deleteAll(new \Criteria('topic_time', '0'), true, true);
475
        parent::cleanOrphan($this->db->prefix('newbb_forums'), 'forum_id');
476
        parent::cleanOrphan($this->db->prefix('newbb_posts'), 'topic_id');
477
478
        return true;
479
    }
480
481
    /**
482
     * clean expired objects from database
483
     *
484
     * @param int $expire time limit for expiration
485
     * @return bool true on success
486
     */
487
    public function cleanExpires(int $expire = 0): bool
488
    {
489
        // irmtfan if 0 no cleanup look include/plugin.php
490
        if (!\func_num_args()) {
491
            $newbbConfig = \newbbLoadConfig();
492
            $expire      = isset($newbbConfig['pending_expire']) ? (int)$newbbConfig['pending_expire'] : 7;
493
            $expire      *= 24 * 3600; // days to seconds
494
        }
495
        if (empty($expire)) {
496
            return false;
497
        }
498
        $crit_expire = new \CriteriaCompo(new \Criteria('approved', '0', '<='));
499
        $crit_expire->add(new \Criteria('topic_time', \time() - (int)$expire, '<'));
500
501
        return $this->deleteAll($crit_expire, true/*, true*/);
502
    }
503
504
    // START irmtfan - rewrite topic synchronization function. add pid sync and remove hard-code db access
505
    /**
506
     * @param mixed $object
507
     * @param bool                         $force
508
     * @return bool
509
     */
510
    public function synchronization($object = null, bool $force = true): bool
511
    {
512
        if (!\is_object($object)) {
513
            $object = $this->get((int)$object);
514
        }
515
        if (!\is_object($object) || !$object->getVar('topic_id')) {
516
            return false;
517
        }
518
519
        /** @var PostHandler $postHandler */
520
        $postHandler = Helper::getInstance()->getHandler('Post');
521
        $criteria    = new \CriteriaCompo();
522
        $criteria->add(new \Criteria('topic_id', (string)$object->getVar('topic_id')), 'AND');
523
        $criteria->add(new \Criteria('approved', '1'), 'AND');
524
        $post_ids = $postHandler->getIds($criteria);
525
        if (empty($post_ids)) {
526
            return false;
527
        }
528
        $last_post     = \max($post_ids);
529
        $top_post      = \min($post_ids);
530
        $topic_replies = (is_countable($post_ids) ? \count($post_ids) : 0) - 1;
531
        if ($object->getVar('topic_last_post_id') != $last_post) {
532
            $object->setVar('topic_last_post_id', $last_post);
533
        }
534
        if ($object->getVar('topic_replies') != $topic_replies) {
535
            $object->setVar('topic_replies', $topic_replies);
536
        }
537
        $b1 = $this->insert($object, $force);
538
        $criteria->add(new \Criteria('post_id', $top_post, '<>'), 'AND');
539
        $criteria->add(new \Criteria('pid', '(' . \implode(', ', $post_ids) . ')', 'NOT IN'), 'AND');
540
        $b2       = $postHandler->updateAll('pid', $top_post, $criteria, $force);
541
        $criteria = new \CriteriaCompo();
542
        $criteria->add(new \Criteria('post_id', $top_post, '='), 'AND');
543
        $b3 = $postHandler->updateAll('pid', 0, $criteria, $force);
544
545
        return ($b1 && $b2 && $b3);
546
    }
547
548
    // END irmtfan - rewrite topic synchronization function. add pid sync and remove hard-code db access
549
    // START irmtfan getActivePolls
550
551
    /**
552
     * get all active poll modules in the current xoops installtion.
553
     * @return array $pollDirs = array($dirname1=>$dirname1, $dirname2=>$dirname2, ...) dirnames of all active poll modules
554
     */
555
    public function getActivePolls(): array
556
    {
557
        $pollDirs = [];
558
        $allDirs  = \xoops_getActiveModules();
559
        foreach ($allDirs as $dirname) {
560
            // pollresults.php file is exist in all xoopspoll versions and umfrage versions
561
            if (\file_exists($GLOBALS['xoops']->path('modules/' . $dirname . '/pollresults.php'))) {
562
                $pollDirs[$dirname] = $dirname;
563
            }
564
        }
565
566
        return $pollDirs;
567
    }
568
569
    // END irmtfan getActivePolls
570
571
    // START irmtfan findPollModule
572
573
    /**
574
     * find poll module that is in used in the current newbb installtion.
575
     * @param array $pollDirs  dirnames of all active poll modules
576
     * @return bool|string | true | false
577
     *                         $dir_def: dirname of poll module that is in used in the current newbb installtion.
578
     *                         true: no poll module is installed | newbb has no topic with poll | newbb has no topic
579
     *                         false: errors (see below xoops_errors)
580
     */
581
    public function findPollModule(array $pollDirs = [])
582
    {
583
        $dir_def = '';
584
        if (empty($pollDirs)) {
585
            $pollDirs = $this->getActivePolls();
586
        }
587
        if (empty($pollDirs)) {
588
            return true;
589
        }
590
        // if only one active poll module still we need to check!!!
591
        //if(count($pollDirs) === 1) return end($pollDirs);
592
        $topicPollObjs = $this->getAll(new \Criteria('topic_haspoll', '1'), ['topic_id', 'poll_id']);
593
        if (empty($topicPollObjs)) {
594
            return true;
595
        } // no poll or no topic!!!
596
        foreach ($topicPollObjs as $tObj) {
597
            $poll_idInMod = 0;
598
            foreach ($pollDirs as $dirname) {
599
                $pollObj = $tObj->getPoll($tObj->getVar('poll_id'), $dirname);
600
                if (\is_object($pollObj) && ($pollObj->getVar('poll_id') == $tObj->getVar('poll_id'))) {
601
                    ++$poll_idInMod;
602
                    $dir_def = $dirname;
603
                }
604
            }
605
            // Only one poll module should has this poll_id
606
            // if 0 there is an error
607
            if (0 == $poll_idInMod) {
608
                \xoops_error("Error: Cannot find poll module for poll_id='{$tObj->getVar('poll_id')}'");
609
610
                return false;
611
            }
612
            // if 1 => $dir_def is correct
613
            if (1 == $poll_idInMod) {
614
                return $dir_def;
615
            }
616
            // if more than 1 continue
617
        }
618
        // if there is some topics but no module or more than one module have polls
619
        \xoops_error(\_MD_NEWBB_ERROR_POLL_MODULE_NOT_FOUND);
620
621
        return false;
622
    }
623
    // END irmtfan findPollModule
624
}
625