Completed
Pull Request — master (#23)
by
unknown
02:00
created

similar_topics_module::isset_or_default()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 2
eloc 2
nc 2
nop 2
1
<?php
2
/**
3
 *
4
 * Precise Similar Topics
5
 *
6
 * @copyright (c) 2013 Matt Friedman
7
 * @license GNU General Public License, version 2 (GPL-2.0)
8
 *
9
 */
10
11
namespace vse\similartopics\acp;
12
13
/**
14
 * @package acp
15
 */
16
class similar_topics_module
17
{
18
	/** @var \phpbb\cache\driver\driver_interface */
19
	protected $cache;
20
21
	/** @var \phpbb\config\config */
22
	protected $config;
23
24
	/** @var \phpbb\db\driver\driver_interface */
25
	protected $db;
26
27
	/** @var \vse\similartopics\core\fulltext_support */
28
	protected $fulltext;
29
30
	/** @var \phpbb\log\log */
31
	protected $log;
32
33
	/** @var \phpbb\request\request */
34
	protected $request;
35
36
	/** @var \phpbb\template\template */
37
	protected $template;
38
39
	/** @var \phpbb\user */
40
	protected $user;
41
42
	/** @var string */
43
	protected $root_path;
44
45
	/** @var string */
46
	protected $php_ext;
47
48
	/** @var array */
49
	protected $times;
50
51
	/** @var string */
52
	public $page_title;
53
54
	/** @var string */
55
	public $tpl_name;
56
57
	/** @var string */
58
	public $u_action;
59
60
	/**
61
	 * ACP module constructor
62
	 *
63
	 * @access public
64
	 */
65
	public function __construct()
66
	{
67
		global $phpbb_container;
68
69
		$this->cache     = $phpbb_container->get('cache');
70
		$this->config    = $phpbb_container->get('config');
71
		$this->db        = $phpbb_container->get('dbal.conn');
72
		$this->fulltext  = $phpbb_container->get('vse.similartopics.fulltext_support');
73
		$this->log       = $phpbb_container->get('log');
74
		$this->request   = $phpbb_container->get('request');
75
		$this->template  = $phpbb_container->get('template');
76
		$this->user      = $phpbb_container->get('user');
77
		$this->root_path = $phpbb_container->getParameter('core.root_path');
78
		$this->php_ext   = $phpbb_container->getParameter('core.php_ext');
79
		$this->times     = array(
80
			'd' => 86400, // one day
81
			'w' => 604800, // one week
82
			'm' => 2626560, // one month
83
			'y' => 31536000, // one year
84
		);
85
	}
86
87
	/**
88
	 * Main ACP module
89
	 *
90
	 * @access public
91
	 */
92
	public function main()
93
	{
94
		$this->user->add_lang_ext('vse/similartopics', 'acp_similar_topics');
95
96
		$this->tpl_name = 'acp_similar_topics';
97
		$this->page_title = $this->user->lang('PST_TITLE_ACP');
98
99
		$form_key = 'acp_similar_topics';
100
		add_form_key($form_key);
101
102
		$action = $this->request->variable('action', '');
103
104
		switch ($action)
105
		{
106
			case 'advanced':
107
				$forum_id = $this->request->variable('f', 0);
108
109
				if ($this->request->is_set_post('submit'))
110
				{
111
					$this->check_form_key($form_key);
112
113
					$similar_topic_forums = $this->request->variable('similar_forums_id', array(0));
114
					$similar_topic_forums = !empty($similar_topic_forums) ? json_encode($similar_topic_forums) : '';
115
116
					$sql = 'UPDATE ' . FORUMS_TABLE . "
117
						SET similar_topic_forums = '" . $this->db->sql_escape($similar_topic_forums) . "'
118
						WHERE forum_id = $forum_id";
119
					$this->db->sql_query($sql);
120
121
					$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'PST_LOG_MSG');
122
123
					$this->end('PST_SAVED');
124
				}
125
126
				$forum_name = '';
127
				$selected = array();
128
				if ($forum_id > 0)
129
				{
130
					$sql = 'SELECT forum_name, similar_topic_forums
131
						FROM ' . FORUMS_TABLE . "
132
						WHERE forum_id = $forum_id";
133
					$result = $this->db->sql_query($sql);
134
					while ($fid = $this->db->sql_fetchrow($result))
135
					{
136
						$selected = json_decode($fid['similar_topic_forums'], true);
137
						$forum_name = $fid['forum_name'];
138
					}
139
					$this->db->sql_freeresult($result);
140
				}
141
142
				$this->template->assign_vars(array(
143
					'S_ADVANCED_SETTINGS'		=> true,
144
					'SIMILAR_FORUMS_OPTIONS'	=> make_forum_select($selected, false, false, true),
145
					'PST_FORUM_NAME'			=> $forum_name,
146
					'PST_ADVANCED_EXP'			=> $this->user->lang('PST_ADVANCED_EXP', $forum_name),
147
					'U_ACTION'					=> $this->u_action . '&amp;action=advanced&amp;f=' . $forum_id,
148
					'U_BACK'					=> $this->u_action,
149
				));
150
			break;
151
152
			default:
153
				if ($this->request->is_set_post('submit'))
154
				{
155
					$this->check_form_key($form_key);
156
157
					// Set basic config settings
158
					$this->config->set('similar_topics', $this->request->variable('pst_enable', 0));
159
					$this->config->set('similar_topics_limit', abs($this->request->variable('pst_limit', 0))); // use abs for positive values only
160
					$this->config->set('similar_topics_cache', abs($this->request->variable('pst_cache', 0))); // use abs for positive values only
161
					$this->config->set('similar_topics_words', $this->request->variable('pst_words', '', true));
162
163
					// Set sensitivity
164
					$pst_sense = min(abs($this->request->variable('pst_sense', 5)), 10); // use abs for positive values only
165
					$this->config->set('similar_topics_sense', $pst_sense);
166
167
					// Set date/time config settings
168
					$pst_time = abs($this->request->variable('pst_time', 0)); // use abs for positive values only
169
					$pst_time_type = $this->request->variable('pst_time_type', '');
170
					$this->config->set('similar_topics_type', $pst_time_type);
171
					$this->config->set('similar_topics_time', $this->set_pst_time($pst_time, $pst_time_type));
172
173
					// Set PostgreSQL TS Name
174
					if ($this->fulltext->is_postgres())
175
					{
176
						$ts_name = $this->request->variable('pst_postgres_ts_name',
177
								($this->config->offsetExists('fulltext_postgres_ts_name')? $this->config['fulltext_postgres_ts_name'] : 'simple'));
178
						$this->config->set('similar_topics_postgres_ts_name', $ts_name);
179
						$this->create_postgres_index($ts_name);
180
					}
181
182
					// Set checkbox array form data
183
					$this->update_forum('similar_topics_hide', $this->request->variable('mark_noshow_forum', array(0), true));
184
					$this->update_forum('similar_topics_ignore', $this->request->variable('mark_ignore_forum', array(0), true));
185
186
					$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'PST_LOG_MSG');
187
188
					$this->cache->destroy('sql', TOPICS_TABLE);
189
190
					$this->end('PST_SAVED');
191
				}
192
193
				// Allow option to update the database to enable FULLTEXT support
194
				if ($this->request->is_set_post('fulltext'))
195
				{
196
					if (confirm_box(true))
197
					{
198
						// If FULLTEXT is not supported, lets make it so
199
						if (!$this->fulltext_support_enabled())
200
						{
201
							// Alter the database to support FULLTEXT
202
							$this->enable_fulltext_support();
203
204
							// Store the original database storage engine in a config var for recovery on uninstall
205
							$this->config->set('similar_topics_fulltext', (string) $this->fulltext->get_engine());
206
207
							$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'PST_LOG_FULLTEXT', time(), array(TOPICS_TABLE));
208
209
							$this->end('PST_SAVE_FULLTEXT');
210
						}
211
						$this->end('PST_ERR_FULLTEXT', E_USER_WARNING);
212
					}
213
					confirm_box(false, $this->user->lang('CONFIRM_OPERATION'), build_hidden_fields(array(
214
						'fulltext' => 1,
215
					)));
216
				}
217
218
				// Build the time options select menu
219
				$time_options = array(
220
					'd' => $this->user->lang('PST_DAYS'),
221
					'w' => $this->user->lang('PST_WEEKS'),
222
					'm' => $this->user->lang('PST_MONTHS'),
223
					'y' => $this->user->lang('PST_YEARS')
224
				);
225
				foreach ($time_options as $value => $label)
226
				{
227
					$this->template->assign_block_vars('similar_time_options', array(
228
						'VALUE'			=> $value,
229
						'LABEL'			=> $label,
230
						'S_SELECTED'	=> $value == $this->config['similar_topics_type'],
231
					));
232
				}
233
234
				$this->template->assign_vars(array(
235
					'S_PST_ENABLE'		=> $this->isset_or_default($this->config['similar_topics'], false),
236
					'PST_LIMIT'			=> $this->isset_or_default($this->config['similar_topics_limit'], ''),
237
					'PST_CACHE'			=> $this->isset_or_default($this->config['similar_topics_cache'], ''),
238
					'PST_SENSE'			=> $this->isset_or_default($this->config['similar_topics_sense'], ''),
239
					'PST_WORDS'			=> $this->isset_or_default($this->config['similar_topics_words'], ''),
240
					'PST_TIME'			=> $this->get_pst_time($this->config['similar_topics_time'], $this->config['similar_topics_type']),
241
					'S_PST_NO_SUPPORT'	=> !$this->fulltext_support_enabled(),
242
					'S_PST_NO_MYSQL'	=> !$this->fulltext->is_mysql(),
243
					'S_PST_IS_POSTGRES'	=> $this->fulltext->is_postgres(),
244
					'U_ACTION'			=> $this->u_action,
245
				));
246
247
				if ($this->fulltext->is_postgres())
248
				{
249
					$sql = 'SELECT cfgname AS ts_name
250
					FROM pg_ts_config';
251
					$result = $this->db->sql_query($sql);
252
					$ts_options = '';
253
254
					while ($row = $this->db->sql_fetchrow($result))
255
					{
256
						$ts_options .= '<option value="' . $row['ts_name'] . '"' . ($row['ts_name'] === $this->config['similar_topics_postgres_ts_name'] ? ' selected="selected"' : '') . '>' . $row['ts_name'] . '</option>';
257
					}
258
					$this->db->sql_freeresult($result);
259
260
					$this->template->assign_vars(array(
261
						'S_POSTGRES_TS_NAME_OPTIONS' => $ts_options,
262
					));
263
				}
264
265
				$forum_list = $this->get_forum_list();
266
				foreach ($forum_list as $row)
267
				{
268
					$this->template->assign_block_vars('forums', array(
269
						'FORUM_NAME'			=> $row['forum_name'],
270
						'FORUM_ID'				=> $row['forum_id'],
271
						'CHECKED_IGNORE_FORUM'	=> $row['similar_topics_ignore'] ? 'checked="checked"' : '',
272
						'CHECKED_NOSHOW_FORUM'	=> $row['similar_topics_hide'] ? 'checked="checked"' : '',
273
						'S_IS_ADVANCED'			=> (bool) $row['similar_topic_forums'],
274
						'U_ADVANCED'			=> "{$this->u_action}&amp;action=advanced&amp;f=" . $row['forum_id'],
275
						'U_FORUM'				=> append_sid("{$this->root_path}viewforum.{$this->php_ext}", 'f=' . $row['forum_id']),
276
					));
277
				}
278
			break;
279
		}
280
	}
281
282
	/**
283
	 * Check form key, trigger error if invalid
284
	 *
285
	 * @access protected
286
	 * @param string $form_key The form key value
287
	 */
288
	protected function check_form_key($form_key)
289
	{
290
		if (!check_form_key($form_key))
291
		{
292
			$this->end('FORM_INVALID', E_USER_WARNING);
293
		}
294
	}
295
296
	/**
297
	 * Get forums list
298
	 *
299
	 * @access protected
300
	 * @return array forum data rows
301
	 */
302
	protected function get_forum_list()
303
	{
304
		$sql = 'SELECT forum_id, forum_name, similar_topic_forums, similar_topics_hide, similar_topics_ignore
305
			FROM ' . FORUMS_TABLE . '
306
			WHERE forum_type = ' . FORUM_POST . '
307
			ORDER BY left_id ASC';
308
		$result = $this->db->sql_query($sql);
309
		$forum_list = $this->db->sql_fetchrowset($result);
310
		$this->db->sql_freeresult($result);
311
312
		return $forum_list;
313
	}
314
315
	/**
316
	 * Update the similar topics columns in the forums table
317
	 *
318
	 * @param string $column    The name of the column to update
319
	 * @param array  $forum_ids An array of forum_ids
320
	 */
321
	protected function update_forum($column, $forum_ids)
322
	{
323
		$this->db->sql_transaction('begin');
324
325
		// Set marked forums (in set) to 1
326
		$sql = 'UPDATE ' . FORUMS_TABLE . "
327
			SET $column = 1
328
			WHERE " . $this->db->sql_in_set('forum_id', $forum_ids, false, true);
329
		$this->db->sql_query($sql);
330
331
		// Set unmarked forums (not in set) to 0
332
		$sql = 'UPDATE ' . FORUMS_TABLE . "
333
			SET $column = 0
334
			WHERE " . $this->db->sql_in_set('forum_id', $forum_ids, true, true);
335
		$this->db->sql_query($sql);
336
337
		$this->db->sql_transaction('commit');
338
	}
339
340
	/**
341
	 * Calculate the time in seconds based on requested time period length
342
	 *
343
	 * @access protected
344
	 * @param int    $length user entered value
345
	 * @param string $type   years, months, weeks, days (y|m|w|d)
346
	 * @return int time in seconds
347
	 */
348
	protected function set_pst_time($length, $type = 'y')
349
	{
350
		$type = isset($this->times[$type]) ? $type : 'y';
351
352
		return (int) ($length * $this->times[$type]);
353
	}
354
355
	/**
356
	 * Get the correct time period length value for the form
357
	 *
358
	 * @access protected
359
	 * @param int    $time as a timestamp
360
	 * @param string $type years, months, weeks, days (y|m|w|d)
361
	 * @return int time converted to the given $type
362
	 */
363
	protected function get_pst_time($time, $type = '')
364
	{
365
		return isset($this->times[$type]) ? (int) round($time / $this->times[$type]) : 0;
366
	}
367
368
	/**
369
	 * Check for FULLTEXT index support
370
	 *
371
	 * @access protected
372
	 * @return bool True if FULLTEXT is fully supported, false otherwise
373
	 */
374
	protected function fulltext_support_enabled()
375
	{
376
		if ($this->fulltext->is_supported())
377
		{
378
			return $this->fulltext->is_index('topic_title');
379
		}
380
381
		return false;
382
	}
383
384
	/**
385
	 * Enable FULLTEXT support for the topic_title
386
	 *
387
	 * @access protected
388
	 */
389
	protected function enable_fulltext_support()
390
	{
391
		if (!$this->fulltext->is_mysql())
392
		{
393
			$this->end('PST_NO_MYSQL', E_USER_WARNING);
394
		}
395
396
		// Alter the storage engine
397
		$sql = 'ALTER TABLE ' . TOPICS_TABLE . ' ENGINE = MYISAM';
398
		$this->db->sql_query($sql);
399
400
		// Prevent adding extra indeces.
401
		if ($this->fulltext->is_index('topic_title'))
402
		{
403
			return;
404
		}
405
406
		$sql = 'ALTER TABLE ' . TOPICS_TABLE . ' ADD FULLTEXT (topic_title)';
407
		$this->db->sql_query($sql);
408
	}
409
410
411
	/**
412
	 * Enable FULLTEXT support for the topic_title
413
	 *
414
	 * @access protected
415
	 */
416
	protected function create_postgres_index($ts_name)
417
	{
418
		if (!$this->fulltext->is_postgres())
419
		{
420
			$this->end('PST_NO_MYSQL', E_USER_WARNING);
421
		}
422
423
		$indexed = false;
424
		// Prevent adding extra indeces.
425
426
		foreach($this->fulltext->get_pg_indexes() as $index)
427
		{
428
			if ($index == TOPICS_TABLE . '_' . $ts_name . '_topic_title')
429
			{
430
				$indexed = true;
431
			} else {
432
				$sql = 'DROP INDEX ' . $index;
433
				$this->db->sql_query($sql);
434
			}
435
		}
436
437
		if (!$indexed)
438
		{
439
			$sql = "CREATE INDEX " . TOPICS_TABLE . "_" . $ts_name . "_topic_title ON " . TOPICS_TABLE . " USING gin (to_tsvector ('" . $ts_name . "', topic_title))";
440
			$this->db->sql_query($sql);
441
		}
442
	}
443
	/**
444
	 * Return a variable if it is set, otherwise default
445
	 *
446
	 * @access protected
447
	 * @param mixed $var     The variable to test
448
	 * @param mixed $default The default value to use
449
	 * @return mixed The value of the variable if set, otherwise default value
450
	 */
451
	protected function isset_or_default($var, $default)
452
	{
453
		return null !== $var ? $var : $default;
454
	}
455
456
	/**
457
	 * End script execution with a trigger_error message
458
	 *
459
	 * @access protected
460
	 * @param string $message Language key string
461
	 * @param int    $code    E_USER_NOTICE|E_USER_WARNING
462
	 * @return void
463
	 */
464
	protected function end($message, $code = E_USER_NOTICE)
465
	{
466
		trigger_error($this->user->lang($message) . adm_back_link($this->u_action), $code);
467
	}
468
}
469