Completed
Pull Request — development (#2979)
by Stephen
08:55
created

ManageSearch_Controller::_settings()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 33
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 2.0046

Importance

Changes 0
Metric Value
cc 2
eloc 17
nc 2
nop 0
dl 0
loc 33
ccs 17
cts 19
cp 0.8947
crap 2.0046
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * The admin screen to change the search settings.  Allows for the creation \
5
 * of search indexes and search weights
6
 *
7
 * @name      ElkArte Forum
8
 * @copyright ElkArte Forum contributors
9
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause
10
 *
11
 * This file contains code covered by:
12
 * copyright:	2011 Simple Machines (http://www.simplemachines.org)
13
 * license:		BSD, See included LICENSE.TXT for terms and conditions.
14
 *
15
 * @version 1.1 Release Candidate 1
16
 *
17
 */
18
19
/**
20
 * ManageSearch controller admin class.
21
 *
22
 * @package Search
23
 */
24
class ManageSearch_Controller extends Action_Controller
25
{
26
	/**
27
	 * Main entry point for the admin search settings screen.
28
	 *
29
	 * What it does:
30
	 *
31
	 * - It checks permissions, and it forwards to the appropriate function based on
32
	 * the given sub-action.
33
	 * - Defaults to sub-action 'settings'.
34
	 * - Called by ?action=admin;area=managesearch.
35
	 * - Requires the admin_forum permission.
36
	 *
37
	 * @event integrate_sa_manage_search add new search actions
38
	 * @uses ManageSearch template.
39
	 * @uses Search language file.
40
	 * @see  Action_Controller::action_index()
41
	 */
42
	public function action_index()
43
	{
44
		global $context, $txt;
45
46
		loadLanguage('Search');
47
		loadTemplate('ManageSearch');
48
49
		$subActions = array(
50
			'settings' => array($this, 'action_searchSettings_display', 'permission' => 'admin_forum'),
51
			'weights' => array($this, 'action_weight', 'permission' => 'admin_forum'),
52
			'method' => array($this, 'action_edit', 'permission' => 'admin_forum'),
53
			'createfulltext' => array($this, 'action_edit', 'permission' => 'admin_forum'),
54
			'removecustom' => array($this, 'action_edit', 'permission' => 'admin_forum'),
55
			'removefulltext' => array($this, 'action_edit', 'permission' => 'admin_forum'),
56
			'createmsgindex' => array($this, 'action_create', 'permission' => 'admin_forum'),
57
			'managesphinx' => array($this, 'action_managesphinx', 'permission' => 'admin_forum'),
58
			'managesphinxql' => array($this, 'action_managesphinx', 'permission' => 'admin_forum'),
59
		);
60
61
		// Control for actions
62
		$action = new Action('manage_search');
63
64
		// Create the tabs for the template.
65
		$context[$context['admin_menu_name']]['tab_data'] = array(
66
			'title' => $txt['manage_search'],
67
			'help' => 'search',
68
			'description' => $txt['search_settings_desc'],
69
			'tabs' => array(
70
				'method' => array(
71
					'description' => $txt['search_method_desc'],
72
				),
73
				'weights' => array(
74
					'description' => $txt['search_weights_desc'],
75
				),
76
				'settings' => array(
77
					'description' => $txt['search_settings_desc'],
78
				),
79
			),
80
		);
81
82
		// Default the sub-action to 'edit search method'.  Call integrate_sa_manage_search
83
		$subAction = $action->initialize($subActions, 'method');
84
85
		// Final bits
86
		$context['sub_action'] = $subAction;
87
		$context['page_title'] = $txt['search_settings_title'];
88
89
		// Call the right function for this sub-action.
90
		$action->dispatch($subAction);
91
	}
92
93
	/**
94
	 * Edit some general settings related to the search function.
95
	 *
96
	 * - Called by ?action=admin;area=managesearch;sa=settings.
97
	 * - Requires the admin_forum permission.
98
	 *
99
	 * @event integrate_save_search_settings
100
	 * @uses ManageSearch template, 'modify_settings' sub-template.
101
	 */
102
	public function action_searchSettings_display()
103
	{
104
		global $txt, $context, $scripturl, $modSettings;
105
106
		// Initialize the form
107
		$settingsForm = new Settings_Form(Settings_Form::DB_ADAPTER);
108
109
		// Initialize it with our settings
110
		$settingsForm->setConfigVars($this->_settings());
111
112
		$context['page_title'] = $txt['search_settings_title'];
113
		$context['sub_template'] = 'show_settings';
114
115
		$context['search_engines'] = array();
116
		if (!empty($modSettings['additional_search_engines']))
117
		{
118
			$context['search_engines'] = Util::unserialize($modSettings['additional_search_engines']);
119
		}
120
121
		for ($count = 0; $count < 3; $count++)
122
		{
123
			$context['search_engines'][] = array(
124
				'name' => '',
125
				'url' => '',
126
				'separator' => '',
127
			);
128
		}
129
130
		// A form was submitted.
131
		if (isset($this->_req->query->save))
132
		{
133
			checkSession();
134
135
			call_integration_hook('integrate_save_search_settings');
136
137
			if (empty($this->_req->post->search_results_per_page))
138
			{
139
				$this->_req->post->search_results_per_page = !empty($modSettings['search_results_per_page']) ? $modSettings['search_results_per_page'] : $modSettings['defaultMaxMessages'];
140
			}
141
142
			$new_engines = array();
143
			foreach ($this->_req->post->engine_name as $id => $searchengine)
144
			{
145
				$url = trim(str_replace(array('"', '<', '>'), array('&quot;', '&lt;', '&gt;'), $this->_req->post->engine_url[$id]));
146
				// If no url, forget it
147
				if (!empty($searchengine) && !empty($url) && filter_var($url, FILTER_VALIDATE_URL))
148
				{
149
					$new_engines[] = array(
150
						'name' => trim(Util::htmlspecialchars($searchengine, ENT_COMPAT)),
151
						'url' => $url,
152
						'separator' => trim(Util::htmlspecialchars(!empty($this->_req->post->engine_separator[$id]) ? $this->_req->post->engine_separator[$id] : '+', ENT_COMPAT)),
153
					);
154
				}
155
			}
156
			updateSettings(array(
157
				'additional_search_engines' => !empty($new_engines) ? serialize($new_engines) : ''
158
			));
159
160
			$settingsForm->setConfigValues((array) $this->_req->post);
161
			$settingsForm->save();
162
			redirectexit('action=admin;area=managesearch;sa=settings;' . $context['session_var'] . '=' . $context['session_id']);
163
		}
164
165
		// Prep the template!
166
		$context['post_url'] = $scripturl . '?action=admin;area=managesearch;save;sa=settings';
167
		$context['settings_title'] = $txt['search_settings_title'];
168
169
		$settingsForm->prepare();
170
	}
171
172
	/**
173
	 * Retrieve admin search settings
174
	 *
175
	 * @event integrate_modify_search_settings
176
	 */
177 1
	private function _settings()
178
	{
179 1
		global $txt;
180
181
		// What are we editing anyway?
182
		$config_vars = array(
183
			// Permission...
184 1
			array('permissions', 'search_posts'),
185
			// Some simple settings.
186 1
			array('check', 'search_dropdown'),
187 1
			array('int', 'search_results_per_page'),
188 1
			array('int', 'search_max_results', 'subtext' => $txt['search_max_results_disable']),
189 1
			'',
190
			// Some limitations.
191 1
			array('int', 'search_floodcontrol_time', 'subtext' => $txt['search_floodcontrol_time_desc'], 6, 'postinput' => $txt['seconds']),
192 1
			array('title', 'additional_search_engines'),
193 1
			array('callback', 'external_search_engines'),
194 1
		);
195
196
		// Perhaps the search method wants to add some settings?
197 1
		$search = new \ElkArte\Search\Search();
198 1
		$searchAPI = $search->findSearchAPI();
199
200 1
		if (is_callable(array($searchAPI, 'searchSettings')))
201 1
		{
202
			call_user_func_array($searchAPI->searchSettings);
203
		}
204
205
		// Add new settings with a nice hook, makes them available for admin settings search as well
206 1
		call_integration_hook('integrate_modify_search_settings', array(&$config_vars));
207
208 1
		return $config_vars;
209
	}
210
211
	/**
212
	 * Return the search settings for use in admin search
213
	 */
214 1
	public function settings_search()
215
	{
216 1
		return $this->_settings();
217
	}
218
219
	/**
220
	 * Edit the relative weight of the search factors.
221
	 *
222
	 * - Called by ?action=admin;area=managesearch;sa=weights.
223
	 * - Requires the admin_forum permission.
224
	 *
225
	 * @event integrate_modify_search_weights
226
	 * @event integrate_save_search_weights
227
	 * @uses ManageSearch template, 'modify_weights' sub-template.
228
	 */
229
	public function action_weight()
230
	{
231
		global $txt, $context, $modSettings;
232
233
		$context['page_title'] = $txt['search_weights_title'];
234
		$context['sub_template'] = 'modify_weights';
235
236
		$factors = array(
237
			'search_weight_frequency',
238
			'search_weight_age',
239
			'search_weight_length',
240
			'search_weight_subject',
241
			'search_weight_first_message',
242
			'search_weight_sticky',
243
			'search_weight_likes',
244
		);
245
246
		call_integration_hook('integrate_modify_search_weights', array(&$factors));
247
248
		// A form was submitted.
249
		if (isset($this->_req->post->save))
250
		{
251
			checkSession();
252
			validateToken('admin-msw');
253
254
			call_integration_hook('integrate_save_search_weights');
255
256
			$changes = array();
257
			foreach ($factors as $factor)
258
			{
259
				$changes[$factor] = (int) $this->_req->post->{$factor};
260
			}
261
262
			updateSettings($changes);
263
		}
264
265
		$context['relative_weights'] = array('total' => 0);
266
		foreach ($factors as $factor)
267
		{
268
			$context['relative_weights']['total'] += isset($modSettings[$factor]) ? $modSettings[$factor] : 0;
269
		}
270
271
		foreach ($factors as $factor)
272
		{
273
			$context['relative_weights'][$factor] = round(100 * (isset($modSettings[$factor]) ? $modSettings[$factor] : 0) / $context['relative_weights']['total'], 1);
274
		}
275
276
		createToken('admin-msw');
277
	}
278
279
	/**
280
	 * Edit the search method and search index used.
281
	 *
282
	 * What it does:
283
	 *
284
	 * - Calculates the size of the current search indexes in use.
285
	 * - Allows to create and delete a fulltext index on the messages table.
286
	 * - Allows to delete a custom index (that action_create() created).
287
	 * - Called by ?action=admin;area=managesearch;sa=method.
288
	 * - Requires the admin_forum permission.
289
	 *
290
	 * @uses ManageSearch template, 'select_search_method' sub-template.
291
	 */
292
	public function action_edit()
293
	{
294
		global $txt, $context, $modSettings;
295
296
		// Need to work with some db search stuffs
297
		$db_search = db_search();
298
		require_once(SUBSDIR . '/ManageSearch.subs.php');
299
300
		$context[$context['admin_menu_name']]['current_subsection'] = 'method';
301
		$context['page_title'] = $txt['search_method_title'];
302
		$context['sub_template'] = 'select_search_method';
303
		$context['supports_fulltext'] = $db_search->search_support('fulltext');
304
		$context['fulltext_index'] = false;
305
306
		// Load any apis.
307
		$context['search_apis'] = $this->loadSearchAPIs();
308
309
		// Detect whether a fulltext index is set.
310
		if ($context['supports_fulltext'])
311
		{
312
			$fulltext_index = detectFulltextIndex();
313
		}
314
315
		// Creating index, removing or simply changing the one in use?
316
		if ($this->_req->getQuery('sa', 'trim', '') === 'createfulltext')
317
		{
318
			checkSession('get');
319
			validateToken('admin-msm', 'get');
320
321
			$context['fulltext_index'] = true;
322
			alterFullTextIndex('{db_prefix}messages', 'body', true);
323
		}
324
		elseif ($this->_req->getQuery('sa', 'trim', '') === 'removefulltext' && !empty($fulltext_index))
325
		{
326
			checkSession('get');
327
			validateToken('admin-msm', 'get');
328
329
			alterFullTextIndex('{db_prefix}messages', $fulltext_index);
330
331
			// Go back to the default search method.
332 View Code Duplication
			if (!empty($modSettings['search_index']) && $modSettings['search_index'] === 'fulltext')
333
			{
334
				updateSettings(array(
335
					'search_index' => '',
336
				));
337
			}
338
		}
339
		elseif ($this->_req->getQuery('sa', 'trim', '') === 'removecustom')
340
		{
341
			checkSession('get');
342
			validateToken('admin-msm', 'get');
343
344
			drop_log_search_words();
345
346
			updateSettings(array(
347
				'search_custom_index_config' => '',
348
				'search_custom_index_resume' => '',
349
			));
350
351
			// Go back to the default search method.
352 View Code Duplication
			if (!empty($modSettings['search_index']) && $modSettings['search_index'] === 'custom')
353
			{
354
				updateSettings(array(
355
					'search_index' => '',
356
				));
357
			}
358
		}
359
		elseif (isset($this->_req->post->save))
360
		{
361
			checkSession();
362
			validateToken('admin-msmpost');
363
364
			updateSettings(array(
365
				'search_index' => empty($this->_req->post->search_index) || (!in_array($this->_req->post->search_index, array('fulltext', 'custom')) && !isset($context['search_apis'][$this->_req->post->search_index])) ? '' : $this->_req->post->search_index,
366
				'search_force_index' => isset($this->_req->post->search_force_index) ? '1' : '0',
367
				'search_match_words' => isset($this->_req->post->search_match_words) ? '1' : '0',
368
			));
369
		}
370
371
		$table_info_defaults = array(
372
			'data_length' => 0,
373
			'index_length' => 0,
374
			'fulltext_length' => 0,
375
			'custom_index_length' => 0,
376
		);
377
378
		// Get some info about the messages table, to show its size and index size.
379
		if (method_exists($db_search, 'membersTableInfo'))
380
		{
381
			$context['table_info'] = array_merge($table_info_defaults, $db_search->membersTableInfo());
382
		}
383 View Code Duplication
		else
384
		{
385
			// Here may be wolves.
386
			$context['table_info'] = array(
387
				'data_length' => $txt['not_applicable'],
388
				'index_length' => $txt['not_applicable'],
389
				'fulltext_length' => $txt['not_applicable'],
390
				'custom_index_length' => $txt['not_applicable'],
391
			);
392
		}
393
394
		// Format the data and index length in human readable form.
395
		foreach ($context['table_info'] as $type => $size)
396
		{
397
			// If it's not numeric then just break.  This database engine doesn't support size.
398
			if (!is_numeric($size))
399
			{
400
				break;
401
			}
402
403
			$context['table_info'][$type] = byte_format($context['table_info'][$type]);
404
		}
405
406
		$context['custom_index'] = !empty($modSettings['search_custom_index_config']);
407
		$context['partial_custom_index'] = !empty($modSettings['search_custom_index_resume']) && empty($modSettings['search_custom_index_config']);
408
		$context['double_index'] = !empty($context['fulltext_index']) && $context['custom_index'];
409
410
		createToken('admin-msmpost');
411
		createToken('admin-msm', 'get');
412
	}
413
414
	/**
415
	 * Create a custom search index for the messages table.
416
	 *
417
	 * What it does:
418
	 *
419
	 * - Called by ?action=admin;area=managesearch;sa=createmsgindex.
420
	 * - Linked from the action_edit screen.
421
	 * - Requires the admin_forum permission.
422
	 * - Depending on the size of the message table, the process is divided in steps.
423
	 *
424
	 * @uses ManageSearch template, 'create_index', 'create_index_progress', and 'create_index_done'
425
	 * sub-templates.
426
	 */
427
	public function action_create()
428
	{
429
		global $modSettings, $context, $txt, $db_show_debug;
430
431
		// Scotty, we need more time...
432
		detectServer()->setTimeLimit(600);
433
434
		$context[$context['admin_menu_name']]['current_subsection'] = 'method';
435
		$context['page_title'] = $txt['search_index_custom'];
436
437
		$messages_per_batch = 50;
438
439
		$index_properties = array(
440
			2 => array(
441
				'column_definition' => 'small',
442
				'step_size' => 1000000,
443
			),
444
			4 => array(
445
				'column_definition' => 'medium',
446
				'step_size' => 1000000,
447
				'max_size' => 16777215,
448
			),
449
			5 => array(
450
				'column_definition' => 'large',
451
				'step_size' => 100000000,
452
				'max_size' => 2000000000,
453
			),
454
		);
455
456
		// Resume building an index that was not completed
457
		if (isset($this->_req->query->resume) && !empty($modSettings['search_custom_index_resume']))
458
		{
459
			$context['index_settings'] = Util::unserialize($modSettings['search_custom_index_resume']);
460
			$context['start'] = (int) $context['index_settings']['resume_at'];
461
			unset($context['index_settings']['resume_at']);
462
			$context['step'] = 1;
463
		}
464
		else
465
		{
466
			$context['index_settings'] = array(
467
				'bytes_per_word' => isset($this->_req->post->bytes_per_word) && isset($index_properties[$this->_req->post->bytes_per_word]) ? (int) $this->_req->post->bytes_per_word : 2,
468
			);
469
			$context['start'] = isset($this->_req->post->start) ? (int) $this->_req->post->start : 0;
470
			$context['step'] = isset($this->_req->post->step) ? (int) $this->_req->post->step : 0;
471
		}
472
473
		if ($context['step'] !== 0)
474
		{
475
			checkSession('request');
476
477
			// Admin timeouts are painful when building these long indexes
478
			$_SESSION['admin_time'] = time();
479
		}
480
481
		// Step 0: let the user determine how they like their index.
482
		if ($context['step'] === 0)
483
		{
484
			$context['sub_template'] = 'create_index';
485
		}
486
487
		require_once(SUBSDIR . '/ManageSearch.subs.php');
488
489
		// Logging may cause session issues with many queries
490
		$old_db_show_debug = $db_show_debug;
491
		$db_show_debug = false;
492
493
		// Step 1: insert all the words.
494
		if ($context['step'] === 1)
495
		{
496
			$context['sub_template'] = 'create_index_progress';
497
498
			list ($context['start'], $context['step'], $context['percentage']) = createSearchIndex($context['start'], $messages_per_batch, $index_properties[$context['index_settings']['bytes_per_word']]['column_definition'], $context['index_settings']);
499
		}
500
501
		// Step 2: removing the words that occur too often and are of no use.
502
		if ($context['step'] === 2)
503
		{
504
			if ($context['index_settings']['bytes_per_word'] < 4)
505
			{
506
				$context['step'] = 3;
507
			}
508
			else
509
			{
510
				list ($context['start'], $complete) = removeCommonWordsFromIndex($context['start'], $index_properties[$context['index_settings']['bytes_per_word']]);
511
				if ($complete)
512
				{
513
					$context['step'] = 3;
514
				}
515
516
				$context['sub_template'] = 'create_index_progress';
517
518
				$context['percentage'] = 80 + round($context['start'] / $index_properties[$context['index_settings']['bytes_per_word']]['max_size'], 3) * 20;
519
			}
520
		}
521
522
		// Restore previous debug state
523
		$db_show_debug = $old_db_show_debug;
524
525
		// Step 3: everything done.
526
		if ($context['step'] === 3)
527
		{
528
			$context['sub_template'] = 'create_index_done';
529
530
			updateSettings(array('search_index' => 'custom', 'search_custom_index_config' => serialize($context['index_settings'])));
531
			removeSettings('search_custom_index_resume');
532
		}
533
	}
534
535
	/**
536
	 * Edit settings related to the sphinx or sphinxQL search function.
537
	 *
538
	 * - Called by ?action=admin;area=managesearch;sa=sphinx.
539
	 * - Checks if connection to search daemon is possible
540
	 */
541
	public function action_managesphinx()
542
	{
543
		global $txt, $context, $modSettings;
544
545
		// Saving the settings
546
		if (isset($this->_req->post->save))
547
		{
548
			checkSession();
549
			validateToken('admin-mssphinx');
550
551
			updateSettings(array(
552
				'sphinx_index_prefix' => rtrim($this->_req->post->sphinx_index_prefix, '/'),
553
				'sphinx_data_path' => rtrim($this->_req->post->sphinx_data_path, '/'),
554
				'sphinx_log_path' => rtrim($this->_req->post->sphinx_log_path, '/'),
555
				'sphinx_stopword_path' => $this->_req->post->sphinx_stopword_path,
556
				'sphinx_indexer_mem' => (int) $this->_req->post->sphinx_indexer_mem,
557
				'sphinx_searchd_server' => $this->_req->post->sphinx_searchd_server,
558
				'sphinx_searchd_port' => (int) $this->_req->post->sphinx_searchd_port,
559
				'sphinxql_searchd_port' => (int) $this->_req->post->sphinxql_searchd_port,
560
				'sphinx_max_results' => (int) $this->_req->post->sphinx_max_results,
561
			));
562
		}
563
		// Checking if we can connect?
564
		elseif (isset($this->_req->post->checkconnect))
565
		{
566
			checkSession();
567
			validateToken('admin-mssphinx');
568
569
			// If they have not picked sphinx yet, let them know, but we can still check connections
570
			if (empty($modSettings['search_index']) || stripos($modSettings['search_index'], 'sphinx') === false)
571
			{
572
				$context['settings_message'][] = $txt['sphinx_test_not_selected'];
573
				$context['error_type'] = 'notice';
574
			}
575
576
			// Try to connect via Sphinx API?
577
			if (empty($modSettings['search_index']) || $modSettings['search_index'] === 'Sphinx')
578
			{
579
				// This is included with sphinx
580
				if (file_exists(SOURCEDIR . '/sphinxapi.php'))
581
				{
582
					include_once(SOURCEDIR . '/sphinxapi.php');
583
					$server = !empty($modSettings['sphinx_searchd_server']) ? $modSettings['sphinx_searchd_server'] : 'localhost';
584
					$port = !empty($modSettings['sphinx_searchd_port']) ? $modSettings['sphinxql_searchd_port'] : '9312';
585
586
					$mySphinx = new SphinxClient();
587
					$mySphinx->SetServer($server, (int) $port);
588
					$mySphinx->SetLimits(0, 25);
589
					$mySphinx->SetMatchMode(SPH_MATCH_BOOLEAN);
590
					$mySphinx->SetSortMode(SPH_SORT_ATTR_ASC, 'id_topic');
591
592
					$index = (!empty($modSettings['sphinx_index_prefix']) ? $modSettings['sphinx_index_prefix'] : 'elkarte') . '_index';
593
					$request = $mySphinx->Query('test', $index);
594 View Code Duplication
					if ($request === false)
595
					{
596
						$context['settings_message'][] = $txt['sphinx_test_connect_failed'];
597
						$context['error_type'] = 'serious';
598
					}
599
					else
600
					{
601
						updateSettings(array('sphinx_searchd_server' => $server, 'sphinx_searchd_port' => $port));
602
						$context['settings_message'][] = $txt['sphinx_test_passed'];
603
					}
604
				}
605
				else
606
				{
607
					$context['settings_message'][] = $txt['sphinx_test_api_missing'];
608
					$context['error_type'] = 'serious';
609
				}
610
			}
611
612
			// Try to connect via SphinxQL
613
			if (empty($modSettings['search_index']) || $modSettings['search_index'] === 'Sphinxql')
614
			{
615
				$server = !empty($modSettings['sphinx_searchd_server']) ? $modSettings['sphinx_searchd_server'] : 'localhost';
616
				$server = $server === 'localhost' ? '127.0.0.1' : $server;
617
				$port = !empty($modSettings['sphinxql_searchd_port']) ? $modSettings['sphinxql_searchd_port'] : '9306';
618
619
				$result = @mysqli_connect($server, '', '', '', (int) $port);
620 View Code Duplication
				if ($result === false)
621
				{
622
					$context['settings_message'][] = $txt['sphinxql_test_connect_failed'];
623
					$context['error_type'] = 'serious';
624
				}
625
				else
626
				{
627
					updateSettings(array('sphinx_searchd_server' => $server, 'sphinxql_searchd_port' => $port));
628
					$context['settings_message'][] = $txt['sphinxql_test_passed'];
629
				}
630
			}
631
		}
632
		elseif (isset($this->_req->post->createconfig))
633
		{
634
			checkSession();
635
			validateToken('admin-mssphinx');
636
			require_once(SUBSDIR . '/ManageSearch.subs.php');
637
638
			createSphinxConfig();
639
		}
640
641
		// Setup for the template
642
		$context[$context['admin_menu_name']]['current_subsection'] = 'managesphinx';
643
		$context['page_title'] = $txt['search_sphinx'];
644
		$context['page_description'] = $txt['sphinx_description'];
645
		$context['sub_template'] = 'manage_sphinx';
646
		createToken('admin-mssphinx');
647
	}
648
649
	/**
650
	 * Get the installed Search API implementations.
651
	 *
652
	 * - This function checks for patterns in comments on top of the Search-API files!
653
	 * - It loads the search API classes if identified.
654
	 * - This function is used by action_edit to list all installed API implementations.
655
	 */
656
	private function loadSearchAPIs()
657
	{
658
		global $txt, $scripturl;
659
660
		$apis = array();
661
		try
662
		{
663
			$files = new GlobIterator(SUBSDIR . '/Search/API/*.php', FilesystemIterator::SKIP_DOTS);
664
			foreach ($files as $file)
665
			{
666
				if ($file->isFile())
667
				{
668
					$index_name = $file->getBasename('.php');
669
					$common_name = strtolower($index_name);
670
671
					if ($common_name === 'searchapi')
672
					{
673
						continue;
674
					}
675
676
					$apis[$index_name] = array(
677
						'filename' => $file->getFilename(),
678
						'setting_index' => $index_name,
679
						'has_template' => in_array($common_name, array('custom', 'fulltext', 'standard')),
680
						'label' => $index_name && isset($txt['search_index_' . $common_name]) ? str_replace('{managesearch_url}', $scripturl . '?action=admin;area=managesearch;sa=manage' . $common_name, $txt['search_index_' . $common_name]) : '',
681
						'desc' => $index_name && isset($txt['search_index_' . $common_name . '_desc']) ? str_replace('{managesearch_url}', $scripturl . '?action=admin;area=managesearch;sa=manage' . $common_name, $txt['search_index_' . $common_name . '_desc']) : '',
682
					);
683
				}
684
			}
685
		}
686
		catch (UnexpectedValueException $e)
687
		{
688
			// @todo for now just passthrough
689
		}
690
691
		return $apis;
692
	}
693
}
694