PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.16
VikBooking Hotel Booking Engine & PMS v1.8.16
1.8.16 1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 All 37 releases
← All changes | libraries/adapter/mvc/controller.php +563 -0 1.6.0 → 1.8.16 View file →
@@ -1,0 +1,563 @@
1 +<?php
2 +/**
3 + * @package VikWP - Libraries
4 + * @subpackage adapter.mvc
5 + * @author E4J s.r.l.
6 + * @copyright Copyright (C) 2023 E4J s.r.l. All Rights Reserved.
7 + * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
8 + * @link https://vikwp.com
9 + */
10 +
11 +// No direct access
12 +defined('ABSPATH') or die('No script kiddies please!');
13 +
14 +JLoader::import('adapter.mvc.view');
15 +JLoader::import('adapter.mvc.model');
16 +
17 +/**
18 + * The main controller used by the MVC framework.
19 + * This controller is used to dispatch the requested actions
20 + * to the apposite views.
21 + *
22 + * @since 10.0
23 + */
24 +#[\AllowDynamicProperties]
25 +abstract class JController
26 +{
27 + /**
28 + * A list of controller instance.
29 + *
30 + * @var array
31 + */
32 + protected static $instances = array();
33 +
34 + /**
35 + * A list of excluded methods.
36 + *
37 + * @var array
38 + */
39 + protected $excludedMethods = array();
40 +
41 + /**
42 + * The controller prefix.
43 + *
44 + * @var string
45 + */
46 + protected $prefix;
47 +
48 + /**
49 + * The base path of the plugin.
50 + *
51 + * @var string
52 + */
53 + protected $basePath;
54 +
55 + /**
56 + * URL for redirection.
57 + *
58 + * @var string
59 + * @since 10.1.30
60 + */
61 + protected $redirect;
62 +
63 + /**
64 + * Redirect message.
65 + *
66 + * @var string
67 + * @since 10.1.30
68 + */
69 + protected $message;
70 +
71 + /**
72 + * Redirect message type.
73 + *
74 + * @var string
75 + * @since 10.1.30
76 + */
77 + protected $messageType;
78 +
79 + /**
80 + * Array of class methods to call for a given task.
81 + *
82 + * @var array
83 + * @since 10.1.30
84 + */
85 + protected $taskMap;
86 +
87 + /**
88 + * Class constructor.
89 + *
90 + * @param array $config An optional associative array of configuration settings.
91 + */
92 + public function __construct($config = array())
93 + {
94 + if (isset($config['prefix']))
95 + {
96 + $this->prefix = $config['prefix'];
97 + }
98 +
99 + if (isset($config['base']))
100 + {
101 + $this->basePath = $config['base'];
102 + }
103 +
104 + $reflect = new ReflectionClass('JController');
105 +
106 + foreach ($reflect->getMethods() as $method)
107 + {
108 + $this->excludedMethods[] = $method->getName();
109 + }
110 +
111 + $this->registerTask('unpublish', 'publish');
112 + }
113 +
114 + /**
115 + * Method to get a singleton controller instance.
116 + *
117 + * @param string $prefix The prefix for the controller.
118 + * @param string $base The base path from which loading the controller.
119 + *
120 + * @return self A new controller instance.
121 + */
122 + public static function getInstance($prefix, $base)
123 + {
124 + if (!isset(static::$instances[$prefix]))
125 + {
126 + $app = JFactory::getApplication();
127 + $input = $app->input;
128 +
129 + $task = $input->get('task', '');
130 + $cmd = $input->get('controller', '');
131 +
132 + if (strpos($task, '.') !== false)
133 + {
134 + $split = explode('.', $task);
135 +
136 + $cmd = array_shift($split);
137 + $task = array_pop($split);
138 + }
139 +
140 + $folder = $app->isAdmin() ? 'admin' : 'site';
141 +
142 + // load the main controller
143 + if (!JLoader::import($folder . '.controller', $base))
144 + {
145 + wp_die(
146 + '<h1>' . JText::translate('FATAL_ERROR') . '</h1>' .
147 + '<p>' . JText::translate('CONTROLLER_FILE_NOT_FOUND_ERR') . '</p>',
148 + 404
149 + );
150 + }
151 +
152 + $className = $prefix . 'Controller';
153 +
154 + // check if the controller class exists
155 + if (!class_exists($className))
156 + {
157 + wp_die(
158 + '<h1>' . JText::translate('FATAL_ERROR') . '</h1>' .
159 + '<p>' . JText::sprintf('CONTROLLER_CLASS_NOT_FOUND_ERR', $className) . '</p>',
160 + 404
161 + );
162 + }
163 +
164 + // try to check if we should load a dedicated controller
165 + if ($cmd)
166 + {
167 + /**
168 + * Search also inside the libraries folder of the current plugin.
169 + * Prioritize this folder to avoid conflicts with deprecated files.
170 + *
171 + * @since 10.1.35
172 + */
173 + if (JLoader::import('libraries.mvc.' . $folder . '.controllers.' . $cmd, $base) || JLoader::import($folder . '.controllers.' . $cmd, $base))
174 + {
175 + $childClass = $className . ucwords($cmd);
176 +
177 + if (class_exists($childClass))
178 + {
179 + $className = $childClass;
180 + }
181 + }
182 + }
183 +
184 + // setup options array
185 + $options = [
186 + 'prefix' => $prefix,
187 + 'base' => $base,
188 + ];
189 +
190 + // instantiate the controller
191 + $controller = new $className($options);
192 +
193 + // make sure the controller is a valid instance
194 + if (!$controller instanceof JController)
195 + {
196 + wp_die(
197 + '<h1>' . JText::translate('FATAL_ERROR') . '</h1>' .
198 + '<p>' . JText::translate('CONTROLLER_INVALID_INSTANCE_ERR') . '</p>',
199 + 500
200 + );
201 + }
202 +
203 + // cache the instance
204 + static::$instances[$prefix] = $controller;
205 + }
206 +
207 + return static::$instances[$prefix];
208 + }
209 +
210 + /**
211 + * Typical view method for MVC based architecture.
212 + *
213 + * This function is provided as a default implementation, in most cases
214 + * you will need to override it in your own controllers.
215 + *
216 + * @return self This object to support chaining.
217 + *
218 + * @uses getView()
219 + * @uses getModel()
220 + */
221 + public function display()
222 + {
223 + $input = JFactory::getApplication()->input;
224 +
225 + // get view name
226 + $action = $input->get('view', null);
227 + $layout = $input->get('layout', null);
228 +
229 + if ($action)
230 + {
231 + // try to obtain the view related to the specified action
232 + $view = $this->getView($action);
233 +
234 + if ($view)
235 + {
236 + // try to obtain the model related to the specified view
237 + $model = $this->getModel($action);
238 +
239 + if ($model)
240 + {
241 + // attach the model if exists
242 + $view->setModel($model);
243 + }
244 +
245 + /**
246 + * Inject the layout through the apposite setter instead of passing it
247 + * as argument to the `JView::display()` method.
248 + *
249 + * @since 10.1.41
250 + */
251 + if ($layout)
252 + {
253 + $view->setLayout($layout);
254 + }
255 +
256 + /**
257 + * Fires before the controller displays the view.
258 + *
259 + * @param JView $view The view instance.
260 + *
261 + * @since 10.1.16
262 + */
263 + do_action_ref_array(strtolower($this->prefix) . '_before_display_' . strtolower($action), array(&$view));
264 +
265 + // display the view before to terminate
266 + $view->display();
267 +
268 + /**
269 + * Fires after the controller displayed the view.
270 + *
271 + * @param JView $view The view instance.
272 + *
273 + * @since 10.1.16
274 + */
275 + do_action(strtolower($this->prefix) . '_after_display_' . strtolower($action), array($view));
276 + }
277 +
278 + }
279 +
280 + return $this;
281 + }
282 +
283 + /**
284 + * Execute a task by triggering a method in the derived class.
285 + *
286 + * @param string $task The task to perform. If no matching task is found,
287 + * the default 'display' method is executed.
288 + *
289 + * @return mixed The value returned by the called method.
290 + */
291 + public function execute($task)
292 + {
293 + $task = (string) $task;
294 +
295 + // get only the string after the dot, if any
296 + if (strpos($task, '.') !== false)
297 + {
298 + $split = explode('.', $task);
299 + $task = array_pop($split);
300 +
301 + /**
302 + * Reset the task without the controller context.
303 + *
304 + * @since 10.1.30
305 + */
306 + JFactory::getApplication()->input->set('task', $task);
307 + }
308 +
309 + // raise an error if we are trying to call reserved methods
310 + if (in_array($task, $this->excludedMethods) && $task != 'display')
311 + {
312 + wp_die(
313 + '<h1>' . JText::translate('FATAL_ERROR') . '</h1>' .
314 + '<p>' . JText::translate('CONTROLLER_PROTECTED_METHOD_ERR') . '</p>',
315 + 403
316 + );
317 + }
318 +
319 + $reflect = new ReflectionClass(get_class($this));
320 +
321 + // check if we should use a different task linked to the specified one
322 + if (isset($this->taskMap[$task]))
323 + {
324 + $task = $this->taskMap[$task];
325 + }
326 +
327 + // check if the $task method is callable
328 + if (!$reflect->hasMethod($task) || !$reflect->getMethod($task)->isPublic())
329 + {
330 + // otherwise use default 'display' method
331 + $task = 'display';
332 + }
333 +
334 + try
335 + {
336 + // dispatch callback
337 + $result = call_user_func(array($this, $task));
338 + }
339 + catch (Exception $e)
340 + {
341 + // We need to terminate the buffer here to avoid displaying
342 + // the output printed by the views into the error screen.
343 +
344 + while (ob_get_status())
345 + {
346 + // repeat until the buffer is empty
347 + ob_end_clean();
348 + }
349 +
350 + if (!wp_doing_ajax())
351 + {
352 + /**
353 + * Included exception backtrace within the document in case the DEBUG is turned on.
354 + *
355 + * @since 10.1.35
356 + */
357 + if (WP_DEBUG)
358 + {
359 + $trace = '<pre style="white-space:pre-wrap;">' . $e->getTraceAsString() . '</pre>';
360 + }
361 + else
362 + {
363 + $trace = '';
364 + }
365 +
366 + // raise an error in case an exception has been thrown
367 + wp_die(
368 + '<h1>' . JText::translate('FATAL_ERROR') . '</h1>'
369 + . '<p>' . $e->getMessage() . '</p>'
370 + . $trace,
371 + ($code = $e->getCode()) ? $code : 500
372 + );
373 + }
374 + else
375 + {
376 + /**
377 + * Raise a minified error for AJAX requests.
378 + *
379 + * @since 10.1.21
380 + */
381 + wp_die(
382 + $e->getMessage(),
383 + ($code = $e->getCode()) ? $code : 500
384 + );
385 + }
386 + }
387 +
388 + return $result;
389 + }
390 +
391 + /**
392 + * Set a URL for browser redirection.
393 + *
394 + * @param string $url URL to redirect to.
395 + * @param string $msg Message to display on redirect.
396 + * @param string $type Message type.
397 + *
398 + * @return self This object to support chaining.
399 + *
400 + * @since 10.1.30
401 + */
402 + public function setRedirect($url, $msg = null, $type = null)
403 + {
404 + // register redirection URL
405 + $this->redirect = $url;
406 +
407 + if ($msg !== null)
408 + {
409 + // controller may have set this directly
410 + $this->message = $msg;
411 + }
412 +
413 + // ensure the type is not overwritten by a previous call to setMessage
414 + if (empty($type))
415 + {
416 + if (empty($this->messageType))
417 + {
418 + $this->messageType = 'message';
419 + }
420 + }
421 + // if the type is explicitly set, set it
422 + else
423 + {
424 + $this->messageType = $type;
425 + }
426 +
427 + return $this;
428 + }
429 +
430 + /**
431 + * Redirects the browser or returns false if no redirect is set.
432 + *
433 + * @return boolean False if no redirect exists.
434 + *
435 + * @since 10.1.30
436 + */
437 + public function redirect()
438 + {
439 + if ($this->redirect)
440 + {
441 + $app = JFactory::getApplication();
442 +
443 + if ($this->message)
444 + {
445 + // enqueue the redirect message
446 + $app->enqueueMessage($this->message, $this->messageType);
447 + }
448 +
449 + // execute the redirect
450 + $app->redirect($this->redirect);
451 + }
452 +
453 + return false;
454 + }
455 +
456 + /**
457 + * Register (map) a task to a method in the class.
458 + *
459 + * @param string $task The task.
460 + * @param string $method The name of the method in the derived class to perform for this task.
461 + *
462 + * @return self This object to support chaining.
463 + *
464 + * @since 10.1.30
465 + */
466 + public function registerTask($task, $method)
467 + {
468 + $this->taskMap[strtolower($task)] = $method;
469 +
470 + return $this;
471 + }
472 +
473 + /**
474 + * Returns the view object related to the specified name.
475 + *
476 + * @param string $view The view name.
477 + *
478 + * @return mixed The view object if exists, otherwise false.
479 + */
480 + protected function getView($view)
481 + {
482 + $app = JFactory::getApplication();
483 +
484 + $folder = $app->isAdmin() ? 'admin' : 'site';
485 +
486 + $paths = [];
487 +
488 + /**
489 + * Search also inside the libraries folder of the current plugin.
490 + * Prioritize this folder to avoid conflicts with deprecated views.
491 + *
492 + * @since 10.1.35
493 + */
494 + $paths[] = $this->basePath . '/libraries/mvc/' . $folder . '/views';
495 +
496 + // get default view path
497 + $paths[] = $this->basePath . '/' . $folder . '/views';
498 +
499 + // find the matching path
500 + $path = JPath::find($paths, $view);
501 +
502 + if (!$path)
503 + {
504 + return false;
505 + }
506 +
507 + // view found, make sure the entry point exists
508 + $path = JPath::clean($path . '/view.html.php');
509 +
510 + // make sure the file path exists
511 + if (!is_file($path))
512 + {
513 + return false;
514 + }
515 +
516 + // include the view file
517 + require_once $path;
518 +
519 + $className = $this->prefix . 'View' . ucwords($view);
520 +
521 + // make sure the view class exists
522 + if (!class_exists($className))
523 + {
524 + return false;
525 + }
526 +
527 + $obj = new $className(dirname($path));
528 +
529 + // make sure the view is a valid instance
530 + if (!$obj instanceof JView)
531 + {
532 + return false;
533 + }
534 +
535 + return $obj;
536 + }
537 +
538 + /**
539 + * Method to get a model object.
540 + *
541 + * @param string $name The model name.
542 + * @param string $prefix The class prefix.
543 + * @param array $config Configuration array for model.
544 + *
545 + * @return mixed Model object on success; otherwise false on failure.
546 + */
547 + public function getModel($name = '', $prefix = '', $config = array())
548 + {
549 + if (!$name)
550 + {
551 + // obtain the model name from the classname of this controller
552 + $name = strtolower(str_replace($this->prefix . 'Controller', '', get_class($this)));
553 + }
554 +
555 + if (!$prefix)
556 + {
557 + $prefix = $this->prefix;
558 + }
559 +
560 + // invoke parent
561 + return JModel::getInstance($name, $prefix, $config);
562 + }
563 +}