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
|
|||||
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
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||
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
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||
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
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||
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 |
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.