PluginProbe
VikBooking Hotel Booking Engine & PMS / trunk
VikBooking Hotel Booking Engine & PMS vtrunk
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 1.7.3 All 36 releases
vikbooking / libraries / adapter / layout / file.php

file.php in VikBooking Hotel Booking Engine & PMS trunk, at libraries/adapter/layout/file.php

572 lines 12.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikWP - Libraries
4 * @subpackage adapter.layout
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.layout.base');
15 JLoader::import('adapter.filesystem.path');
16
17 /**
18 * Base class for rendering a display layout loaded from from a layout file.
19 *
20 * It is possible to create theme overrides for the layouts by adding the specific
21 * file into a path built as follows:
22 * /wp-content/uploads/[PLUGIN_NAME]/layouts/[CLIENT]/[LAYOUT_PATH].php
23 *
24 * For example, in case we need to override the site 'html.user.login' layout
25 * that belong to the 'vik' plugin, the path will look like:
26 * /wp-content/uploads/vik/layouts/site/html/user/login.php
27 *
28 * The client can assume only 2 values: site or admin.
29 *
30 * @since 10.0
31 */
32 class JLayoutFile extends JLayoutBase
33 {
34 /**
35 * A list containing the cached layout paths.
36 *
37 * @var array
38 */
39 protected static $cache = array();
40
41 /**
42 * The identifier of the layout file to render.
43 *
44 * @var string
45 */
46 protected $layoutId = '';
47
48 /**
49 * The base path of the files to include.
50 *
51 * @var string
52 */
53 protected $basePath = null;
54
55 /**
56 * Full path to actual layout files, after possible template override check.
57 *
58 * @var string
59 * @since 10.1.18
60 */
61 protected $fullPath = null;
62
63 /**
64 * Paths to search for layouts.
65 *
66 * @var array
67 * @since 10.1.18
68 */
69 protected $includePaths = array();
70
71 /**
72 * Method to instantiate the file-based layout.
73 *
74 * @param string $layoutId Dot separated path to the layout file, relative to base path.
75 * @param string $basePath Base path to use when loading layout files.
76 * @param mixed $options Optional custom options to load. Registry or array format.
77 */
78 public function __construct($layoutId, $basePath = null, $options = null)
79 {
80 // initialise / load options
81 $this->setOptions($options);
82
83 // main properties
84 $this->setLayoutId($layoutId);
85 $this->basePath = $basePath;
86
87 // init enviroment
88 $this->setComponent($this->options->get('component', 'auto'));
89 $this->setClient($this->options->get('client', 'auto'));
90 }
91
92 /**
93 * Method to render the layout.
94 *
95 * @param array $displayData Array of properties available for use inside
96 * the layout file to build the displayed output.
97 *
98 * @return string The necessary HTML to display the layout.
99 *
100 * @uses clearDebugMessages()
101 * @uses getPath()
102 * @uses isDebugEnabled()
103 * @uses renderDebugMessages()
104 */
105 public function render($displayData = array())
106 {
107 $this->clearDebugMessages();
108
109 // inherit base output from parent class
110 $layoutOutput = '';
111
112 // automatically merge any previously data set if $displayData is an array
113 if (is_array($displayData))
114 {
115 $displayData = array_merge($this->data, $displayData);
116 }
117
118 // check possible overrides, and build the full path to layout file
119 $path = $this->getPath();
120
121 if ($this->isDebugEnabled())
122 {
123 echo '<pre>' . $this->renderDebugMessages() . '</pre>';
124 }
125
126 // nothing to show
127 if (empty($path))
128 {
129 return $layoutOutput;
130 }
131
132 // start buffer
133 ob_start();
134 // include the file
135 include $path;
136 // push the buffer data in a variable
137 $layoutOutput = ob_get_contents();
138 // end buffer end clean
139 ob_end_clean();
140
141 return $layoutOutput;
142 }
143
144 /**
145 * Method to find the full real file path, checking possible overrides.
146 *
147 * @return string The full path to the layout file.
148 *
149 * @uses getLayoutId()
150 * @uses getIncludePaths()
151 * @uses addDebugMessage()
152 */
153 protected function getPath()
154 {
155 $layoutId = $this->getLayoutId();
156 $includePaths = $this->getIncludePaths();
157
158 $this->addDebugMessage('<strong>Layout:</strong> ' . $this->layoutId);
159
160 // make sure we have something to render
161 if (!$layoutId)
162 {
163 $this->addDebugMessage('<strong>There is no active layout</strong>');
164
165 return;
166 }
167
168 // make sure some paths have been specified
169 if (!$includePaths)
170 {
171 $this->addDebugMessage('<strong>There are no folders to search for layouts:</strong> ' . $layoutId);
172
173 return;
174 }
175
176 // create signature key
177 $hash = md5(json_encode($includePaths));
178
179 // check if the same layout has been already cached
180 if (!empty(static::$cache[$layoutId][$hash]))
181 {
182 $this->addDebugMessage('<strong>Cached path:</strong> ' . static::$cache[$layoutId][$hash]);
183
184 return static::$cache[$layoutId][$hash];
185 }
186
187 $this->addDebugMessage('<strong>Include Paths:</strong> ' . print_r($includePaths, true));
188
189 // standard version
190 $rawPath = str_replace('.', '/', $this->layoutId) . '.php';
191 $this->addDebugMessage('<strong>Searching layout for:</strong> ' . $rawPath);
192
193 // search for a layout file
194 $foundLayout = JPath::find($this->includePaths, $rawPath);
195
196 if (!$foundLayout)
197 {
198 // impossible to find any layouts
199 $this->addDebugMessage('<strong>Unable to find layout: </strong> ' . $layoutId);
200
201 return;
202 }
203
204 $this->addDebugMessage('<strong>Found layout:</strong> ' . $foundLayout);
205
206 // cache the layout found for later uses
207 static::$cache[$layoutId][$hash] = $foundLayout;
208
209 return static::$cache[$layoutId][$hash];
210 }
211
212 /**
213 * Adds one path to include in layout search.
214 * Proxy of addIncludePaths().
215 *
216 * @param string $path The path to search for layouts.
217 *
218 * @return self This object to support chaining.
219 *
220 * @since 10.1.18
221 *
222 * @uses addIncludePaths()
223 */
224 public function addIncludePath($path)
225 {
226 $this->addIncludePaths($path);
227
228 return $this;
229 }
230
231 /**
232 * Adds one or more paths to include in layout search.
233 *
234 * @param mixed $paths The path or array of paths to search for layouts.
235 *
236 * @return self This object to support chaining.
237 *
238 * @since 10.1.18
239 *
240 * @uses getIncludePaths()
241 * @uses setIncludePaths()
242 */
243 public function addIncludePaths($paths)
244 {
245 if (empty($paths))
246 {
247 return $this;
248 }
249
250 $includePaths = $this->getIncludePaths();
251
252 // in case the path is an array, merge all the paths and make sure we have no duplicated
253 if (is_array($paths))
254 {
255 $includePaths = array_unique(array_merge($paths, $includePaths));
256 }
257 // otherwise add the path as first element
258 else
259 {
260 array_unshift($includePaths, $paths);
261 }
262
263 // update include paths
264 $this->setIncludePaths($includePaths);
265
266 return $this;
267 }
268
269 /**
270 * Clears the include paths.
271 *
272 * @return self This object to support chaining.
273 *
274 * @since 10.1.18
275 */
276 public function clearIncludePaths()
277 {
278 $this->includePaths = array();
279
280 return $this;
281 }
282
283 /**
284 * Gets the active include paths.
285 *
286 * @return array
287 *
288 * @since 10.1.18
289 *
290 * @uses getDefaultIncludePaths()
291 */
292 public function getIncludePaths()
293 {
294 if (empty($this->includePaths))
295 {
296 $this->includePaths = $this->getDefaultIncludePaths();
297 }
298
299 return $this->includePaths;
300 }
301
302 /**
303 * Gets the active layout id.
304 *
305 * @return string
306 *
307 * @since 10.1.18
308 */
309 public function getLayoutId()
310 {
311 return $this->layoutId;
312 }
313
314 /**
315 * Removes one path from the layout search.
316 * Proxy of removeIncludePaths().
317 *
318 * @param string $path The path to remove from the layout search.
319 *
320 * @return self This object to support chaining.
321 *
322 * @since 10.1.18
323 *
324 * @uses removeIncludePaths()
325 */
326 public function removeIncludePath($path)
327 {
328 $this->removeIncludePaths($path);
329
330 return $this;
331 }
332
333 /**
334 * Removes one or more paths to exclude in layout search.
335 *
336 * @param mixed $paths The path or array of paths to remove for the layout search.
337 *
338 * @return self This object to support chaining.
339 *
340 * @since 10.1.18
341 */
342 public function removeIncludePaths($paths)
343 {
344 if (!empty($paths))
345 {
346 // always use an array of paths
347 $paths = (array) $paths;
348
349 // obtain a list of paths by excluding the specified ones
350 $this->includePaths = array_diff($this->includePaths, $paths);
351 }
352
353 return $this;
354 }
355
356 /**
357 * Validates that the active component is valid.
358 *
359 * @param string $option URL Option of the component (e.g. com_xxx).
360 *
361 * @return boolean True if valid, false otherwise.
362 *
363 * @since 10.1.18
364 */
365 protected function validComponent($option = null)
366 {
367 // by default we will validate the active component
368 $component = ($option !== null) ? $option : $this->options->get('component', null);
369
370 // validate option format
371 return !empty($component) && preg_match("/^com_/", $component);
372 }
373
374 /**
375 * Method to change the component where search for layouts.
376 *
377 * @param string $option URL Option of the component (e.g. com_xxx).
378 *
379 * @return void
380 *
381 * @since 10.1.18
382 *
383 * @uses validComponent()
384 * @uses clearIncludePaths()
385 */
386 public function setComponent($option)
387 {
388 $component = null;
389
390 switch ((string) $option)
391 {
392 case 'none':
393 $component = null;
394 break;
395
396 case 'auto':
397 // recover component name from request
398 $component = JFactory::getApplication()->input->get('option', null);
399 break;
400
401 default:
402 $component = $option;
403 break;
404 }
405
406 // extra checks
407 if (!$this->validComponent($component))
408 {
409 $component = null;
410 }
411 else
412 {
413 $component = preg_replace("/^com_/", '', $component);
414 }
415
416 // update component option
417 $this->options->set('component', $component);
418
419 // refresh include paths
420 $this->clearIncludePaths();
421 }
422
423 /**
424 * Function to initialise the application client.
425 *
426 * @param mixed $client The application client:
427 * - 0 or 'site': front-end;
428 * - 1 or 'admin': back-end.
429 *
430 * @return void
431 *
432 * @since 10.1.18
433 *
434 * @uses clearIncludePaths()
435 */
436 public function setClient($client)
437 {
438 // force string conversion to avoid unexpected states
439 switch ((string) $client)
440 {
441 case 'site':
442 case '0':
443 $client = 0;
444 break;
445
446 case 'admin':
447 case '1':
448 $client = 1;
449 break;
450
451 default:
452 $client = (int) JFactory::getApplication()->isAdmin();
453 break;
454 }
455
456 // update client option
457 $this->options->set('client', $client);
458
459 // refresh include paths
460 $this->clearIncludePaths();
461 }
462
463 /**
464 * Sets the active layout id.
465 *
466 * @param string $layoutId Layout identifier.
467 *
468 * @return self This object to support chaining.
469 *
470 * @since 10.1.18
471 */
472 public function setLayoutId($layoutId)
473 {
474 $this->layoutId = $layoutId;
475 $this->fullPath = null;
476
477 return $this;
478 }
479
480 /**
481 * Gets the default array of include paths.
482 *
483 * @return array
484 *
485 * @since 10.1.18
486 */
487 public function getDefaultIncludePaths()
488 {
489 $paths = array();
490
491 // (1 - highest priority) Received a custom high priority path
492 if ($this->basePath !== null)
493 {
494 $paths[] = rtrim($this->basePath, DIRECTORY_SEPARATOR);
495 }
496
497 // component layouts & overrides if exist
498 $component = $this->options->get('component', null);
499
500 if (!empty($component))
501 {
502 // get upload dir
503 $uploads = wp_upload_dir();
504
505 if ($this->options->get('client') == 0)
506 {
507 // (2) build component override site layouts path
508 $paths[] = rtrim($uploads['basedir'], DIRECTORY_SEPARATOR) . '/' . $component . '/layouts/site';
509
510 // (3) build component site layouts path
511 $paths[] = WP_PLUGIN_DIR . '/' . $component . '/site/layouts';
512 }
513 else
514 {
515 // (2) build component override admin layouts path
516 $paths[] = rtrim($uploads['basedir'], DIRECTORY_SEPARATOR) . '/' . $component . '/layouts/admin';
517
518 // (3) build component admin layouts path
519 $paths[] = WP_PLUGIN_DIR . '/' . $component . '/admin/layouts';
520 }
521
522 // (4) build libraries layouts path
523 $paths[] = WP_PLUGIN_DIR . '/' . $component . '/libraries';
524 }
525
526 return $paths;
527 }
528
529 /**
530 * Sets the include paths to search for layouts.
531 *
532 * @param array $paths Array with paths to search in.
533 *
534 * @return self This object to support chaining.
535 *
536 * @since 10.1.18
537 */
538 public function setIncludePaths($paths)
539 {
540 $this->includePaths = (array) $paths;
541
542 return $this;
543 }
544
545 /**
546 * Render a layout with the same include paths & options.
547 *
548 * @param string $layoutId The identifier for the sublayout to be searched in a
549 * subfolder with the name of the current layout.
550 * @param mixed $displayData Data to be rendered.
551 *
552 * @return string The necessary HTML to display the layout.
553 *
554 * @since 10.1.18
555 */
556 public function sublayout($layoutId, $displayData = array())
557 {
558 // sublayouts are searched in a subfolder with the name of the current layout
559 if (!empty($this->layoutId))
560 {
561 $layoutId = $this->layoutId . '.' . $layoutId;
562 }
563
564 // instantiate new layout file
565 $sublayout = new static($layoutId, $this->basePath, $this->options);
566 $sublayout->includePaths = $this->includePaths;
567
568 // render sublayout
569 return $sublayout->render($displayData);
570 }
571 }
572