Passed
Branch development (7a3bc2)
by Elk
06:00
created

Markasread::action_index_api()   B

Complexity

Conditions 9
Paths 12

Size

Total Lines 67
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 31
nc 12
nop 2
dl 0
loc 67
rs 8.0555
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Handles all mark as read options, boards, topics, replies
5
 *
6
 * @package   ElkArte Forum
7
 * @copyright ElkArte Forum contributors
8
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
9
 *
10
 * @version 2.0 dev
11
 *
12
 */
13
14
namespace ElkArte\Controller;
15
16
use ElkArte\AbstractController;
17
use ElkArte\Action;
18
use ElkArte\Languages\Txt;
19
20
/**
21
 * This class handles a part of the actions to mark boards, topics, or replies,
22
 * as read/unread.
23
 */
24
class Markasread extends AbstractController
25
{
26
	/** @var array used to redirect user to the correct boards when marking unread */
27
	private $_querystring_board_limits;
28
29
	/** @var array used to remember user's sorting options when marking unread */
30
	private $_querystring_sort_limits;
31
32
	/** @var bool if this is an api call */
33
	private $api = false;
34
35
	/**
36
	 * This is the pre-dispatch function, actions common to all methods
37
	 */
38
	public function pre_dispatch()
39
	{
40
		$this->api = $this->getApi() === 'xml';
41
42
		// We will check these items in the ajax function
43
		if (!$this->api)
44
		{
45
			// Guests can't mark things.
46
			is_not_guest();
47
48
			checkSession('get');
49
		}
50
	}
51
52
	/**
53
	 * This is the main function for markasread file
54
	 *
55
	 * markasread;sa=topic;t=###;topic=###.0;session Mark a topic unread
56
	 * markasread;sa=board;board=#.0;session Mark a board (all its topics) as read
57
	 * markasread;sa=board;c=#;start=0;session Mark a category read
58
	 * markasread;sa=all;session everything is read
59
	 * markasread;sa=unreadreplies;topics=6056-4692-6026-5817;session
60
	 */
61
	public function action_index()
62
	{
63
		global $context;
64
65
		$subActions = array(
66
			'all' => array($this, 'action_markboards'),
67
			'unreadreplies' => array($this, 'action_markreplies'),
68
			'topic' => array($this, 'action_marktopic_unread'),
69
			'markasread' => array($this, 'action_markasread')
70
		);
71
72
		$action = new Action('markasread');
73
		$subAction = $action->initialize($subActions, 'markasread');
74
		$context['sub_action'] = $subAction;
75
76
		if ($this->api)
77
		{
78
			$this->action_index_api($action, $subAction);
79
			return;
80
		}
81
82
		$action->dispatch($subAction);
83
	}
84
85
	/**
86
	 * This is the controller when using APIs.
87
	 *
88
	 * @uses Xml template generic_xml_buttons sub template
89
	 */
90
	public function action_index_api($action, $subAction)
91
	{
92
		global $context, $txt;
93
94
		// Setup for an Ajax response
95
		theme()->getTemplates()->load('Xml');
96
		theme()->getLayers()->removeAll();
97
		$context['sub_template'] = 'generic_xml_buttons';
98
99
		// Guests can't mark things.
100
		if ($this->user->is_guest)
101
		{
102
			Txt::load('Errors');
103
			$context['xml_data'] = array(
104
				'error' => 1,
105
				'text' => $txt['not_guests']
106
			);
107
108
			return;
109
		}
110
111
		// Best have a valid session
112
		if (checkSession('get', '', false))
113
		{
114
			// Again, this is a special case, someone will deal with the others later :P
115
			if ($this->_req->getQuery('sa') === 'all')
116
			{
117
				Txt::load('Errors');
118
				$context['xml_data'] = array(
119
					'error' => 1,
120
					'url' => getUrl('action', ['action' => 'markasread', 'sa' => 'all', '{session_data}']),
121
				);
122
123
				return;
124
			}
125
126
			obExit(false);
127
		}
128
129
		// Dispatch to the right method
130
		$action->dispatch($subAction);
131
132
		// For the time being this is a special case, but in BoardIndex no, we don't want it
133
		if ($this->_req->getQuery('sa') === 'all' || $this->_req->getQuery('sa') === 'board' && !isset($this->_req->query->bi))
134
		{
135
			$url_params = ['action' => 'unread', 'all', '{session_data}'];
136
			if (!empty($this->_querystring_board_limits))
137
			{
138
				$url_params += $this->_querystring_board_limits;
139
				$url_params['start'] = 0;
140
			}
141
142
			if (!empty($this->_querystring_sort_limits))
143
			{
144
				$url_params += $this->_querystring_sort_limits;
145
			}
146
147
			$context['xml_data'] = array(
148
				'text' => $txt['topic_alert_none'],
149
				'body' => str_replace('{unread_all_url}', getUrl('action', $url_params), $txt['unread_topics_visit_none']),
150
			);
151
152
			return;
153
		}
154
155
		// No need to output anything, just return to the button
156
		obExit(false);
157
	}
158
159
	/**
160
	 * Marks boards as read (or unread)
161
	 *
162
	 * - Accessed by action=markasread;sa=all
163
	 */
164
	public function action_markboards()
165
	{
166
		global $modSettings;
167
168
		require_once(SUBSDIR . '/Boards.subs.php');
169
170
		// Find all the boards this user can see.
171
		$boards = accessibleBoards();
172
173
		// Mark boards as read
174
		if (!empty($boards))
175
		{
176
			markBoardsRead($boards, isset($this->_req->query->unread), true);
177
		}
178
179
		$_SESSION['id_msg_last_visit'] = $modSettings['maxMsgID'];
180
		$redirectAction = '';
181
		if (!empty($_SESSION['old_url']) && strpos($_SESSION['old_url'], 'action=unread') !== false)
182
		{
183
			$redirectAction = 'action=unread';
184
		}
185
186
		if (isset($_SESSION['topicseen_cache']))
187
		{
188
			$_SESSION['topicseen_cache'] = array();
189
		}
190
191
		if (!empty($modSettings['default_forum_action']) && $redirectAction === '')
192
		{
193
			$redirectAction = getUrlQuery('action', $modSettings['default_forum_action']);
194
		}
195
196
		if ($this->api)
197
		{
198
			return;
199
		}
200
201
		redirectexit($redirectAction);
202
	}
203
204
	/**
205
	 * Marks the selected topics as read.
206
	 *
207
	 * - Accessed by action=markasread;sa=unreadreplies
208
	 */
209
	public function action_markreplies()
210
	{
211
		global $modSettings;
212
213
		// Make sure all the topics are integers!
214
		$topics = array_map('intval', explode('-', $this->_req->query->topics));
215
216
		require_once(SUBSDIR . '/Topic.subs.php');
217
		$logged_topics = getLoggedTopics($this->user->id, $topics);
218
219
		$markRead = array();
220
		foreach ($topics as $id_topic)
221
		{
222
			$markRead[] = array($this->user->id, (int) $id_topic, $modSettings['maxMsgID'], (int) !empty($logged_topics[$id_topic]));
223
		}
224
225
		markTopicsRead($markRead, true);
226
227
		if (isset($_SESSION['topicseen_cache']))
228
		{
229
			$_SESSION['topicseen_cache'] = array();
230
		}
231
232
		if ($this->api)
233
		{
234
			return;
235
		}
236
237
		redirectexit('action=unreadreplies');
238
	}
239
240
	/**
241
	 * Mark a single topic as unread, returning to the board topic listing
242
	 *
243
	 * - Accessed by action=markasread;sa=topic;topic=123;t=123
244
	 * - Button URL set in Display.php Controller
245
	 */
246
	public function action_marktopic_unread()
247
	{
248
		global $board, $topic;
249
250
		require_once(SUBSDIR . '/Topic.subs.php');
251
		require_once(SUBSDIR . '/Messages.subs.php');
252
253
		// First, let's figure out what the latest message is.
254
		$topicinfo = getTopicInfo($topic, 'all');
255
		$topic_msg_id = $this->_req->getQuery('t', 'intval');
256
		if (!empty($topic_msg_id))
257
		{
258
			// If they read the whole topic, go back to the beginning.
259
			if ($topic_msg_id >= $topicinfo['id_last_msg'])
260
			{
261
				$earlyMsg = 0;
262
			}
263
			// If they want to mark the whole thing read, same.
264
			elseif ($topic_msg_id <= $topicinfo['id_first_msg'])
265
			{
266
				$earlyMsg = 0;
267
			}
268
			// Otherwise, get the latest message before the named one.
269
			else
270
			{
271
				$earlyMsg = previousMessage($topic_msg_id, $topic);
272
			}
273
		}
274
		// Marking read from first page?  That's the whole topic.
275
		elseif ($this->_req->query->start == 0)
276
		{
277
			$earlyMsg = 0;
278
		}
279
		else
280
		{
281
			list ($earlyMsg) = messageAt((int) $this->_req->query->start, $topic);
282
			$earlyMsg--;
283
		}
284
285
		// Blam, unread!
286
		markTopicsRead(array($this->user->id, $topic, $earlyMsg, $topicinfo['unwatched']), true);
287
288
		if ($this->api)
289
		{
290
			return;
291
		}
292
293
		redirectexit('board=' . $board . '.0');
294
	}
295
296
	/**
297
	 * Mark as read: boards, topics, unread replies.
298
	 *
299
	 * - action=markasread;sa=board;board=1.0;HvVjpAAiL=5sGGC9DvMYeGTiH1MkTJjTcAG6foW2qm
300
	 * - Accessed by action=markasread
301
	 * - Subactions: sa=topic, sa=all, sa=unreadreplies, sa=board
302
	 */
303
	public function action_markasread()
304
	{
305
		global $board, $board_info;
306
307
		require_once(SUBSDIR . '/Boards.subs.php');
308
309
		$categories = array();
310
		$boards = array();
311
312
		if (isset($this->_req->query->c))
313
		{
314
			$categories = array_map('intval', explode(',', $this->_req->query->c));
315
		}
316
317
		if (isset($this->_req->query->boards))
318
		{
319
			$boards = array_map('intval', explode(',', $this->_req->query->boards));
320
		}
321
322
		if (!empty($board))
323
		{
324
			$boards[] = (int) $board;
325
		}
326
327
		if (isset($this->_req->query->children) && !empty($boards))
328
		{
329
			// Mark all children of the boards we got (selected by the user).
330
			$boards = addChildBoards($boards);
331
		}
332
333
		$boards = array_keys(boardsPosts($boards, $categories));
334
335
		if (empty($boards))
336
		{
337
			if ($this->api)
338
			{
339
				return;
340
			}
341
342
			redirectexit();
343
		}
344
345
		// Mark boards as read.
346
		markBoardsRead($boards, isset($this->_req->query->unread), true);
347
348
		foreach ($boards as $b)
349
		{
350
			if (isset($_SESSION['topicseen_cache'][$b]))
351
			{
352
				$_SESSION['topicseen_cache'][$b] = array();
353
			}
354
		}
355
356
		$this->_querystring_board_limits = $this->_req->getQuery('sa') === 'board' ? ['boards' => implode(',', $boards), 'start' => '%d'] : [];
357
358
		$this->_setQuerystringSortLimits();
359
360
		$this->_markAsRead($boards);
361
362
		if (empty($board_info['parent']) && !$this->api)
363
		{
364
			redirectexit();
365
		}
366
367
		if ($this->api)
368
		{
369
			return;
370
		}
371
372
		redirectexit('board=' . $board_info['parent'] . '.0');
373
	}
374
375
	private function _setQuerystringSortLimits()
376
	{
377
		$sort_methods = [
378
			'subject',
379
			'starter',
380
			'replies',
381
			'views',
382
			'first_post',
383
			'last_post'
384
		];
385
386
		// The default is the most logical: newest first.
387
		if (!isset($this->_req->query->sort) || !in_array($this->_req->query->sort, $sort_methods))
388
		{
389
			$this->_querystring_sort_limits = isset($this->_req->query->asc) ? ['asc'] : [];
390
		}
391
		// But, for other methods the default sort is ascending.
392
		else
393
		{
394
			$this->_querystring_sort_limits = ['sort' => $this->_req->query->sort, isset($this->_req->query->desc) ? 'desc' : ''];
395
		}
396
	}
397
398
	private function _markAsRead($boards)
399
	{
400
		global $board;
401
402
		// Want to mark as unread, nothing to do here
403
		if (isset($this->_req->query->unread))
404
		{
405
			return;
406
		}
407
408
		// Find all boards with the parents in the board list
409
		$boards_to_add = accessibleBoards(null, $boards);
410
		if (!empty($boards_to_add))
411
		{
412
			markBoardsRead($boards_to_add);
413
		}
414
415
		$redirectAction = 'board=' . $board . '.0';
416
		if (empty($board))
417
		{
418
			$redirectAction = '';
419
		}
420
421
		if ($this->api)
422
		{
423
			return;
424
		}
425
426
		redirectexit($redirectAction);
427
	}
428
}
429