Issues (1686)

sources/ElkArte/AbstractController.php (4 issues)

Severity
1
<?php
2
3
/**
4
 * Abstract base class for controllers. Holds action_index and pre_dispatch
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;
15
16
use ElkArte\Helper\HttpReq;
17
use ElkArte\Helper\ValuesContainer;
18
19
/**
20
 * AbstractController class
21
 *
22
 * This class serves as a base class for all controllers in the application.
23
 * It provides common functionality and methods that can be used by its subclasses.
24
 *
25
 *  - Requires a default action handler, action_index().
26
 *  - Provides a constructor that loads in HttpReq.  Controllers should use a pre_dispatch class which is called
27
 *    by the dispatcher before any other action method.
28
 */
29
abstract class AbstractController
30
{
31
	/** @var object The event manager. */
32
	protected $_events;
33
34
	/** @var string The current hook. */
35
	protected $_hook = '';
36
37
	/** @var HttpReq Holds instance of \ElkArte\Helper\HttpReq object */
38
	protected $_req;
39
40
	/** @var ValuesContainer Holds instance of \ElkArte\User::$info object */
41
	protected $user;
42
43
	/**
44
	 * Constructor for the class.
45
	 *
46
	 * @param EventManager $eventManager The event manager object.
47
	 */
48
	public function __construct($eventManager)
49
	{
50
		// Dependency injection will come later
51
		$this->_req = HttpReq::instance();
52
53
		$this->_events = $eventManager;
54
	}
55 101
56
	/**
57
	 * Default action handler.
58 101
	 *
59
	 * What it does:
60 101
	 *
61 101
	 * - This will be called by the dispatcher in many cases.
62
	 * - It may set up a menu, sub-dispatch at its turn to the method matching ?sa= parameter
63
	 * or simply forward the request to a known default method.
64
	 */
65
	abstract public function action_index();
66
67
	/**
68
	 * Called before any other action method in this class.
69
	 *
70
	 * What it does:
71
	 *
72
	 * - Allows for initializations, such as default values or loading templates or language files.
73
	 */
74
	public function pre_dispatch()
75
	{
76
		// By default, do nothing.
77
		// Sub-classes may implement their prerequisite loading,
78
		// such as load the template, load the language(s) file(s)
79
	}
80
81
	/**
82
	 * Standard method to add an "home" button when using a custom action as forum index.
83
	 *
84
	 * @param array $buttons
85
	 */
86
	public static function addForumButton(&$buttons)
87
	{
88
		global $scripturl, $txt, $modSettings;
89
90
		$buttons = array_merge([
91
			'base' => [
92
				'title' => $txt['home'],
93
				'href' => $scripturl,
94
				'data-icon' => 'i-home',
95
				'show' => true,
96
				'action_hook' => true,
97
			]], $buttons);
98
99
		$buttons['home']['href'] = getUrl('action', $modSettings['default_forum_action']);
100
		$buttons['home']['data-icon'] = 'i-comment-blank';
101
	}
102
103
	/**
104
	 * Standard method to tweak the current action when using a custom action as forum index.
105
	 *
106
	 * @param string $current_action
107
	 */
108
	public static function fixCurrentAction(&$current_action)
109
	{
110
		if ($current_action === 'home')
111
		{
112
			$current_action = 'base';
113
		}
114
115
		if (empty($_REQUEST['action']))
116
		{
117
			return;
118
		}
119
120
		if ($_REQUEST['action'] !== 'forum')
121
		{
122
			return;
123
		}
124
125
		$current_action = 'home';
126
	}
127
128
	/**
129
	 * Tells if the controller can be displayed as front page.
130
	 *
131
	 * @return bool
132
	 */
133
	public static function canFrontPage()
134
	{
135 78
		return in_array(FrontpageInterface::class, class_implements(static::class), true);
136
	}
137 78
138 78
	/**
139
	 * Used to define the parameters the controller may need for the front page
140
	 * action to work
141
	 *
142
	 * - e.g. specify a topic ID or a board listing
143
	 */
144
	public static function frontPageOptions()
145
	{
146
		return [];
147
	}
148
149
	/**
150
	 * Used to validate any parameters the controller may need for the front page
151
	 * action to work
152
	 *
153
	 * - e.g. specify a topic ID
154
	 * - should return true or false based on if its able to show the front page
155
	 */
156
	public static function validateFrontPageOptions($post)
0 ignored issues
show
The parameter $post is not used and could be removed. ( Ignorable by Annotation )

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

156
	public static function validateFrontPageOptions(/** @scrutinizer ignore-unused */ $post)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
157
	{
158
		return true;
159
	}
160
161
	/**
162
	 * Tells if the controller requires the security framework to be loaded. This is called
163
	 * immediately after the controller is initialized.
164
	 *
165
	 * @param string $action the function name of the current action
166
	 *
167
	 * @return bool
168
	 */
169
	public function needSecurity($action = '')
0 ignored issues
show
The parameter $action is not used and could be removed. ( Ignorable by Annotation )

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

169
	public function needSecurity(/** @scrutinizer ignore-unused */ $action = '')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
170
	{
171
		return true;
172
	}
173
174
	/**
175
	 * Tells if the controller needs the theme loaded up.
176
	 *
177
	 * @param string $action the function name of the current action
178
	 *
179
	 * @return bool
180
	 */
181
	public function needTheme($action = '')
0 ignored issues
show
The parameter $action is not used and could be removed. ( Ignorable by Annotation )

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

181
	public function needTheme(/** @scrutinizer ignore-unused */ $action = '')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
182
	{
183
		return true;
184
	}
185
186
	/**
187
	 * Tells if the controller wants to be tracked.
188
	 *
189
	 * @param string $action the function name of the current action
190
	 *
191
	 * @return bool
192
	 */
193
	public function trackStats($action = '')
0 ignored issues
show
The parameter $action is not used and could be removed. ( Ignorable by Annotation )

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

193
	public function trackStats(/** @scrutinizer ignore-unused */ $action = '')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
194
	{
195
		return empty($this->_req->getRequest('api', 'trim', false));
196
	}
197
198
	/**
199
	 * Public function to return the controllers generic hook name
200
	 */
201
	public function getHook()
202
	{
203
		if ($this->_hook === '')
204
		{
205
			// Use the base controller name for the hook, ie post
206
			$this->_hook = $this->getModuleClass();
207
208
			// Initialize the events associated with this controller
209
			$this->_initEventManager();
210
		}
211
212
		return strtolower($this->_hook);
213
	}
214
215
	/**
216
	 * Public function to return the modules hook class name
217
	 */
218
	public function getModuleClass()
219
	{
220
		// Use the base controller name for the hook, ie post
221
		$module_class = explode('\\', trim(static::class, '\\'));
222
		$module_class = end($module_class);
223
224
		return ucfirst($module_class);
225
	}
226
227
	/**
228
	 * Initialize the event manager for the controller
229
	 *
230
	 * Uses the \ElkArte\Controller\XXX name to define the set of event hooks to load
231
	 */
232
	protected function _initEventManager()
233
	{
234
		// Find any module classes associated with this controller
235
		$classes = $this->_loadModules();
236
237
		// Register any module classes => events we found
238
		$this->_events->registerClasses($classes);
239
240
		$this->_events->setSource($this);
241
	}
242
243
	/**
244
	 * Finds modules registered to a certain controller
245
	 *
246
	 * What it does:
247
	 *
248
	 * - Uses the controllers generic hook name to find modules
249
	 * - Searches for modules registered against the module name
250
	 * - Example
251
	 *   - \ElkArte\Controller\Display results in searching for modules registered against modules_display
252
	 *   - $modSettings['modules_display'] returns drafts,calendar,.....
253
	 *   - Verifies classes Drafts_Display_Module, Calendar_Display_Module, ... exist
254
	 *
255
	 * @return string[] Valid Module Classes for this Controller
256
	 */
257
	protected function _loadModules()
258
	{
259
		global $modSettings;
260
261
		$classes = [];
262
		$setting_key = 'modules_' . $this->getHook();
263
		$namespace = '\\ElkArte\\Modules\\';
264
265
		// For all the modules that have been registered see if we have a class to load for this hook area
266
		if (!empty($modSettings[$setting_key]))
267
		{
268
			$modules = explode(',', $modSettings[$setting_key]);
269
270
			foreach ($modules as $module)
271
			{
272
				// drafts => Drafts, some_name => SomeName
273
				$module_name = array_map('ucfirst', explode('_', $module));
274
				$class = $namespace . implode('', $module_name) . '\\' . $this->getModuleClass();
275
276
				if (class_exists($class))
277
				{
278
					$classes[] = $class;
279
				}
280
			}
281
		}
282
283 18
		return $classes;
284
	}
285
286
	/**
287
	 * An odd function that allows events to request dependencies from properties
288 18
	 * of the class.  Used by the EventManager to allow registered events to access
289
	 * values of the class that triggered the event.
290
	 *
291
	 * If the property does not exist in the class, will also look in globals.
292
	 *
293
	 * @param string $dep - The name of the property the even wants
294
	 * @param array $dependencies - the array that will be filled with the references to the dependencies
295
	 */
296
	public function provideDependencies($dep, &$dependencies)
297
	{
298
		if (property_exists($this, $dep))
299
		{
300
			$dependencies[$dep] = &$this->{$dep};
301
		}
302
		elseif (property_exists($this, '_' . $dep))
303
		{
304
			$dependencies[$dep] = &$this->{'_' . $dep};
305
		}
306
		elseif (array_key_exists($dep, $GLOBALS))
307
		{
308
			$dependencies[$dep] = &$GLOBALS[$dep];
309
		}
310
	}
311
312
	/**
313
	 * Returns the user object.
314
	 *
315
	 * @return ValuesContainer the user object.
316
	 */
317
	public function getUser(): ValuesContainer
318
	{
319
		return $this->user;
320
	}
321
322
	/**
323
	 * Sets the $this->user property to the current user
324
	 *
325
	 * @param ValuesContainer $user
326
	 */
327
	public function setUser($user)
328
	{
329
		$this->user = $user;
330
	}
331
332
	/**
333
	 * Helper function to see if the request is asking for any api processing
334
	 *
335
	 * @return string|false
336
	 */
337
	public function getApi()
338
	{
339
		global $db_show_debug;
340
341
		// API Call?
342
		$api = $this->_req->getRequest('api', 'trim', '');
343
		$api = in_array($api, ['xml', 'json', 'html']) && !empty($_SERVER['HTTP_X_REQUESTED_WITH']) ? $api : false;
344
345
		// Lazy developers, nuff said :P
346
		if ($api !== false)
347
		{
348
			$db_show_debug = false;
349
		}
350
351
		return $api;
352
	}
353
354
	/**
355
	 * Shortcut to register an array of names as events triggered at a certain position in the code.
356
	 *
357
	 * @param string $name - Name of the trigger where the events will be executed.
358
	 * @param string $method - The method that will be executed.
359
	 * @param string[] $to_register - An array of classes to register.
360
	 */
361
	protected function _registerEvent($name, $method, $to_register)
362
	{
363
		foreach ($to_register as $class)
364
		{
365
			$this->_events->register($name, array($name, array($class, $method, 0)));
366
		}
367
	}
368
}
369