|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/** |
|
4
|
|
|
* This file contains a class to collect the data needed to |
|
5
|
|
|
* show a list of boards for the board index and the message index. |
|
6
|
|
|
* |
|
7
|
|
|
* @package ElkArte Forum |
|
8
|
|
|
* @copyright ElkArte Forum contributors |
|
9
|
|
|
* @license BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file) |
|
10
|
|
|
* |
|
11
|
|
|
* This file contains code covered by: |
|
12
|
|
|
* copyright: 2011 Simple Machines (http://www.simplemachines.org) |
|
13
|
|
|
* |
|
14
|
|
|
* @version 2.0 Beta 1 |
|
15
|
|
|
* |
|
16
|
|
|
*/ |
|
17
|
|
|
|
|
18
|
|
|
namespace ElkArte; |
|
19
|
|
|
|
|
20
|
|
|
use BBC\ParserWrapper; |
|
21
|
|
|
use ElkArte\Cache\Cache; |
|
22
|
|
|
use ElkArte\Database\QueryInterface; |
|
23
|
|
|
use ElkArte\Helper\Util; |
|
24
|
|
|
|
|
25
|
|
|
/** |
|
26
|
|
|
* This class fetches all the stuff needed to build a list of boards |
|
27
|
|
|
*/ |
|
28
|
|
|
class BoardsList |
|
29
|
|
|
{ |
|
30
|
|
|
/** @var array All the options */ |
|
31
|
|
|
private $_options; |
|
32
|
|
|
|
|
33
|
|
|
/** @var array Some data regarding the current user */ |
|
34
|
|
|
private $_user; |
|
35
|
|
|
|
|
36
|
|
|
/** @var array Holds the info about the latest post of the series */ |
|
37
|
|
|
private $_latest_post = []; |
|
38
|
|
|
|
|
39
|
|
|
/** @var int[] Remembers boards to easily scan the array to add moderators later */ |
|
40
|
|
|
private $_boards = []; |
|
41
|
|
|
|
|
42
|
|
|
/** @var array An array containing all the data of the categories and boards requested */ |
|
43
|
|
|
private $_categories = []; |
|
44
|
|
|
|
|
45
|
|
|
/** @var array The category/board that is being processed "now" */ |
|
46
|
|
|
private $_current_boards = []; |
|
47
|
|
|
|
|
48
|
|
|
/** @var string The url where to find images */ |
|
49
|
|
|
private $_images_url; |
|
50
|
|
|
|
|
51
|
|
|
/** @var int Cut the subject at this number of chars, set from modSettings */ |
|
52
|
|
|
private $_subject_length = 48; |
|
53
|
|
|
|
|
54
|
|
|
/** @var int The id of the recycle board (0 for none or not enabled) */ |
|
55
|
|
|
private $_recycle_board = 0; |
|
56
|
|
|
|
|
57
|
|
|
/** @var QueryInterface The database! */ |
|
58
|
|
|
private $_db; |
|
59
|
|
|
|
|
60
|
|
|
/** |
|
61
|
|
|
* Initialize the class |
|
62
|
|
|
* |
|
63
|
|
|
* @param array $options - Available options and corresponding defaults are: |
|
64
|
|
|
* - 'include_categories' => false |
|
65
|
|
|
* - 'countChildPosts' => false |
|
66
|
|
|
* - 'base_level' => false |
|
67
|
|
|
* - 'parent_id' => 0 |
|
68
|
|
|
* - 'set_latest_post' => false |
|
69
|
|
|
* - 'get_moderators' => true |
|
70
|
|
|
*/ |
|
71
|
|
|
public function __construct($options) |
|
72
|
|
|
{ |
|
73
|
|
|
global $settings, $context, $modSettings; |
|
74
|
|
|
|
|
75
|
|
|
$this->_options = array_merge([ |
|
76
|
|
|
'include_categories' => false, |
|
77
|
|
|
'countChildPosts' => false, |
|
78
|
|
|
'base_level' => 0, |
|
79
|
|
|
'parent_id' => 0, |
|
80
|
|
|
'set_latest_post' => false, |
|
81
|
|
|
'get_moderators' => true, |
|
82
|
|
|
], $options); |
|
83
|
|
|
|
|
84
|
|
|
$this->_options['avatars_on_indexes'] = !empty($settings['avatars_on_indexes']) && $settings['avatars_on_indexes'] !== 2; |
|
85
|
|
|
$this->_images_url = $settings['images_url'] . '/' . $context['theme_variant_url']; |
|
86
|
|
|
|
|
87
|
|
|
if (!empty($modSettings['subject_length'])) |
|
88
|
|
|
{ |
|
89
|
|
|
$this->_subject_length = $modSettings['subject_length']; |
|
90
|
|
|
} |
|
91
|
|
|
|
|
92
|
|
|
$this->_user = User::$info; |
|
|
|
|
|
|
93
|
|
|
$this->_user['mod_cache_ap'] = empty($this->_user->mod_cache['ap']) ? [] : $this->_user->mod_cache['ap']; |
|
|
|
|
|
|
94
|
|
|
|
|
95
|
|
|
$this->_db = database(); |
|
96
|
|
|
|
|
97
|
|
|
// Start with an empty array. |
|
98
|
|
|
if ($this->_options['include_categories']) |
|
99
|
|
|
{ |
|
100
|
|
|
$this->_categories = []; |
|
101
|
|
|
} |
|
102
|
|
|
else |
|
103
|
|
|
{ |
|
104
|
|
|
$this->_current_boards = []; |
|
105
|
|
|
} |
|
106
|
|
|
|
|
107
|
|
|
// For performance, track the latest post while going through the boards. |
|
108
|
|
|
if (!empty($this->_options['set_latest_post'])) |
|
109
|
|
|
{ |
|
110
|
|
|
$this->_latest_post = ['timestamp' => 0]; |
|
111
|
|
|
} |
|
112
|
|
|
|
|
113
|
|
|
if (!empty($modSettings['recycle_enable'])) |
|
114
|
|
|
{ |
|
115
|
4 |
|
$this->_recycle_board = (int) $modSettings['recycle_board']; |
|
116
|
|
|
} |
|
117
|
4 |
|
} |
|
118
|
|
|
|
|
119
|
4 |
|
/** |
|
120
|
4 |
|
* Fetches a list of boards and (optional) categories including statistical |
|
121
|
|
|
* information, sub-boards, and moderators. |
|
122
|
|
|
* - Used by both the board index (main data) and the message index (child boards). |
|
123
|
|
|
* - Depending on the include_categories setting returns an associative array with |
|
124
|
|
|
* categories->boards->child_boards or an associative array with boards->child_boards. |
|
125
|
|
|
* |
|
126
|
2 |
|
* @return array |
|
127
|
|
|
*/ |
|
128
|
4 |
|
public function getBoards(): array |
|
129
|
|
|
{ |
|
130
|
4 |
|
global $txt, $modSettings; |
|
131
|
4 |
|
|
|
132
|
|
|
// Fetch and sort the boards' data. |
|
133
|
4 |
|
$result_boards = $this->_fetchBoardsData(); |
|
134
|
|
|
$bbc_parser = ParserWrapper::instance(); |
|
135
|
4 |
|
|
|
136
|
4 |
|
// Parent map used when accumulating grandchild post/topic counts |
|
137
|
|
|
$parent_map = []; |
|
138
|
4 |
|
|
|
139
|
|
|
// Run through the categories and boards (or only boards)... |
|
140
|
|
|
foreach ($result_boards as $row_board) |
|
141
|
4 |
|
{ |
|
142
|
|
|
// Perhaps we are ignoring this board? |
|
143
|
2 |
|
$ignoreThisBoard = in_array($row_board['id_board'], $this->_user['ignoreboards']); |
|
144
|
|
|
$row_board['is_read'] = !empty($row_board['is_read']) || $ignoreThisBoard ? '1' : '0'; |
|
145
|
|
|
// Not a child. |
|
146
|
|
|
$isChild = false; |
|
147
|
2 |
|
|
|
148
|
|
|
// Initialize category scaffolding when needed and early-continue if collapsed. |
|
149
|
|
|
$this->_initCategoryIfNeeded($row_board); |
|
150
|
|
|
if ($this->_options['include_categories'] && $this->_categories[$row_board['id_cat']]['is_collapsed']) |
|
151
|
4 |
|
{ |
|
152
|
|
|
continue; |
|
153
|
2 |
|
} |
|
154
|
|
|
|
|
155
|
|
|
// This is a parent board. |
|
156
|
4 |
|
if ((int) $row_board['id_parent'] === (int) $this->_options['parent_id']) |
|
157
|
|
|
{ |
|
158
|
|
|
$this->_ensureParentBoardEntry($row_board, $bbc_parser); |
|
159
|
|
|
} |
|
160
|
4 |
|
// Found a sub-board... make sure we've found its parent and the child hasn't been set yet. |
|
161
|
|
|
elseif (isset($this->_current_boards[$row_board['id_parent']]['children']) && !isset($this->_current_boards[$row_board['id_parent']]['children'][$row_board['id_board']])) |
|
162
|
|
|
{ |
|
163
|
|
|
// A valid child! |
|
164
|
|
|
$isChild = true; |
|
165
|
|
|
$this->_addChildBoard($row_board, $bbc_parser); |
|
166
|
|
|
} |
|
167
|
|
|
// Child of a child... just add it on... |
|
168
|
|
|
elseif (!empty($this->_options['countChildPosts'])) |
|
169
|
|
|
{ |
|
170
|
|
|
$this->_accumulateGrandchildCounts($row_board, $parent_map); |
|
171
|
|
|
continue; |
|
172
|
|
|
} |
|
173
|
4 |
|
// Found a child of a child - skip. |
|
174
|
|
|
else |
|
175
|
4 |
|
{ |
|
176
|
|
|
continue; |
|
177
|
|
|
} |
|
178
|
4 |
|
|
|
179
|
4 |
|
// Prepare the subject and make sure it's not too long. |
|
180
|
4 |
|
$this_last_post = $this->_buildLastPost($row_board); |
|
181
|
|
|
|
|
182
|
|
|
// Set the last post in the parent board. |
|
183
|
|
|
$this->_assignLastPost($row_board, $isChild, $this_last_post); |
|
184
|
|
|
// Determine a global most recent topic. |
|
185
|
|
|
if (!$this->_options['set_latest_post']) |
|
186
|
4 |
|
{ |
|
187
|
4 |
|
continue; |
|
188
|
4 |
|
} |
|
189
|
4 |
|
if (empty($row_board['poster_time'])) |
|
190
|
4 |
|
{ |
|
191
|
4 |
|
continue; |
|
192
|
4 |
|
} |
|
193
|
|
|
if ($row_board['poster_time'] <= $this->_latest_post['timestamp']) |
|
194
|
4 |
|
{ |
|
195
|
4 |
|
continue; |
|
196
|
4 |
|
} |
|
197
|
4 |
|
if ($ignoreThisBoard) |
|
198
|
4 |
|
{ |
|
199
|
4 |
|
continue; |
|
200
|
|
|
} |
|
201
|
|
|
$this->_latest_post = &$this->_current_boards[$isChild ? $row_board['id_parent'] : $row_board['id_board']]['last_post']; |
|
202
|
4 |
|
} |
|
203
|
4 |
|
|
|
204
|
4 |
|
if ($this->_options['get_moderators'] && !empty($this->_boards)) |
|
205
|
4 |
|
{ |
|
206
|
|
|
$this->_getBoardModerators(); |
|
207
|
|
|
} |
|
208
|
|
|
|
|
209
|
4 |
|
usort($this->_categories, static fn($a, $b) => $a['order'] <=> $b['order']); |
|
210
|
|
|
|
|
211
|
|
|
return $this->_options['include_categories'] ? $this->_categories : $this->_current_boards; |
|
212
|
|
|
} |
|
213
|
4 |
|
|
|
214
|
|
|
/** |
|
215
|
4 |
|
* Fetch all boards (and optional categories) data from DB and sort by board_order |
|
216
|
|
|
*/ |
|
217
|
|
|
private function _fetchBoardsData(): array |
|
218
|
4 |
|
{ |
|
219
|
|
|
$request = $this->_db->fetchQuery(' |
|
220
|
|
|
SELECT ' . ($this->_options['include_categories'] ? ' |
|
221
|
2 |
|
c.id_cat, c.name AS cat_name, c.cat_order,' : '') . ' |
|
222
|
2 |
|
b.id_board, b.name AS board_name, b.description, b.board_order, |
|
223
|
|
|
CASE WHEN b.redirect != {string:blank_string} THEN 1 ELSE 0 END AS is_redirect, |
|
224
|
2 |
|
b.num_posts, b.num_topics, b.unapproved_posts, b.unapproved_topics, b.id_parent, |
|
225
|
|
|
COALESCE(m.poster_time, 0) AS poster_time, COALESCE(mem.member_name, m.poster_name) AS poster_name, |
|
226
|
2 |
|
m.subject, m.id_topic, COALESCE(mem.real_name, m.poster_name) AS real_name, |
|
227
|
|
|
' . ($this->_user['is_guest'] ? ' 1 AS is_read, 0 AS new_from,' : ' |
|
228
|
|
|
(CASE WHEN COALESCE(lb.id_msg, 0) >= b.id_msg_updated THEN 1 ELSE 0 END) AS is_read, COALESCE(lb.id_msg, -1) + 1 AS new_from,' . ($this->_options['include_categories'] ? ' |
|
229
|
2 |
|
c.can_collapse, COALESCE(cc.id_member, 0) AS is_collapsed,' : '')) . ' |
|
230
|
|
|
COALESCE(mem.id_member, 0) AS id_member, mem.avatar, m.id_msg' . ($this->_options['avatars_on_indexes'] ? ', |
|
231
|
2 |
|
COALESCE(a.id_attach, 0) AS id_attach, a.filename, a.attachment_type, mem.email_address' : '') . ' |
|
232
|
2 |
|
FROM {db_prefix}boards AS b' . ($this->_options['include_categories'] ? ' |
|
233
|
2 |
|
LEFT JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat)' : '') . ' |
|
234
|
2 |
|
LEFT JOIN {db_prefix}messages AS m ON (m.id_msg = b.id_last_msg) |
|
235
|
2 |
|
LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)' . ($this->_user['is_guest'] ? '' : ' |
|
236
|
2 |
|
LEFT JOIN {db_prefix}log_boards AS lb ON (lb.id_board = b.id_board AND lb.id_member = {int:current_member})' . ($this->_options['include_categories'] ? ' |
|
237
|
2 |
|
LEFT JOIN {db_prefix}collapsed_categories AS cc ON (cc.id_cat = c.id_cat AND cc.id_member = {int:current_member})' : '')) . ($this->_options['avatars_on_indexes'] ? ' |
|
238
|
2 |
|
LEFT JOIN {db_prefix}attachments AS a ON (a.id_member = m.id_member AND a.id_member != 0)' : '') . ' |
|
239
|
2 |
|
WHERE {query_see_board}' . (empty($this->_options['countChildPosts']) ? (empty($this->_options['base_level']) ? '' : ' |
|
240
|
2 |
|
AND b.child_level >= {int:child_level}') : ' |
|
241
|
|
|
AND b.child_level BETWEEN {int:child_level} AND {int:upper_level}'), |
|
242
|
|
|
[ |
|
243
|
|
|
'current_member' => $this->_user['id'], |
|
244
|
2 |
|
'child_level' => $this->_options['base_level'], |
|
245
|
2 |
|
'upper_level' => $this->_options['base_level'] + 1, |
|
246
|
2 |
|
'blank_string' => '', |
|
247
|
|
|
] |
|
248
|
|
|
); |
|
249
|
|
|
|
|
250
|
2 |
|
$result_boards = $request->fetch_all(); |
|
251
|
|
|
usort($result_boards, static fn($a, $b) => $a['board_order'] <=> $b['board_order']); |
|
252
|
2 |
|
return $result_boards; |
|
253
|
|
|
} |
|
254
|
|
|
|
|
255
|
|
|
/** |
|
256
|
2 |
|
* Initialize category for a row (when include_categories is enabled) |
|
257
|
|
|
*/ |
|
258
|
|
|
private function _initCategoryIfNeeded(array $row_board): void |
|
259
|
2 |
|
{ |
|
260
|
|
|
global $txt, $modSettings; |
|
261
|
|
|
|
|
262
|
|
|
if (!$this->_options['include_categories']) |
|
263
|
|
|
{ |
|
264
|
|
|
return; |
|
265
|
2 |
|
} |
|
266
|
|
|
|
|
267
|
|
|
if (empty($this->_categories[$row_board['id_cat']])) |
|
268
|
|
|
{ |
|
269
|
2 |
|
$cat_name = $row_board['cat_name']; |
|
270
|
|
|
$can_collapse = !empty($row_board['can_collapse']) && (int) $row_board['can_collapse'] === 1; |
|
271
|
|
|
$is_collapsed = $can_collapse && (int) $row_board['is_collapsed'] > 0; |
|
272
|
2 |
|
|
|
273
|
|
|
$this->_categories[$row_board['id_cat']] = [ |
|
274
|
2 |
|
'id' => $row_board['id_cat'], |
|
275
|
2 |
|
'name' => $row_board['cat_name'], |
|
276
|
2 |
|
'order' => $row_board['cat_order'], |
|
277
|
2 |
|
'is_collapsed' => $is_collapsed, |
|
278
|
2 |
|
'can_collapse' => $can_collapse, |
|
279
|
2 |
|
'collapse_href' => $can_collapse ? getUrl('action', ['action' => 'collapse', 'c' => $row_board['id_cat'], 'sa' => $is_collapsed ? 'expand' : 'collapse', '{session_data}',]) . '#c' . $row_board['id_cat'] : '', |
|
280
|
2 |
|
'collapse_image' => $can_collapse ? '<img src="' . $this->_images_url . ($is_collapsed ? 'expand.png" alt="+"' : 'collapse.png" alt="-"') . ' />' : '', |
|
281
|
|
|
'href' => getUrl('action', $modSettings['default_forum_action']) . '#c' . $row_board['id_cat'], |
|
282
|
|
|
'boards' => [], |
|
283
|
|
|
'new' => false |
|
284
|
|
|
]; |
|
285
|
|
|
$this->_categories[$row_board['id_cat']]['link'] = '<a id="c' . $row_board['id_cat'] . '"></a>' . ($this->_user['is_guest'] |
|
286
|
2 |
|
? $cat_name |
|
287
|
2 |
|
: '<a href="' . getUrl('action', ['action' => 'unread', 'c' => $row_board['id_cat']]) . '" title="' . sprintf($txt['new_posts_in_category'], strip_tags($row_board['cat_name'])) . '">' . $cat_name . '</a>'); |
|
288
|
2 |
|
} |
|
289
|
2 |
|
|
|
290
|
2 |
|
// Category new indicator (skip recycle bin) |
|
291
|
2 |
|
if ($this->_recycle_board !== (int) $row_board['id_board']) |
|
292
|
2 |
|
{ |
|
293
|
2 |
|
$this->_categories[$row_board['id_cat']]['new'] |= empty($row_board['is_read']) && $row_board['poster_name'] !== ''; |
|
294
|
|
|
} |
|
295
|
|
|
|
|
296
|
2 |
|
// Avoid showing a category unread link where it only has redirection boards. |
|
297
|
|
|
$this->_categories[$row_board['id_cat']]['show_unread'] = empty($this->_categories[$row_board['id_cat']]['show_unread']) ? !$row_board['is_redirect'] : 1; |
|
298
|
|
|
|
|
299
|
|
|
// Set current boards reference for this category (even if collapsed) |
|
300
|
|
|
$this->_current_boards = &$this->_categories[$row_board['id_cat']]['boards']; |
|
301
|
|
|
} |
|
302
|
|
|
|
|
303
|
|
|
/** |
|
304
|
|
|
* Ensure the parent board entry exists and record for moderators mapping |
|
305
|
|
|
*/ |
|
306
|
|
|
private function _ensureParentBoardEntry(array $row_board, ParserWrapper $bbc_parser): void |
|
307
|
|
|
{ |
|
308
|
|
|
if (!isset($this->_current_boards[$row_board['id_board']])) |
|
309
|
|
|
{ |
|
310
|
|
|
$href = getUrl('board', ['board' => $row_board['id_board'], 'start' => '0', 'name' => $row_board['board_name']]); |
|
311
|
|
|
$this->_current_boards[$row_board['id_board']] = [ |
|
312
|
|
|
'new' => empty($row_board['is_read']), |
|
313
|
|
|
'id' => (int) $row_board['id_board'], |
|
314
|
|
|
'name' => $row_board['board_name'], |
|
315
|
|
|
'description' => $bbc_parser->parseBoard($row_board['description']), |
|
316
|
|
|
'raw_description' => $row_board['description'], |
|
317
|
|
|
'moderators' => [], |
|
318
|
|
|
'link_moderators' => [], |
|
319
|
|
|
'children' => [], |
|
320
|
|
|
'link_children' => [], |
|
321
|
|
|
'children_new' => false, |
|
322
|
|
|
'topics' => (int) $row_board['num_topics'], |
|
323
|
|
|
'posts' => (int) $row_board['num_posts'], |
|
324
|
|
|
'is_redirect' => $row_board['is_redirect'], |
|
325
|
|
|
'unapproved_topics' => $row_board['unapproved_topics'], |
|
326
|
|
|
'unapproved_posts' => $row_board['unapproved_posts'] - $row_board['unapproved_topics'], |
|
327
|
|
|
'can_approve_posts' => $this->_user['mod_cache_ap'] == [0] || in_array($row_board['id_board'], $this->_user['mod_cache_ap']), |
|
328
|
|
|
'href' => $href, |
|
329
|
|
|
'link' => '<a href="' . $href . '">' . $row_board['board_name'] . '</a>' |
|
330
|
|
|
]; |
|
331
|
|
|
} |
|
332
|
|
|
|
|
333
|
|
|
$this->_boards[$row_board['id_board']] = $this->_options['include_categories'] ? $row_board['id_cat'] : 0; |
|
334
|
|
|
} |
|
335
|
|
|
|
|
336
|
|
|
/** |
|
337
|
|
|
* Add a child board to its parent and update counters and links |
|
338
|
|
|
*/ |
|
339
|
|
|
private function _addChildBoard(array $row_board, ParserWrapper $bbc_parser): void |
|
340
|
|
|
{ |
|
341
|
|
|
$href = getUrl('board', ['board' => $row_board['id_board'], 'start' => '0', 'name' => $row_board['board_name']]); |
|
342
|
|
|
$this->_current_boards[$row_board['id_parent']]['children'][$row_board['id_board']] = [ |
|
343
|
|
|
'id' => (int) $row_board['id_board'], |
|
344
|
|
|
'name' => $row_board['board_name'], |
|
345
|
|
|
'description' => $bbc_parser->parseBoard($row_board['description']), |
|
346
|
|
|
'raw_description' => $row_board['description'], |
|
347
|
|
|
'new' => empty($row_board['is_read']) && $row_board['poster_name'] !== '', |
|
348
|
|
|
'topics' => (int) $row_board['num_topics'], |
|
349
|
|
|
'posts' => (int) $row_board['num_posts'], |
|
350
|
|
|
'is_redirect' => $row_board['is_redirect'], |
|
351
|
|
|
'unapproved_topics' => $row_board['unapproved_topics'], |
|
352
|
|
|
'unapproved_posts' => $row_board['unapproved_posts'] - $row_board['unapproved_topics'], |
|
353
|
|
|
'can_approve_posts' => $this->_user['mod_cache_ap'] == [0] || in_array($row_board['id_board'], $this->_user['mod_cache_ap']), |
|
354
|
|
|
'href' => $href, |
|
355
|
|
|
'link' => '<a href="' . $href . '">' . $row_board['board_name'] . '</a>' |
|
356
|
|
|
]; |
|
357
|
|
|
|
|
358
|
|
|
// Counting sub-board posts is... slow :/. |
|
359
|
|
|
if (!empty($this->_options['countChildPosts']) && !$row_board['is_redirect']) |
|
360
|
|
|
{ |
|
361
|
|
|
$this->_current_boards[$row_board['id_parent']]['posts'] += $row_board['num_posts']; |
|
362
|
|
|
$this->_current_boards[$row_board['id_parent']]['topics'] += $row_board['num_topics']; |
|
363
|
|
|
} |
|
364
|
|
|
|
|
365
|
|
|
// Does this board contain new boards? |
|
366
|
|
|
$is_read = empty($row_board['is_read']); |
|
367
|
|
|
$this->_current_boards[$row_board['id_parent']]['children_new'] |= $is_read; |
|
368
|
|
|
|
|
369
|
|
|
// This is easier to use in many cases for the theme... |
|
370
|
|
|
$this->_current_boards[$row_board['id_parent']]['link_children'][] = &$this->_current_boards[$row_board['id_parent']]['children'][$row_board['id_board']]['link']; |
|
371
|
|
|
} |
|
372
|
|
|
|
|
373
|
|
|
/** |
|
374
|
|
|
* Accumulate posts/topics for grandchildren when countChildPosts is enabled |
|
375
|
|
|
*/ |
|
376
|
|
|
private function _accumulateGrandchildCounts(array $row_board, array &$parent_map): void |
|
377
|
|
|
{ |
|
378
|
2 |
|
if (!isset($parent_map[$row_board['id_parent']])) |
|
379
|
2 |
|
{ |
|
380
|
2 |
|
foreach ($this->_current_boards as $id => $board) |
|
381
|
|
|
{ |
|
382
|
2 |
|
if (!isset($board['children'][$row_board['id_parent']])) |
|
383
|
2 |
|
{ |
|
384
|
2 |
|
continue; |
|
385
|
2 |
|
} |
|
386
|
2 |
|
|
|
387
|
|
|
$parent_map[$row_board['id_parent']] = [&$this->_current_boards[$id], &$this->_current_boards[$id]['children'][$row_board['id_parent']]]; |
|
388
|
2 |
|
$parent_map[$row_board['id_board']] = [&$this->_current_boards[$id], &$this->_current_boards[$id]['children'][$row_board['id_parent']]]; |
|
389
|
2 |
|
break; |
|
390
|
2 |
|
} |
|
391
|
2 |
|
} |
|
392
|
2 |
|
|
|
393
|
|
|
if (isset($parent_map[$row_board['id_parent']]) && !$row_board['is_redirect']) |
|
394
|
2 |
|
{ |
|
395
|
2 |
|
$parent_map[$row_board['id_parent']][0]['posts'] += $row_board['num_posts']; |
|
396
|
|
|
$parent_map[$row_board['id_parent']][0]['topics'] += $row_board['num_topics']; |
|
397
|
|
|
$parent_map[$row_board['id_parent']][1]['posts'] += $row_board['num_posts']; |
|
398
|
2 |
|
$parent_map[$row_board['id_parent']][1]['topics'] += $row_board['num_topics']; |
|
399
|
|
|
} |
|
400
|
2 |
|
} |
|
401
|
|
|
|
|
402
|
|
|
/** |
|
403
|
|
|
* Build the last post-array for a board row |
|
404
|
2 |
|
*/ |
|
405
|
|
|
private function _buildLastPost(array $row_board): array |
|
406
|
2 |
|
{ |
|
407
|
2 |
|
global $txt; |
|
408
|
|
|
|
|
409
|
|
|
$row_board['subject'] = censor($row_board['subject']); |
|
410
|
|
|
$row_board['short_subject'] = Util::shorten_text($row_board['subject'], $this->_subject_length); |
|
411
|
|
|
$poster_href = getUrl('profile', ['action' => 'profile', 'u' => $row_board['id_member'], 'name' => $row_board['real_name']]); |
|
412
|
2 |
|
$this_last_post = [ |
|
413
|
|
|
'id' => (int) $row_board['id_msg'], |
|
414
|
|
|
'time' => $row_board['poster_time'] > 0 ? standardTime($row_board['poster_time']) : $txt['not_applicable'], |
|
415
|
|
|
'html_time' => $row_board['poster_time'] > 0 ? htmlTime($row_board['poster_time']) : $txt['not_applicable'], |
|
416
|
|
|
'timestamp' => forum_time(true, $row_board['poster_time']), |
|
417
|
|
|
'subject' => $row_board['short_subject'], |
|
418
|
|
|
'member' => [ |
|
419
|
|
|
'id' => (int) $row_board['id_member'], |
|
420
|
|
|
'username' => $row_board['poster_name'] !== '' ? $row_board['poster_name'] : $txt['not_applicable'], |
|
421
|
|
|
'name' => $row_board['real_name'], |
|
422
|
2 |
|
'href' => $row_board['poster_name'] !== '' && !empty($row_board['id_member']) ? $poster_href : '', |
|
423
|
|
|
'link' => $row_board['poster_name'] !== '' ? (empty($row_board['id_member']) ? $row_board['real_name'] : '<a href="' . $poster_href . '">' . $row_board['real_name'] . '</a>') : $txt['not_applicable'], |
|
424
|
2 |
|
], |
|
425
|
|
|
'start' => 'msg' . $row_board['new_from'], |
|
426
|
|
|
'topic' => (int) $row_board['id_topic'] |
|
427
|
2 |
|
]; |
|
428
|
|
|
|
|
429
|
|
|
if ($this->_options['avatars_on_indexes']) |
|
430
|
|
|
{ |
|
431
|
|
|
$this_last_post['member']['avatar'] = determineAvatar($row_board); |
|
432
|
|
|
} |
|
433
|
|
|
|
|
434
|
|
|
if ($row_board['subject'] !== '') |
|
435
|
2 |
|
{ |
|
436
|
|
|
$this_last_post['href'] = getUrl('topic', ['topic' => $row_board['id_topic'], 'start' => 'msg' . ($this->_user['is_guest'] ? $row_board['id_msg'] : $row_board['new_from']), 'subject' => $row_board['subject'], 0 => empty($row_board['is_read']) ? 'boardseen' : '']) . '#new'; |
|
437
|
|
|
$this_last_post['link'] = '<a href="' . $this_last_post['href'] . '" title="' . Util::htmlspecialchars($row_board['subject']) . '">' . $row_board['short_subject'] . '</a>'; |
|
438
|
|
|
$this_last_post['last_post_message'] = sprintf($txt['last_post_message'], $this_last_post['member']['link'], $this_last_post['link'], $this_last_post['html_time']); |
|
439
|
|
|
} |
|
440
|
|
|
else |
|
441
|
2 |
|
{ |
|
442
|
|
|
$this_last_post['href'] = ''; |
|
443
|
2 |
|
$this_last_post['link'] = $txt['not_applicable']; |
|
444
|
|
|
$this_last_post['last_post_message'] = ''; |
|
445
|
|
|
} |
|
446
|
|
|
|
|
447
|
4 |
|
return $this_last_post; |
|
448
|
|
|
} |
|
449
|
2 |
|
|
|
450
|
|
|
/** |
|
451
|
|
|
* Assign last post info to the right board (and child board if applicable) |
|
452
|
|
|
*/ |
|
453
|
|
|
private function _assignLastPost(array $row_board, bool $isChild, array $this_last_post): void |
|
454
|
4 |
|
{ |
|
455
|
|
|
if ((int) $row_board['id_parent'] === (int) $this->_options['parent_id'] || ($isChild && !empty($row_board['poster_time']) && $this->_current_boards[$row_board['id_parent']]['last_post']['timestamp'] < forum_time(true, $row_board['poster_time']))) |
|
456
|
4 |
|
{ |
|
457
|
|
|
$this->_current_boards[$isChild ? $row_board['id_parent'] : $row_board['id_board']]['last_post'] = $this_last_post; |
|
458
|
|
|
} |
|
459
|
|
|
|
|
460
|
|
|
if ($isChild) |
|
461
|
|
|
{ |
|
462
|
2 |
|
$this->_current_boards[$row_board['id_parent']]['children'][$row_board['id_board']]['last_post'] = $this_last_post; |
|
463
|
|
|
$this->_current_boards[$row_board['id_parent']]['children'][$row_board['id_board']]['new'] &= $row_board['poster_name'] !== ''; |
|
464
|
2 |
|
} |
|
465
|
|
|
elseif ($row_board['poster_name'] === '') |
|
466
|
2 |
|
{ |
|
467
|
2 |
|
$this->_current_boards[$row_board['id_board']]['new'] = false; |
|
468
|
|
|
} |
|
469
|
2 |
|
} |
|
470
|
|
|
|
|
471
|
2 |
|
/** |
|
472
|
|
|
* Fetches and adds to the results the board moderators for the current boards |
|
473
|
|
|
*/ |
|
474
|
|
|
private function _getBoardModerators(): void |
|
475
|
|
|
{ |
|
476
|
|
|
global $txt; |
|
477
|
2 |
|
|
|
478
|
|
|
$boards = array_keys($this->_boards); |
|
479
|
|
|
$mod_cached = []; |
|
480
|
2 |
|
|
|
481
|
|
|
if (!Cache::instance()->getVar($mod_cached, 'localmods_' . md5(implode(',', $boards)), 3600)) |
|
482
|
2 |
|
{ |
|
483
|
|
|
$request = $this->_db->fetchQuery(' |
|
484
|
|
|
SELECT |
|
485
|
2 |
|
mods.id_board, COALESCE(mods_mem.id_member, 0) AS id_moderator, mods_mem.real_name AS mod_real_name |
|
486
|
|
|
FROM {db_prefix}moderators AS mods |
|
487
|
|
|
LEFT JOIN {db_prefix}members AS mods_mem ON (mods_mem.id_member = mods.id_member) |
|
488
|
|
|
WHERE mods.id_board IN ({array_int:id_boards})', |
|
489
|
|
|
[ |
|
490
|
|
|
'id_boards' => $boards, |
|
491
|
|
|
] |
|
492
|
|
|
); |
|
493
|
|
|
$mod_cached = $request->fetch_all(); |
|
494
|
|
|
|
|
495
|
|
|
Cache::instance()->put('localmods_' . md5(implode(',', $boards)), $mod_cached, 3600); |
|
496
|
|
|
} |
|
497
|
|
|
|
|
498
|
|
|
foreach ($mod_cached as $row_mods) |
|
499
|
|
|
{ |
|
500
|
|
|
if ($this->_options['include_categories']) |
|
501
|
2 |
|
{ |
|
502
|
|
|
$this->_current_boards = &$this->_categories[$this->_boards[$row_mods['id_board']]]['boards']; |
|
503
|
|
|
} |
|
504
|
|
|
|
|
505
|
|
|
$href = getUrl('profile', ['action' => 'profile', 'u' => $row_mods['id_moderator'], 'name' => $row_mods['mod_real_name']]); |
|
506
|
|
|
$this->_current_boards[$row_mods['id_board']]['moderators'][$row_mods['id_moderator']] = [ |
|
507
|
|
|
'id' => $row_mods['id_moderator'], |
|
508
|
2 |
|
'name' => $row_mods['mod_real_name'], |
|
509
|
|
|
'href' => $href, |
|
510
|
2 |
|
'link' => '<a href="' . $href . '" title="' . $txt['board_moderator'] . '">' . $row_mods['mod_real_name'] . '</a>' |
|
511
|
|
|
]; |
|
512
|
|
|
$this->_current_boards[$row_mods['id_board']]['link_moderators'][] = '<a href="' . $href . '" title="' . $txt['board_moderator'] . '">' . $row_mods['mod_real_name'] . '</a>'; |
|
513
|
|
|
} |
|
514
|
|
|
} |
|
515
|
|
|
|
|
516
|
2 |
|
/** |
|
517
|
|
|
* Returns the array containing the "latest post" information |
|
518
|
|
|
* |
|
519
|
|
|
* @return array |
|
520
|
|
|
*/ |
|
521
|
|
|
public function getLatestPost(): array |
|
522
|
|
|
{ |
|
523
|
|
|
if (empty($this->_latest_post) || empty($this->_latest_post['link'])) |
|
524
|
|
|
{ |
|
525
|
|
|
return []; |
|
526
|
|
|
} |
|
527
|
|
|
|
|
528
|
|
|
return $this->_latest_post; |
|
529
|
|
|
} |
|
530
|
|
|
} |
|
531
|
|
|
|
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.
Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..