BoardsList::_accumulateGrandchildCounts()   A
last analyzed

Complexity

Conditions 6
Paths 6

Size

Total Lines 23
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 12
c 1
b 0
f 0
nc 6
nop 2
dl 0
loc 23
ccs 16
cts 16
cp 1
crap 6
rs 9.2222
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;
0 ignored issues
show
Documentation Bug introduced by
It seems like ElkArte\User::info of type ElkArte\Helper\ValuesContainer is incompatible with the declared type array of property $_user.

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..

Loading history...
93
		$this->_user['mod_cache_ap'] = empty($this->_user->mod_cache['ap']) ? [] : $this->_user->mod_cache['ap'];
0 ignored issues
show
Bug Best Practice introduced by
The property mod_cache does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
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