list_integration_hooks_data()   F
last analyzed

Complexity

Conditions 37
Paths 9112

Size

Total Lines 199
Code Lines 105

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 1406

Importance

Changes 0
Metric Value
cc 37
eloc 105
nc 9112
nop 3
dl 0
loc 199
ccs 0
cts 158
cp 0
crap 1406
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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
 * Functions to support addon settings controller
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
 * This file contains code covered by:
11
 * copyright: 2011 Simple Machines (http://www.simplemachines.org)
12
 *
13
 * @version 2.0 dev
14
 *
15
 */
16
17
/**
18
 * Gets all files in a directory and its children directories
19
 *
20
 * @param string $dir_path
21
 * @return array
22
 * @package AddonSettings
23
 */
24
function get_files_recursive($dir_path)
25
{
26
	$files = array();
27
28
	try
29
	{
30
		$iterator = new RecursiveIteratorIterator(
31
			new RecursiveDirectoryIterator($dir_path, FilesystemIterator::SKIP_DOTS),
32
			RecursiveIteratorIterator::SELF_FIRST,
33
			RecursiveIteratorIterator::CATCH_GET_CHILD
34
		);
35
36
		foreach ($iterator as $file)
37
		{
38
			if ($file->isFile())
39
			{
40
				$files[] = array('dir' => $file->getPath(), 'name' => $file->getFilename());
41
			}
42
		}
43
	}
44
	catch (UnexpectedValueException $e)
45
	{
46
		// @todo, give them a prize
47
	}
48
49
	return $files;
50
}
51
52
/**
53
 * Callback function for the integration hooks list (list_integration_hooks)
54
 *
55
 * What it does:
56
 *
57
 * - Gets all of the hooks in the system and their status
58
 * - Would be better documented if Ema was not lazy
59
 *
60
 * @param int $start The item to start with (for pagination purposes)
61
 * @param int $items_per_page The number of items to show per page
62
 * @param string $sort A string indicating how to sort the results
63
 * @return array
64
 * @package AddonSettings
65
 */
66
function list_integration_hooks_data($start, $items_per_page, $sort)
67
{
68
	global $txt, $context, $scripturl;
69
70
	require_once(SUBSDIR . '/Package.subs.php');
71
72
	$hooks = $temp_hooks = get_integration_hooks();
73
	$hooks_data = $temp_data = $hook_status = array();
74
75
	$files = get_files_recursive(SOURCEDIR);
76
	if (!empty($files))
77
	{
78
		foreach ($files as $file)
79
		{
80
			if (is_file($file['dir'] . '/' . $file['name']) && substr($file['name'], -4) === '.php')
81
			{
82
				$fp = fopen($file['dir'] . '/' . $file['name'], 'rb');
83
				$fc = strtr(fread($fp, max(filesize($file['dir'] . '/' . $file['name']), 1)), array("\r" => '', "\n" => ''));
84
				fclose($fp);
85
86
				foreach ($temp_hooks as $hook => $functions)
87
				{
88
					foreach ($functions as $function_o)
89
					{
90
						$hook_name = str_replace(']', '', $function_o);
91
92
						if (strpos($hook_name, '::') !== false)
93
						{
94
							$function = explode('::', $hook_name);
95
							$class = $function[0];
96
							$function = $function[1];
97
						}
98
						else
99
						{
100
							$class = '';
101
							$function = $hook_name;
102
						}
103
104
						$function = explode('|', $function);
105
						$function = $function[0];
106
107
						if (substr($hook, -8) === '_include')
108
						{
109
							$real_path = parse_path(trim($hook_name));
110
111
							if ($real_path == $hook_name)
112
							{
113
								$hook_status[$hook][$hook_name]['exists'] = false;
114
							}
115
							else
116
							{
117
								$hook_status[$hook][$hook_name]['exists'] = file_exists(parse_path(ltrim($real_path, '|')));
118
							}
119
120
							// I need to know if there is at least one function called in this file.
121
							$temp_data['include'][basename($function)] = array('hook' => $hook, 'function' => $function);
122
							unset($temp_hooks[$hook][$function_o]);
123
						}
124
						// Procedural functions as easy
125
						elseif (empty($class) && strpos(str_replace(' (', '(', $fc), 'function ' . trim($function) . '(') !== false)
126
						{
127
							$hook_status[$hook][$hook_name]['exists'] = true;
128
							$hook_status[$hook][$hook_name]['in_file'] = $file['name'];
129
130
							// I want to remember all the functions called within this file (to check later if they are
131
							// enabled or disabled and decide if the integrate_*_include of that file can be disabled too)
132
							$temp_data['function'][$file['name']][] = $function_o;
133
							unset($temp_hooks[$hook][$function_o]);
134
						}
135
						// OOP a bit more difficult
136
						elseif (!empty($class) && preg_match('~class\s*' . preg_quote(trim($class)) . '.*function\s*' . preg_quote(trim($function), '~') . '\s*\(~i', $fc) != 0)
137
						{
138
							$hook_status[$hook][$hook_name]['exists'] = true;
139
							$hook_status[$hook][$hook_name]['in_file'] = $file['name'];
140
141
							// I want to remember all the functions called within this file (to check later if they are
142
							// enabled or disabled and decide if the integrate_*_include of that file can be disabled too)
143
							$temp_data['function'][$file['name']][] = $function_o;
144
							unset($temp_hooks[$hook][$function_o]);
145
						}
146
					}
147
				}
148
			}
149
		}
150
	}
151
152
	$sort_types = array(
153
		'hook_name' => array('hook_name', SORT_ASC),
154
		'hook_name DESC' => array('hook_name', SORT_DESC),
155
		'function_name' => array('function_name', SORT_ASC),
156
		'function_name DESC' => array('function_name', SORT_DESC),
157
		'file_name' => array('file_name', SORT_ASC),
158
		'file_name DESC' => array('file_name', SORT_DESC),
159
		'status' => array('status', SORT_ASC),
160
		'status DESC' => array('status', SORT_DESC),
161
	);
162
163
	$sort_options = $sort_types[$sort];
164
	$sort = array();
165
	$hooks_filters = array();
166
167
	foreach ($hooks as $hook => $functions)
168
	{
169
		$hooks_filters[] = '<option ' . ($context['current_filter'] == $hook ? 'selected="selected" ' : '') . ' value="' . $hook . '">' . $hook . '</option>';
170
		foreach ($functions as $function)
171
		{
172
			$function = str_replace(']', '', $function);
173
174
			// This is a not an include and the function is included in a certain file (if not it doesn't exists so don't care)
175
			if (substr($hook, -8) !== '_include' && isset($hook_status[$hook][$function]['in_file']))
176
			{
177
				$current_hook = $temp_data['include'][$hook_status[$hook][$function]['in_file']] ?? '';
178
				$enabled = false;
179
180
				// Checking all the functions within this particular file
181
				// if any of them is enable then the file *must* be included and the integrate_*_include hook cannot be disabled
182
				foreach ($temp_data['function'][$hook_status[$hook][$function]['in_file']] as $func)
183
				{
184
					$enabled = $enabled || strstr($func, ']') !== false;
185
				}
186
187
				if (!$enabled && !empty($current_hook))
188
				{
189
					$hook_status[$current_hook['hook']][$current_hook['function']]['enabled'] = true;
190
				}
191
			}
192
		}
193
	}
194
195
	theme()->addInlineJavascript('
196
			var hook_name_header = document.getElementById(\'header_list_integration_hooks_hook_name\');
197
			hook_name_header.innerHTML += ' . JavaScriptEscape('
198
				<select onchange="window.location = \'' . $scripturl . '?action=admin;area=maintain;sa=hooks\' + (this.value ? \';filter=\' + this.value : \'\');">
199
					<option>---</option>
200
					<option value="">' . $txt['hooks_reset_filter'] . '</option>' . implode('', $hooks_filters) . '</select>' . '
201
				</select>') . ';', true);
202
203
	$temp_data = array();
204
	$id = 0;
205
206
	foreach ($hooks as $hook => $functions)
207
	{
208
		if (empty($context['filter']) || (!empty($context['filter']) && $context['filter'] == $hook))
209
		{
210
			foreach ($functions as $function)
211
			{
212
				$enabled = strstr($function, ']') === false;
213
				$function = str_replace(']', '', $function);
214
				$hook_exists = !empty($hook_status[$hook][$function]['exists']);
215
216
				if (strpos($function, '::') !== false)
217
				{
218
					$function = explode('::', $function);
219
					$function = $function[1];
220
				}
221
222
				$exploded = explode('|', $function);
223
224
				$temp_data[] = array(
225
					'id' => 'hookid_' . ($id++),
226
					'hook_name' => $hook,
227
					'function_name' => $function,
228
					'real_function' => $exploded[0],
229
					'included_file' => isset($exploded[1]) ? parse_path(trim($exploded[1])) : '',
230
					'file_name' => ($hook_status[$hook][$function]['in_file'] ?? ''),
231
					'hook_exists' => $hook_exists,
232
					'status' => $hook_exists ? ($enabled ? 'allow' : 'moderate') : 'deny',
233
					'img_text' => $txt['hooks_' . ($hook_exists ? ($enabled ? 'active' : 'disabled') : 'missing')],
234
					'enabled' => $enabled,
235
					'can_be_disabled' => false,
236
				);
237
238
				// Build the array of sort to values
239
				$sort_end = end($temp_data);
240
				$sort[] = $sort_end[$sort_options[0]];
241
			}
242
		}
243
	}
244
245
	array_multisort($sort, $sort_options[1], $temp_data);
246
247
	$counter = 0;
248
	$start++;
249
250
	foreach ($temp_data as $data)
251
	{
252
		if (++$counter < $start)
253
		{
254
			continue;
255
		}
256
		elseif ($counter === $start + $items_per_page)
257
		{
258
			break;
259
		}
260
261
		$hooks_data[] = $data;
262
	}
263
264
	return $hooks_data;
265
}
266
267
/**
268
 * Simply returns the total count of integration hooks
269
 *
270
 * What it does:
271
 *
272
 * - used by createList() as a callback to determine the number of hooks in
273
 * use in the system
274
 *
275
 * @param bool $filter
276
 *
277
 * @return int
278
 * @package AddonSettings
279
 *
280
 */
281
function integration_hooks_count($filter = false)
282
{
283
	$hooks = get_integration_hooks();
284
	$hooks_count = 0;
285
286
	foreach ($hooks as $hook => $functions)
287
	{
288
		if (empty($filter) || ($filter == $hook))
289
		{
290
			$hooks_count += count($functions);
291
		}
292
	}
293
294
	return $hooks_count;
295
}
296
297
/**
298
 * Parses modSettings to create integration hook array
299
 *
300
 * What it does:
301
 *
302
 * - used by createList() callbacks
303
 *
304
 * @return array
305
 * @package AddonSettings
306
 * @staticvar type $integration_hooks
307
 */
308
function get_integration_hooks()
309
{
310
	global $modSettings;
311
	static $integration_hooks = null;
312
313
	if ($integration_hooks === null)
314
	{
315
		$integration_hooks = array();
316
		foreach ($modSettings as $key => $value)
317
		{
318
			if (!empty($value) && substr($key, 0, 10) === 'integrate_')
319
			{
320
				$integration_hooks[$key] = explode(',', $value);
321
			}
322
		}
323
	}
324
325
	return $integration_hooks;
326
}
327