similar_topics   F
last analyzed

Complexity

Total Complexity 63

Size/Duplication

Total Lines 456
Duplicated Lines 0 %

Importance

Changes 34
Bugs 2 Features 0
Metric Value
eloc 164
c 34
b 2
f 0
dl 0
loc 456
rs 3.36
wmc 63

10 Methods

Rating   Name   Duplication   Size   Complexity  
A is_available() 0 3 3
A is_viewable() 0 3 2
A __construct() 0 19 1
A is_enabled() 0 3 2
A english_lang() 0 3 2
A get_ignore_words() 0 14 3
A clean_topic_title() 0 11 3
F display_similar_topics() 0 196 40
A strip_stop_words() 0 33 4
A make_word_array() 0 16 3

How to fix   Complexity   

Complex Class

Complex classes like similar_topics often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use similar_topics, and based on these observations, apply Extract Interface, too.

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\core;
12
13
use phpbb\auth\auth;
0 ignored issues
show
Bug introduced by
The type phpbb\auth\auth was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
14
use phpbb\cache\service as cache;
0 ignored issues
show
Bug introduced by
The type phpbb\cache\service was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
15
use phpbb\config\config;
0 ignored issues
show
Bug introduced by
The type phpbb\config\config was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
use phpbb\config\db_text;
0 ignored issues
show
Bug introduced by
The type phpbb\config\db_text was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
use phpbb\content_visibility;
0 ignored issues
show
Bug introduced by
The type phpbb\content_visibility was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
18
use phpbb\db\driver\driver_interface as db;
0 ignored issues
show
Bug introduced by
The type phpbb\db\driver\driver_interface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
use phpbb\event\dispatcher_interface as dispatcher;
0 ignored issues
show
Bug introduced by
The type phpbb\event\dispatcher_interface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
20
use phpbb\extension\manager as ext_manager;
0 ignored issues
show
Bug introduced by
The type phpbb\extension\manager was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
21
use phpbb\language\language;
0 ignored issues
show
Bug introduced by
The type phpbb\language\language was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
22
use phpbb\pagination;
0 ignored issues
show
Bug introduced by
The type phpbb\pagination was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
23
use phpbb\request\request;
0 ignored issues
show
Bug introduced by
The type phpbb\request\request was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
24
use phpbb\template\template;
0 ignored issues
show
Bug introduced by
The type phpbb\template\template was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
25
use phpbb\user;
0 ignored issues
show
Bug introduced by
The type phpbb\user was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
26
use vse\similartopics\driver\driver_interface as similartopics_driver;
27
use vse\similartopics\driver\manager as similartopics_manager;
28
29
class similar_topics
30
{
31
	/** @var auth */
32
	protected $auth;
33
34
	/** @var cache */
35
	protected $cache;
36
37
	/** @var config */
38
	protected $config;
39
40
	/** @var db_text */
41
	protected $config_text;
42
43
	/** @var db */
44
	protected $db;
45
46
	/** @var dispatcher */
47
	protected $dispatcher;
48
49
	/** @var ext_manager */
50
	protected $extension_manager;
51
52
	/** @var language */
53
	protected $language;
54
55
	/** @var pagination */
56
	protected $pagination;
57
58
	/** @var request */
59
	protected $request;
60
61
	/** @var template */
62
	protected $template;
63
64
	/** @var user */
65
	protected $user;
66
67
	/** @var content_visibility */
68
	protected $content_visibility;
69
70
	/** @var similartopics_driver */
71
	protected $similartopics;
72
73
	/** @var string phpBB root path  */
74
	protected $root_path;
75
76
	/** @var string PHP file extension */
77
	protected $php_ext;
78
79
	/** @var string String of custom ignore words */
80
	protected $ignore_words;
81
82
	/**
83
	 * Constructor
84
	 *
85
	 * @access public
86
	 * @param auth                  $auth
87
	 * @param cache                 $cache
88
	 * @param config                $config
89
	 * @param db_text               $config_text
90
	 * @param db                    $db
91
	 * @param dispatcher            $dispatcher
92
	 * @param ext_manager           $extension_manager
93
	 * @param language              $language
94
	 * @param pagination            $pagination
95
	 * @param request               $request
96
	 * @param template              $template
97
	 * @param user                  $user
98
	 * @param content_visibility    $content_visibility
99
	 * @param similartopics_manager $similartopics_manager
100
	 * @param string                $root_path
101
	 * @param string                $php_ext
102
	 */
103
	public function __construct(auth $auth, cache $cache, config $config, db_text $config_text, db $db, dispatcher $dispatcher, ext_manager $extension_manager, language $language, pagination $pagination, request $request, template $template, user $user, content_visibility $content_visibility, similartopics_manager $similartopics_manager, $root_path, $php_ext)
104
	{
105
		$this->auth = $auth;
106
		$this->cache = $cache;
107
		$this->config = $config;
108
		$this->config_text = $config_text;
109
		$this->db = $db;
110
		$this->dispatcher = $dispatcher;
111
		$this->extension_manager = $extension_manager;
112
		$this->language = $language;
113
		$this->pagination = $pagination;
114
		$this->request = $request;
115
		$this->template = $template;
116
		$this->user = $user;
117
		$this->content_visibility = $content_visibility;
118
		$this->root_path = $root_path;
119
		$this->php_ext = $php_ext;
120
121
		$this->similartopics = $similartopics_manager->get_driver($db->get_sql_layer());
122
	}
123
124
	/**
125
	 * Is similar topics available?
126
	 *
127
	 * @access public
128
	 * @return bool True if available, false otherwise
129
	 */
130
	public function is_available()
131
	{
132
		return $this->is_enabled() && $this->is_viewable() && $this->similartopics !== null;
133
	}
134
135
	/**
136
	 * Is similar topics configured?
137
	 *
138
	 * @access public
139
	 * @return bool True if configured, false otherwise
140
	 */
141
	public function is_enabled()
142
	{
143
		return !empty($this->config['similar_topics']) && !empty($this->config['similar_topics_limit']);
144
	}
145
146
	/**
147
	 * Is similar topics viewable by the user?
148
	 *
149
	 * @access public
150
	 * @return bool True if viewable, false otherwise
151
	 */
152
	public function is_viewable()
153
	{
154
		return !empty($this->user->data['user_similar_topics']) && $this->auth->acl_get('u_similar_topics');
155
	}
156
157
	/**
158
	 * Get similar topics by matching topic titles
159
	 * Loosely based on viewforum.php lines 840-1040
160
	 *
161
	 * NOTE: FULLTEXT has built-in English ignore words. We use phpBB's
162
	 * ignore words for non-English languages. We also remove any
163
	 * admin-defined special ignore words.
164
	 *
165
	 * @access public
166
	 * @param array $topic_data Array with topic data
167
	 */
168
	public function display_similar_topics($topic_data)
169
	{
170
		// If the forum should not display similar topics, no need to continue
171
		if ($topic_data['similar_topics_hide'])
172
		{
173
			return;
174
		}
175
176
		$topic_title = $this->clean_topic_title($topic_data['topic_title']);
177
178
		// If the cleaned up topic_title is empty, no need to continue
179
		if (empty($topic_title))
180
		{
181
			return;
182
		}
183
184
		// Get stored sensitivity value and divide by 10. In query, it should be a number between 0.0 to 1.0.
185
		$sensitivity = $this->config->offsetExists('similar_topics_sense') ? number_format($this->config['similar_topics_sense'] / 10, 1, '.', '') : '0.5';
186
187
		// Similar Topics SQL query is generated in similar topics driver
188
		$sql_array = $this->similartopics->get_query($topic_data['topic_id'], $topic_title, $this->config['similar_topics_time'], $sensitivity);
0 ignored issues
show
Bug introduced by
$sensitivity of type string is incompatible with the type double expected by parameter $sensitivity of vse\similartopics\driver..._interface::get_query(). ( Ignorable by Annotation )

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

188
		$sql_array = $this->similartopics->get_query($topic_data['topic_id'], $topic_title, $this->config['similar_topics_time'], /** @scrutinizer ignore-type */ $sensitivity);
Loading history...
189
190
		// Add topic tracking data to the query (only if query caching is off)
191
		if ($this->user->data['is_registered'] && $this->config['load_db_lastread'] && !$this->config['similar_topics_cache'])
192
		{
193
			$sql_array['LEFT_JOIN'][] = array('FROM' => array(TOPICS_TRACK_TABLE => 'tt'), 'ON' => 'tt.topic_id = t.topic_id AND tt.user_id = ' . $this->user->data['user_id']);
0 ignored issues
show
Bug introduced by
The constant vse\similartopics\core\TOPICS_TRACK_TABLE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
194
			$sql_array['LEFT_JOIN'][] = array('FROM' => array(FORUMS_TRACK_TABLE => 'ft'), 'ON' => 'ft.forum_id = f.forum_id AND ft.user_id = ' . $this->user->data['user_id']);
0 ignored issues
show
Bug introduced by
The constant vse\similartopics\core\FORUMS_TRACK_TABLE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
195
			$sql_array['SELECT'] .= ', tt.mark_time, ft.mark_time as f_mark_time';
196
		}
197
		else if ($this->config['load_anon_lastread'] || $this->user->data['is_registered'])
198
		{
199
			// Cookie based tracking copied from search.php
200
			$tracking_topics = $this->request->variable($this->config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE);
0 ignored issues
show
Bug introduced by
The type phpbb\request\request_interface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
201
			$tracking_topics = $tracking_topics ? tracking_unserialize($tracking_topics) : array();
0 ignored issues
show
Bug introduced by
The function tracking_unserialize was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

201
			$tracking_topics = $tracking_topics ? /** @scrutinizer ignore-call */ tracking_unserialize($tracking_topics) : array();
Loading history...
202
		}
203
204
		// We need to exclude passworded forums, so we do not leak the topic title
205
		$passworded_forums = $this->user->get_passworded_forums();
206
207
		// See if the admin set this forum to only search a specific group of other forums, and include them
208
		if (!empty($topic_data['similar_topic_forums']))
209
		{
210
			// Remove any passworded forums from this group of forums we will be searching
211
			$included_forums = array_diff(json_decode($topic_data['similar_topic_forums'], true), $passworded_forums);
212
			// if there's nothing left to display (user has no access to the forums we want to search)
213
			if (empty($included_forums))
214
			{
215
				return;
216
			}
217
218
			$sql_array['WHERE'] .= ' AND ' . $this->db->sql_in_set('f.forum_id', $included_forums);
219
		}
220
		// Otherwise, exclude any ignored forums
221
		else
222
		{
223
			// Remove any passworded forums
224
			if (count($passworded_forums))
225
			{
226
				$sql_array['WHERE'] .= ' AND ' . $this->db->sql_in_set('f.forum_id', $passworded_forums, true);
227
			}
228
229
			$sql_array['WHERE'] .= ' AND f.similar_topics_ignore = 0';
230
		}
231
232
		/**
233
		 * Event to modify the sql_array for similar topics
234
		 *
235
		 * @event vse.similartopics.get_topic_data
236
		 * @var array sql_array SQL array to get similar topics data
237
		 * @since 1.3.0
238
		 */
239
		$vars = array('sql_array');
240
		extract($this->dispatcher->trigger_event('vse.similartopics.get_topic_data', compact($vars)));
241
242
		$rowset = array();
243
244
		$sql = $this->db->sql_build_query('SELECT', $sql_array);
245
		$result = $this->db->sql_query_limit($sql, $this->config['similar_topics_limit'], 0, $this->config['similar_topics_cache']);
246
		while ($row = $this->db->sql_fetchrow($result))
247
		{
248
			$rowset[(int) $row['topic_id']] = $row;
249
		}
250
		$this->db->sql_freeresult($result);
251
252
		// Grab icons
253
		$icons = $this->cache->obtain_icons();
254
255
		/**
256
		 * Modify the rowset data for similar topics
257
		 *
258
		 * @event vse.similartopics.modify_rowset
259
		 * @var	array rowset Array with the search results data
260
		 * @since 1.4.2
261
		 */
262
		$vars = array('rowset');
263
		extract($this->dispatcher->trigger_event('vse.similartopics.modify_rowset', compact($vars)));
264
265
		foreach ($rowset as $row)
266
		{
267
			$similar_forum_id = (int) $row['forum_id'];
268
			$similar_topic_id = (int) $row['topic_id'];
269
270
			if ($this->auth->acl_get('f_read', $similar_forum_id))
271
			{
272
				// Get topic tracking info
273
				if ($this->user->data['is_registered'] && $this->config['load_db_lastread'] && !$this->config['similar_topics_cache'])
274
				{
275
					$topic_tracking_info = get_topic_tracking($similar_forum_id, $similar_topic_id, $rowset, array($similar_forum_id => $row['f_mark_time']));
0 ignored issues
show
Bug introduced by
The function get_topic_tracking was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

275
					$topic_tracking_info = /** @scrutinizer ignore-call */ get_topic_tracking($similar_forum_id, $similar_topic_id, $rowset, array($similar_forum_id => $row['f_mark_time']));
Loading history...
276
				}
277
				else if ($this->config['load_anon_lastread'] || $this->user->data['is_registered'])
278
				{
279
					$topic_tracking_info = get_complete_topic_tracking($similar_forum_id, $similar_topic_id);
0 ignored issues
show
Bug introduced by
The function get_complete_topic_tracking was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

279
					$topic_tracking_info = /** @scrutinizer ignore-call */ get_complete_topic_tracking($similar_forum_id, $similar_topic_id);
Loading history...
280
281
					if (!$this->user->data['is_registered'])
282
					{
283
						$this->user->data['user_lastmark'] = isset($tracking_topics['l']) ? ((int) base_convert($tracking_topics['l'], 36, 10) + (int) $this->config['board_startdate']) : 0;
284
					}
285
				}
286
287
				// Replies
288
				$replies = $this->content_visibility->get_count('topic_posts', $row, $similar_forum_id) - 1;
289
290
				// Get folder img, topic status/type related information
291
				$folder_img = $folder_alt = $topic_type = '';
292
				$unread_topic = isset($topic_tracking_info[$similar_topic_id]) && $row['topic_last_post_time'] > $topic_tracking_info[$similar_topic_id];
293
				topic_status($row, $replies, $unread_topic, $folder_img, $folder_alt, $topic_type);
0 ignored issues
show
Bug introduced by
The function topic_status was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

293
				/** @scrutinizer ignore-call */ 
294
    topic_status($row, $replies, $unread_topic, $folder_img, $folder_alt, $topic_type);
Loading history...
294
295
				$view_topic_url_params = 't=' . $similar_topic_id;
296
297
				$topic_unapproved = $row['topic_visibility'] == ITEM_UNAPPROVED && $this->auth->acl_get('m_approve', $similar_forum_id);
0 ignored issues
show
Bug introduced by
The constant vse\similartopics\core\ITEM_UNAPPROVED was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
298
				$posts_unapproved = $row['topic_visibility'] == ITEM_APPROVED && $row['topic_posts_unapproved'] && $this->auth->acl_get('m_approve', $similar_forum_id);
0 ignored issues
show
Bug introduced by
The constant vse\similartopics\core\ITEM_APPROVED was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
299
				$u_mcp_queue = ($topic_unapproved || $posts_unapproved) ? append_sid("{$this->root_path}mcp.$this->php_ext", 'i=queue&amp;mode=' . ($topic_unapproved ? 'approve_details' : 'unapproved_posts') . "&amp;t=$similar_topic_id", true, $this->user->session_id) : '';
0 ignored issues
show
Bug introduced by
The function append_sid was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

299
				$u_mcp_queue = ($topic_unapproved || $posts_unapproved) ? /** @scrutinizer ignore-call */ append_sid("{$this->root_path}mcp.$this->php_ext", 'i=queue&amp;mode=' . ($topic_unapproved ? 'approve_details' : 'unapproved_posts') . "&amp;t=$similar_topic_id", true, $this->user->session_id) : '';
Loading history...
300
301
				$base_url = append_sid("{$this->root_path}viewtopic.$this->php_ext", $view_topic_url_params);
302
303
				$topic_row = array(
304
					'TOPIC_AUTHOR_FULL'			=> get_username_string('full', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
0 ignored issues
show
Bug introduced by
The function get_username_string was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

304
					'TOPIC_AUTHOR_FULL'			=> /** @scrutinizer ignore-call */ get_username_string('full', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
Loading history...
305
					'FIRST_POST_TIME'			=> $this->user->format_date($row['topic_time']),
306
					'FIRST_POST_TIME_RFC3339'	=> gmdate(DATE_RFC3339, $row['topic_time']),
307
					'LAST_POST_TIME'			=> $this->user->format_date($row['topic_last_post_time']),
308
					'LAST_POST_TIME_RFC3339'	=> gmdate(DATE_RFC3339, $row['topic_last_post_time']),
309
					'LAST_POST_AUTHOR_FULL'		=> get_username_string('full', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']),
310
311
					'TOPIC_REPLIES'			=> $replies,
312
					'TOPIC_VIEWS'			=> $row['topic_views'],
313
					'TOPIC_TITLE'			=> censor_text($row['topic_title']),
0 ignored issues
show
Bug introduced by
The function censor_text was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

313
					'TOPIC_TITLE'			=> /** @scrutinizer ignore-call */ censor_text($row['topic_title']),
Loading history...
314
					'FORUM_TITLE'			=> $row['forum_name'],
315
316
					'TOPIC_IMG_STYLE'		=> $folder_img,
317
					'TOPIC_FOLDER_IMG'		=> $this->user->img($folder_img, $folder_alt),
318
					'TOPIC_FOLDER_IMG_ALT'	=> $this->language->lang($folder_alt),
319
320
					'TOPIC_ICON_IMG'		=> !empty($icons[$row['icon_id']]) ? $icons[$row['icon_id']]['img'] : '',
321
					'TOPIC_ICON_IMG_WIDTH'	=> !empty($icons[$row['icon_id']]) ? $icons[$row['icon_id']]['width'] : '',
322
					'TOPIC_ICON_IMG_HEIGHT'	=> !empty($icons[$row['icon_id']]) ? $icons[$row['icon_id']]['height'] : '',
323
					'ATTACH_ICON_IMG'		=> ($this->auth->acl_get('u_download') && $this->auth->acl_get('f_download', $similar_forum_id) && $row['topic_attachment']) ? $this->user->img('icon_topic_attach', $this->language->lang('TOTAL_ATTACHMENTS')) : '',
324
					'UNAPPROVED_IMG'		=> ($topic_unapproved || $posts_unapproved) ? $this->user->img('icon_topic_unapproved', $topic_unapproved ? 'TOPIC_UNAPPROVED' : 'POSTS_UNAPPROVED') : '',
325
326
					'S_UNREAD_TOPIC'		=> $unread_topic,
327
					'S_TOPIC_REPORTED'		=> !empty($row['topic_reported']) && $this->auth->acl_get('m_report', $similar_forum_id),
328
					'S_TOPIC_UNAPPROVED'	=> $topic_unapproved,
329
					'S_POSTS_UNAPPROVED'	=> $posts_unapproved,
330
					'S_HAS_POLL'			=> (bool) $row['poll_start'],
331
332
					'U_NEWEST_POST'			=> append_sid("{$this->root_path}viewtopic.$this->php_ext", $view_topic_url_params . '&amp;view=unread') . '#unread',
333
					'U_LAST_POST'			=> append_sid("{$this->root_path}viewtopic.$this->php_ext", $view_topic_url_params . '&amp;p=' . $row['topic_last_post_id']) . '#p' . $row['topic_last_post_id'],
334
					'U_VIEW_TOPIC'			=> $base_url,
335
					'U_VIEW_FORUM'			=> append_sid("{$this->root_path}viewforum.$this->php_ext", 'f=' . $similar_forum_id),
336
					'U_MCP_REPORT'			=> append_sid("{$this->root_path}mcp.$this->php_ext", 'i=reports&amp;mode=reports&amp;' . $view_topic_url_params, true, $this->user->session_id),
337
					'U_MCP_QUEUE'			=> $u_mcp_queue,
338
				);
339
340
				/**
341
				 * Event to modify the similar topics template block
342
				 *
343
				 * @event vse.similartopics.modify_topicrow
344
				 * @var array row       Array with similar topic data
345
				 * @var array topic_row Template block array
346
				 * @since 1.3.0
347
				 */
348
				$vars = array('row', 'topic_row');
349
				extract($this->dispatcher->trigger_event('vse.similartopics.modify_topicrow', compact($vars)));
350
351
				$this->template->assign_block_vars('similar', $topic_row);
352
353
				$this->pagination->generate_template_pagination($base_url, 'similar.pagination', 'start', $replies + 1, $this->config['posts_per_page'], 1, true, true);
354
			}
355
		}
356
357
		$this->language->add_lang('similar_topics', 'vse/similartopics');
358
359
		$this->template->assign_vars(array(
360
			'NEWEST_POST_IMG'	=> $this->user->img('icon_topic_newest', 'VIEW_NEWEST_POST'),
361
			'LAST_POST_IMG'		=> $this->user->img('icon_topic_latest', 'VIEW_LATEST_POST'),
362
			'REPORTED_IMG'		=> $this->user->img('icon_topic_reported', 'TOPIC_REPORTED'),
363
			'POLL_IMG'			=> $this->user->img('icon_topic_poll', 'TOPIC_POLL'),
364
		));
365
	}
366
367
	/**
368
	 * Clean topic title (and if needed, ignore-words)
369
	 *
370
	 * @access public
371
	 * @param string $text The topic title
372
	 * @return string The topic title
373
	 */
374
	public function clean_topic_title($text)
375
	{
376
		// Strip quotes, ampersands
377
		$text = str_replace(array('&quot;', '&amp;'), '', $text);
378
379
		if (!$this->english_lang() || $this->get_ignore_words())
380
		{
381
			$text = $this->strip_stop_words($text);
382
		}
383
384
		return $text;
385
	}
386
387
	/**
388
	 * Remove any non-english and/or custom defined ignore-words
389
	 *
390
	 * @access protected
391
	 * @param string $text The topic title
392
	 * @return string The topic title
393
	 */
394
	protected function strip_stop_words($text)
395
	{
396
		$words = array();
397
398
		// If non-English, look for a list of stop-words to be ignored
399
		// in either the core or the extension (deprecated from core)
400
		if (!$this->english_lang())
401
		{
402
			$finder = $this->extension_manager->get_finder();
403
			$search_ignore_words = $finder
404
				->set_extensions(array('vse/similartopics'))
405
				->prefix('search_ignore_words')
406
				->suffix(".$this->php_ext")
407
				->extension_directory("/language/{$this->user->lang_name}")
408
				->core_path("language/{$this->user->lang_name}/")
409
				->get_files();
410
			if (current($search_ignore_words))
411
			{
412
				include current($search_ignore_words);
413
			}
414
		}
415
416
		if ($this->get_ignore_words())
417
		{
418
			// Merge any custom defined ignore words from the ACP to the stop-words array
419
			$words = array_merge($this->make_word_array($this->get_ignore_words()), $words);
420
		}
421
422
		// Remove stop-words from the topic title text
423
		$words = array_diff($this->make_word_array($text), $words);
424
425
		// Convert our words array back to a string
426
		return implode(' ', $words);
427
	}
428
429
	/**
430
	 * Helper function to split string into an array of words
431
	 *
432
	 * @access protected
433
	 * @param string $text String of plain text words
434
	 * @return array Array of plaintext words
435
	 */
436
	protected function make_word_array($text)
437
	{
438
		// Strip out any non-alpha-numeric characters using PCRE regex syntax
439
		$text = trim(preg_replace('#[^\p{L}\p{N}]+#u', ' ', $text));
440
441
		$words = explode(' ', utf8_strtolower($text));
0 ignored issues
show
Bug introduced by
The function utf8_strtolower was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

441
		$words = explode(' ', /** @scrutinizer ignore-call */ utf8_strtolower($text));
Loading history...
442
		foreach ($words as $key => $word)
443
		{
444
			// Strip words of 2 characters or fewer
445
			if (utf8_strlen(trim($word)) < 3)
0 ignored issues
show
Bug introduced by
The function utf8_strlen was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

445
			if (/** @scrutinizer ignore-call */ utf8_strlen(trim($word)) < 3)
Loading history...
446
			{
447
				unset($words[$key]);
448
			}
449
		}
450
451
		return $words;
452
	}
453
454
	/**
455
	 * Check if English is the current user's language
456
	 *
457
	 * @access protected
458
	 * @return bool True if lang is 'en' or 'en_us', false otherwise
459
	 */
460
	protected function english_lang()
461
	{
462
		return ($this->user->lang_name === 'en' || $this->user->lang_name === 'en_us');
463
	}
464
465
	/**
466
	 * Get custom ignore words if any were defined for similar topics
467
	 *
468
	 * @access protected
469
	 * @return string|null String of ignore words or null if there are none defined
470
	 */
471
	protected function get_ignore_words()
472
	{
473
		$key = 'similar_topics_words';
474
475
		$cache = $this->cache->get_driver();
476
477
		if ($this->ignore_words === null && (($this->ignore_words = $cache->get("_$key")) === false))
478
		{
479
			$this->ignore_words = $this->config_text->get($key);
480
481
			$cache->put("_$key", $this->ignore_words);
482
		}
483
484
		return $this->ignore_words;
485
	}
486
}
487