StatsHandler::getInstance()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace XoopsModules\Newbb;
4
5
/**
6
 * NewBB 5.0x,  the forum module for XOOPS project
7
 *
8
 * @copyright      XOOPS Project (https://xoops.org)
9
 * @license        GNU GPL 2 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
 * @package        module::newbb
13
 */
14
15
16
17
\defined('NEWBB_FUNCTIONS_INI') || require __DIR__ . '/functions.ini.php';
18
19
\define('NEWBB_STATS_TYPE_TOPIC', 1);
20
\define('NEWBB_STATS_TYPE_POST', 2);
21
\define('NEWBB_STATS_TYPE_DIGEST', 3);
22
\define('NEWBB_STATS_TYPE_VIEW', 4);
23
24
\define('NEWBB_STATS_PERIOD_TOTAL', 1);
25
\define('NEWBB_STATS_PERIOD_DAY', 2);
26
\define('NEWBB_STATS_PERIOD_WEEK', 3);
27
\define('NEWBB_STATS_PERIOD_MONTH', 4);
28
29
/**
30
 * Stats for forum
31
 */
32
class StatsHandler
33
{
34
    public $db;
35
    public $table;
36
    public $param = [
37
        'type'   => ['topic', 'post', 'digest', 'view'],
38
        'period' => ['total', 'day', 'week', 'month'],
39
    ];
40
41
    /**
42
     * @param null|\XoopsDatabase $db
43
     */
44
    public function __construct(\XoopsDatabase $db = null)
0 ignored issues
show
Unused Code introduced by
The parameter $db is not used and could be removed. ( Ignorable by Annotation )

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

44
    public function __construct(/** @scrutinizer ignore-unused */ \XoopsDatabase $db = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
45
    {
46
        //$this->db = $db;
47
        //if (!$db || !($db instanceof \XoopsDatabase)) {
48
        $this->db = $GLOBALS['xoopsDB'];
49
        //}
50
        $this->table = $this->db->prefix('newbb_stats');
51
    }
52
53
    /**
54
     * @param null|\XoopsDatabase $db
55
     * @return StatsHandler
56
     */
57
    public static function getInstance(\XoopsDatabase $db = null)
58
    {
59
        static $instance;
60
        if (null === $instance) {
61
            $instance = new static($db);
62
        }
63
64
        return $instance;
65
    }
66
67
    /**
68
     * @param       $id
69
     * @param       $type
70
     * @param int   $increment
71
     * @return bool
72
     */
73
    public function update($id, $type, $increment = 1)
74
    {
75
        $id        = (int)$id;
76
        $increment = (int)$increment;
77
78
        if (empty($increment) || false === ($type = \array_search($type, $this->param['type'], true))) {
79
            return false;
80
        }
81
82
        $sql    = "    UPDATE {$this->table}"
83
                  . '    SET stats_value = CASE '
84
                  . "                    WHEN time_format = '' OR DATE_FORMAT(time_update, time_format) = DATE_FORMAT(NOW(), time_format)  THEN stats_value + '{$increment}' "
85
                  . "                    ELSE '{$increment}' "
86
                  . '                END, '
87
                  . '        time_update = NOW()'
88
                  . '    WHERE '
89
                  . "        (stats_id = '0' OR stats_id = '{$id}') "
90
                  . "        AND stats_type='{$type}' ";
91
        $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...
92
        $rows   = $this->db->getAffectedRows();
93
        if (0 == $rows) {
94
            $sql    = "    INSERT INTO {$this->table}"
95
                      . '        (`stats_id`, `stats_value`, `stats_type`, `stats_period`, `time_update`, `time_format`) '
96
                      . '    VALUES '
97
                      . "        ('0', '{$increment}', '{$type}', '"
98
                      . \array_search('total', $this->param['period'], true)
0 ignored issues
show
Bug introduced by
Are you sure array_search('total', $t...>param['period'], true) of type false|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

98
                      . /** @scrutinizer ignore-type */ \array_search('total', $this->param['period'], true)
Loading history...
99
                      . "', NOW(), ''), "
100
                      . "        ('0', '{$increment}', '{$type}', '"
101
                      . \array_search('day', $this->param['period'], true)
0 ignored issues
show
Bug introduced by
Are you sure array_search('day', $this->param['period'], true) of type false|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

101
                      . /** @scrutinizer ignore-type */ \array_search('day', $this->param['period'], true)
Loading history...
102
                      . "', NOW(), '%Y%j'), "
103
                      . "        ('0', '{$increment}', '{$type}', '"
104
                      . \array_search('week', $this->param['period'], true)
0 ignored issues
show
Bug introduced by
Are you sure array_search('week', $th...>param['period'], true) of type false|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

104
                      . /** @scrutinizer ignore-type */ \array_search('week', $this->param['period'], true)
Loading history...
105
                      . "', NOW(), '%Y%u'), "
106
                      . "        ('0', '{$increment}', '{$type}', '"
107
                      . \array_search('month', $this->param['period'], true)
0 ignored issues
show
Bug introduced by
Are you sure array_search('month', $t...>param['period'], true) of type false|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

107
                      . /** @scrutinizer ignore-type */ \array_search('month', $this->param['period'], true)
Loading history...
108
                      . "', NOW(), '%Y%m')";
109
            $result = $this->db->queryF($sql);
110
        }
111
        if ($rows < 2 * \count($this->param['period']) && !empty($id)) {
112
            $sql    = "    INSERT INTO {$this->table}"
113
                      . '        (`stats_id`, `stats_value`, `stats_type`, `stats_period`, `time_update`, `time_format`) '
114
                      . '    VALUES '
115
                      . "        ('{$id}', '{$increment}', '{$type}', '"
116
                      . \array_search('total', $this->param['period'], true)
117
                      . "', NOW(), ''), "
118
                      . "        ('{$id}', '{$increment}', '{$type}', '"
119
                      . \array_search('day', $this->param['period'], true)
120
                      . "', NOW(), '%Y%j'), "
121
                      . "        ('{$id}', '{$increment}', '{$type}', '"
122
                      . \array_search('week', $this->param['period'], true)
123
                      . "', NOW(), '%Y%u'), "
124
                      . "        ('{$id}', '{$increment}', '{$type}', '"
125
                      . \array_search('month', $this->param['period'], true)
126
                      . "', NOW(), '%Y%m')";
127
            $result = $this->db->queryF($sql);
128
        }
129
    }
130
131
    /**
132
     * Get stats of "Today"
133
     *
134
     * @param array $ids     ID of forum: > 0, forum; 0 - global; empty - all
135
     * @param array $types   type of stats items: 1 - topic; 2 - post; 3 - digest; 4 - click; empty - all
136
     * @param array $periods time period: 1 - all time; 2 - today; 3 - this week; 4 - this month; empty - all
137
     * @return array
138
     */
139
    public function getStats(array $ids, array $types = [], array $periods = [])
140
    {
141
        $ret = [];
142
143
        $_types = [];
144
        foreach ($types as $type) {
145
            $_types[] = \array_search($type, $this->param['type'], true);
146
        }
147
        $_periods = [];
148
        foreach ($periods as $period) {
149
            $_periods[] = \array_search($period, $this->param['period'], true);
150
        }
151
        $sql    = '    SELECT stats_id, stats_value, stats_type, stats_period ' . "    FROM {$this->table} " . '    WHERE ' . "        ( time_format = '' OR DATE_FORMAT(time_update, time_format) = DATE_FORMAT(NOW(), time_format) ) " . '        ' . (empty($ids) ? '' : 'AND stats_id IN (' . \implode(
152
                    ', ',
153
                    \array_map(
154
                        '\intval',
155
                        $ids
156
                    )
157
                ) . ')') . '        ' . (empty($_types) ? '' : 'AND stats_type IN (' . \implode(', ', $_types) . ')') . '        ' . (empty($_periods) ? '' : 'AND stats_period IN (' . \implode(', ', $_periods) . ')');
158
        $result = $this->db->query($sql);
159
160
        while (false !== ($row = $this->db->fetchArray($result))) {
161
            $ret[(string)$row['stats_id']][$this->param['type'][$row['stats_type']]][$this->param['period'][$row['stats_period']]] = $row['stats_value'];
162
        }
163
164
        return $ret;
165
    }
166
167
    public function reset()
168
    {
169
        $this->db->queryF('TRUNCATE TABLE ' . $this->table);
170
        $now        = \time();
171
        $time_start = [
172
            'day'   => '%Y%j',
173
            'week'  => '%Y%u',
174
            'month' => '%Y%m',
175
        ];
176
        $counts     = [];
177
178
        $sql = '    SELECT forum_id' . '    FROM ' . $this->db->prefix('newbb_forums');
179
        $ret = $this->db->query($sql);
180
        while (list($forum_id) = $this->db->fetchRow($ret)) {
181
            $sql    = '    SELECT COUNT(*), SUM(topic_views)' . '    FROM ' . $this->db->prefix('newbb_topics') . "    WHERE approved=1 AND forum_id = {$forum_id}";
182
            $result = $this->db->query($sql);
183
            [$topics, $views] = $this->db->fetchRow($result);
184
            $this->update($forum_id, 'topic', $topics);
185
            $this->update($forum_id, 'view', $views);
186
187
            $sql    = '    SELECT COUNT(*)' . '    FROM ' . $this->db->prefix('newbb_topics') . "    WHERE approved=1 AND topic_digest >0 AND forum_id = {$forum_id}";
188
            $result = $this->db->query($sql);
189
            [$digests] = $this->db->fetchRow($result);
190
            $this->update($forum_id, 'digest', $digests);
191
192
            $sql    = '    SELECT COUNT(*)' . '    FROM ' . $this->db->prefix('newbb_posts') . "    WHERE approved=1 AND forum_id = {$forum_id}";
193
            $result = $this->db->query($sql);
194
            [$posts] = $this->db->fetchRow($result);
195
            $this->update($forum_id, 'post', $posts);
196
197
            foreach ($time_start as $period => $format) {
198
                $sql    = '    SELECT COUNT(*), SUM(topic_views)' . '    FROM ' . $this->db->prefix('newbb_topics') . "    WHERE approved=1 AND forum_id = {$forum_id}" . "        AND FROM_UNIXTIME(topic_time, '{$format}') >= FROM_UNIXTIME({$now}, '{$format}')";
199
                $result = $this->db->query($sql);
200
                [$topics, $views] = $this->db->fetchRow($result);
201
                $views = empty($views) ? 0 : $views; // null check
202
                $this->db->queryF(
203
                    "    INSERT INTO {$this->table}" . '        (`stats_id`, `stats_value`, `stats_type`, `stats_period`, `time_update`, `time_format`) ' . '    VALUES ' . "        ('{$forum_id}', '{$topics}', '" . \array_search('topic', $this->param['type'], true) . "', '" . \array_search(
0 ignored issues
show
Bug introduced by
Are you sure array_search($period, $t...>param['period'], true) of type false|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

203
                    "    INSERT INTO {$this->table}" . '        (`stats_id`, `stats_value`, `stats_type`, `stats_period`, `time_update`, `time_format`) ' . '    VALUES ' . "        ('{$forum_id}', '{$topics}', '" . \array_search('topic', $this->param['type'], true) . "', '" . /** @scrutinizer ignore-type */ \array_search(
Loading history...
Bug introduced by
Are you sure array_search('topic', $this->param['type'], true) of type false|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

203
                    "    INSERT INTO {$this->table}" . '        (`stats_id`, `stats_value`, `stats_type`, `stats_period`, `time_update`, `time_format`) ' . '    VALUES ' . "        ('{$forum_id}', '{$topics}', '" . /** @scrutinizer ignore-type */ \array_search('topic', $this->param['type'], true) . "', '" . \array_search(
Loading history...
204
                        $period,
205
                        $this->param['period'],
206
                        true
207
                    ) . "', NOW(), '{$format}')"
208
                );
209
                $this->db->queryF(
210
                    "    INSERT INTO {$this->table}" . '        (`stats_id`, `stats_value`, `stats_type`, `stats_period`, `time_update`, `time_format`) ' . '    VALUES ' . "        ('{$forum_id}', '{$views}', '" . \array_search('view', $this->param['type'], true) . "', '" . \array_search(
0 ignored issues
show
Bug introduced by
Are you sure array_search('view', $this->param['type'], true) of type false|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

210
                    "    INSERT INTO {$this->table}" . '        (`stats_id`, `stats_value`, `stats_type`, `stats_period`, `time_update`, `time_format`) ' . '    VALUES ' . "        ('{$forum_id}', '{$views}', '" . /** @scrutinizer ignore-type */ \array_search('view', $this->param['type'], true) . "', '" . \array_search(
Loading history...
211
                        $period,
212
                        $this->param['period'],
213
                        true
214
                    ) . "', NOW(), '{$format}')"
215
                );
216
                @$counts['topic'][$period] += $topics;
217
                @$counts['view'][$period] += $views;
218
219
                $sql    = '    SELECT COUNT(*)' . '    FROM ' . $this->db->prefix('newbb_topics') . "    WHERE approved=1 AND topic_digest >0 AND forum_id = {$forum_id}" . "        AND FROM_UNIXTIME(digest_time, '{$format}') >= FROM_UNIXTIME({$now}, '{$format}')";
220
                $result = $this->db->query($sql);
221
                [$digests] = $this->db->fetchRow($result);
222
                $this->db->queryF(
223
                    "    INSERT INTO {$this->table}" . '        (`stats_id`, `stats_value`, `stats_type`, `stats_period`, `time_update`, `time_format`) ' . '    VALUES ' . "        ('{$forum_id}', '{$digests}', '" . \array_search('digest', $this->param['type'], true) . "', '" . \array_search(
0 ignored issues
show
Bug introduced by
Are you sure array_search('digest', $...s->param['type'], true) of type false|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

223
                    "    INSERT INTO {$this->table}" . '        (`stats_id`, `stats_value`, `stats_type`, `stats_period`, `time_update`, `time_format`) ' . '    VALUES ' . "        ('{$forum_id}', '{$digests}', '" . /** @scrutinizer ignore-type */ \array_search('digest', $this->param['type'], true) . "', '" . \array_search(
Loading history...
224
                        $period,
225
                        $this->param['period'],
226
                        true
227
                    ) . "', NOW(), '{$format}')"
228
                );
229
                @$counts['digest'][$period] += $digests;
230
231
                $sql    = '    SELECT COUNT(*)' . '    FROM ' . $this->db->prefix('newbb_posts') . "    WHERE approved=1 AND forum_id = {$forum_id}" . "        AND FROM_UNIXTIME(post_time, '{$format}') >= FROM_UNIXTIME({$now}, '{$format}')";
232
                $result = $this->db->query($sql);
233
                [$posts] = $this->db->fetchRow($result);
234
                $this->db->queryF(
235
                    "    INSERT INTO {$this->table}" . '        (`stats_id`, `stats_value`, `stats_type`, `stats_period`, `time_update`, `time_format`) ' . '    VALUES ' . "        ('{$forum_id}', '{$posts}', '" . \array_search('post', $this->param['type'], true) . "', '" . \array_search(
0 ignored issues
show
Bug introduced by
Are you sure array_search('post', $this->param['type'], true) of type false|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

235
                    "    INSERT INTO {$this->table}" . '        (`stats_id`, `stats_value`, `stats_type`, `stats_period`, `time_update`, `time_format`) ' . '    VALUES ' . "        ('{$forum_id}', '{$posts}', '" . /** @scrutinizer ignore-type */ \array_search('post', $this->param['type'], true) . "', '" . \array_search(
Loading history...
236
                        $period,
237
                        $this->param['period'],
238
                        true
239
                    ) . "', NOW(), '{$format}')"
240
                );
241
                @$counts['post'][$period] += $posts;
242
            }
243
        }
244
245
        $this->db->queryF("    DELETE FROM {$this->table}" . "    WHERE stats_id = '0' AND stats_period <> " . \array_search('total', $this->param['period'], true));
0 ignored issues
show
Bug introduced by
Are you sure array_search('total', $t...>param['period'], true) of type false|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

245
        $this->db->queryF("    DELETE FROM {$this->table}" . "    WHERE stats_id = '0' AND stats_period <> " . /** @scrutinizer ignore-type */ \array_search('total', $this->param['period'], true));
Loading history...
246
        foreach ($time_start as $period => $format) {
247
            foreach (\array_keys($counts) as $type) {
248
                $this->db->queryF(
249
                    "    INSERT INTO {$this->table}" . '        (`stats_id`, `stats_value`, `stats_type`, `stats_period`, `time_update`, `time_format`) ' . '    VALUES ' . "        ('0', '{$counts[$type][$period]}', '" . \array_search($type, $this->param['type'], true) . "', '" . \array_search(
0 ignored issues
show
Bug introduced by
Are you sure array_search($type, $this->param['type'], true) of type false|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

249
                    "    INSERT INTO {$this->table}" . '        (`stats_id`, `stats_value`, `stats_type`, `stats_period`, `time_update`, `time_format`) ' . '    VALUES ' . "        ('0', '{$counts[$type][$period]}', '" . /** @scrutinizer ignore-type */ \array_search($type, $this->param['type'], true) . "', '" . \array_search(
Loading history...
250
                        $period,
251
                        $this->param['period'],
252
                        true
253
                    ) . "', NOW(), '{$format}')"
254
                );
255
            }
256
        }
257
    }
258
}
259