PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.6.6
VikBooking Hotel Booking Engine & PMS v1.6.6
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
vikbooking / libraries / mvc / admin / models / overrides.php

overrides.php in VikBooking Hotel Booking Engine & PMS 1.6.6, at libraries/mvc/admin/models/overrides.php

593 lines 14.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikBooking
4 * @subpackage core
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 to this file
12 defined('ABSPATH') or die('No script kiddies please!');
13
14 JLoader::import('adapter.mvc.models.form');
15
16 /**
17 * VikBooking plugin Overrides model.
18 * @wponly
19 *
20 * @since 1.6.5
21 * @see JModel
22 */
23 class VikBookingModelOverrides extends JModel
24 {
25 /**
26 * A list containing all the back-end views to exclude.
27 *
28 * @var array
29 */
30 public $_excludedAdminViews = ['getpro', 'gotopro', 'overrides'];
31
32 /**
33 * A list containing all the front-end views to exclude.
34 *
35 * @var array
36 */
37 public $_excludedSiteViews = [];
38
39 /**
40 * A list containing all the widgets to exclude.
41 *
42 * @var array
43 */
44 public $_excludedModules = [];
45
46 /**
47 * A list containing all the layouts to exclude.
48 *
49 * @var array
50 */
51 public $_excludedLayouts = [];
52
53 /**
54 * Checks whether the specified file supports overrides.
55 *
56 * @param mixed $tree Either the tree array or the client string.
57 * @param string $file The file to look for.
58 *
59 * @return mixed The node found on success, false otherwise.
60 */
61 public function isSupported($tree, string $file)
62 {
63 if (!is_array($tree))
64 {
65 // client given, generate tree
66 $tree = $this->getTree($tree);
67 }
68
69 // look for a leaf
70 if (isset($tree['folder']) && !$tree['folder'])
71 {
72 // leaf found, look for a match with the file path
73 if ($file == $tree['path'] || $file == $tree['override'])
74 {
75 // match found, override supported
76 return $tree;
77 }
78 else
79 {
80 // match not found, go ahead
81 return false;
82 }
83 }
84
85 // scan files if we are inside a node
86 if (isset($tree['files']))
87 {
88 $tree = $tree['files'];
89 }
90
91 // iterate nodes
92 foreach ($tree as $node)
93 {
94 // recursively check whether the node contains
95 // a file matching the specified path
96 if ($leaf = $this->isSupported($node, $file))
97 {
98 // leaf found, override supported
99 return $leaf;
100 }
101 }
102
103 // file not supported
104 return false;
105 }
106
107 /**
108 * Creates the tree containing the available overrides for the specified client.
109 *
110 * @param string $client The client to look for. Supports the following options:
111 * - administrator back-end views;
112 * - site front-end views;
113 * - layouts admin, site and core layouts;
114 * - modules plugin widgets.
115 *
116 * @return array The resulting tree.
117 */
118 public function getTree(string $client)
119 {
120 // look for administrator/site views
121 if (preg_match("/^(admin(?:istrator)?|site)$/i", $client))
122 {
123 // scan views overrides
124 $tree = $this->getViewsTree($client);
125 }
126 else if (preg_match("/^layouts?$/i", $client))
127 {
128 // scan layouts overrides
129 $tree = $this->getLayoutsTree();
130 }
131 else if (preg_match("/^(modules?|widgets?)$/i", $client))
132 {
133 // scan modules overrides
134 $tree = $this->getModulesTree();
135 }
136 else
137 {
138 // client not supported, throw exception
139 throw new Exception(sprintf('Override [%s] client not supported', $client), 500);
140 }
141
142 return $tree;
143 }
144
145 /**
146 * Creates the tree containing the available overrides for the admin/site views.
147 *
148 * @param string $client The client to look for.
149 *
150 * @return array The resulting tree.
151 */
152 protected function getViewsTree(string $client)
153 {
154 $tree = [];
155
156 // build path according to the specified client
157 if (preg_match("/^admin(?:istrator)?$/i", $client))
158 {
159 // admin path
160 $path = VBO_ADMIN_PATH . DIRECTORY_SEPARATOR . 'views';
161
162 // get list of excluded views
163 $excluded = $this->_excludedAdminViews;
164
165 // define client folder
166 $clientFolder = 'admin';
167 }
168 else
169 {
170 // site path
171 $path = VBO_SITE_PATH . DIRECTORY_SEPARATOR . 'views';
172
173 // get list of excluded views
174 $excluded = $this->_excludedSiteViews;
175
176 // define client folder
177 $clientFolder = 'site';
178 }
179
180 // retrieve temporary uploads path
181 $upload = wp_upload_dir();
182
183 // create base path of overrides
184 $overridesPath = JPath::clean($upload['basedir'] . '/vikbooking/overrides/' . $clientFolder . '/');
185
186 // get all folders at the specified path
187 $views = JFolder::folders($path, '.', $recursive = false, $fullPath = true);
188
189 // check whether the plugin supports specific views only for the WordPress platform
190 if (JFolder::exists(VIKBOOKING_LIBRARIES . '/mvc/' . $clientFolder . '/views'))
191 {
192 $views = array_merge($views, JFolder::folders(VIKBOOKING_LIBRARIES . '/mvc/' . $clientFolder . '/views', '.', $recursive = false, $fullPath = true));
193 }
194
195 // iterate views and extract all the supported templates
196 foreach ($views as $view)
197 {
198 $viewName = basename($view);
199
200 // make sure the view should not be excluded
201 if (!$this->isExcluded($viewName, $excluded))
202 {
203 // create node to inject within the tree
204 $node = [
205 'name' => $viewName,
206 'path' => $view,
207 'folder' => true,
208 'files' => [],
209 ];
210
211 // build path containing the view templates
212 $tmpl = JPath::clean($view . '/tmpl');
213
214 // scan files within the view
215 $files = JFolder::files($tmpl, '\.php$', $recursive = false, $fullPath = true);
216
217 // iterate files
218 foreach ($files as $file)
219 {
220 $filename = basename($file);
221
222 // create override path
223 $fileOverridePath = $overridesPath . $viewName . DIRECTORY_SEPARATOR . $filename;
224
225 $published = false;
226
227 // look for an existing override
228 if (JFile::exists($fileOverridePath))
229 {
230 // the file owns an override
231 $override = $published = true;
232 }
233 else
234 {
235 // look for an unpublished override
236 $unpublishedPath = $overridesPath . $viewName . DIRECTORY_SEPARATOR . '__' . $filename;
237
238 // check whether the file exists
239 if (JFile::exists($unpublishedPath))
240 {
241 // the file owns an unpublished override
242 $override = true;
243 }
244 else
245 {
246 // missing override
247 $override = false;
248 }
249 }
250
251 // register node within the parent
252 $node['files'][] = [
253 'name' => $filename,
254 'path' => $file,
255 'override' => $fileOverridePath,
256 'folder' => false,
257 'has' => $override,
258 'published' => $published,
259 ];
260 }
261
262 // append node to the tree
263 $tree[] = $node;
264 }
265 }
266
267 // sort folders by ascending name
268 usort($tree, function($a, $b)
269 {
270 return strcasecmp($a['name'], $b['name']);
271 });
272
273 return $tree;
274 }
275
276 /**
277 * Creates the tree containing the available overrides for the layouts.
278 * The first level will always contain these nodes: admin, site, core.
279 *
280 * @return array The resulting tree.
281 */
282 protected function getLayoutsTree()
283 {
284 $tree = [];
285
286 // administrator layouts
287 $tree[] = [
288 'name' => 'admin',
289 'path' => VBO_ADMIN_PATH . DIRECTORY_SEPARATOR . 'layouts',
290 'folder' => true,
291 'files' => [],
292 ];
293
294 // site layouts
295 // $tree[] = [
296 // 'name' => 'site',
297 // 'path' => VBO_SITE_PATH . DIRECTORY_SEPARATOR . 'layouts',
298 // 'folder' => true,
299 // 'files' => [],
300 // ];
301
302 // system layouts
303 $tree[] = [
304 'name' => 'core',
305 'path' => VIKBOOKING_LIBRARIES . DIRECTORY_SEPARATOR . 'html',
306 'folder' => true,
307 'files' => [],
308 ];
309
310 // retrieve temporary uploads path
311 $upload = wp_upload_dir();
312
313 // create base path of overrides
314 $overridesPath = JPath::clean($upload['basedir'] . '/vikbooking/layouts/');
315
316 // iterate main nodes
317 foreach ($tree as &$node)
318 {
319 if ($node['name'] == 'site')
320 {
321 $op = $overridesPath . 'site' . DIRECTORY_SEPARATOR;
322 }
323 else
324 {
325 $op = $overridesPath . 'admin' . DIRECTORY_SEPARATOR;
326
327 if ($node['name'] == 'core')
328 {
329 // append HTML folder in case of core client
330 $op .= 'html' . DIRECTORY_SEPARATOR;
331 }
332 }
333
334 // scan and construct node recursively
335 $this->_scanNode($node, $op);
336 }
337
338 return $tree;
339 }
340
341 /**
342 * Creates the tree containing the available overrides for the plugin widgets.
343 *
344 * @return array The resulting tree.
345 */
346 protected function getModulesTree()
347 {
348 $tree = [];
349
350 // retrieve temporary uploads path
351 $upload = wp_upload_dir();
352
353 // create base path of overrides
354 $overridesPath = JPath::clean($upload['basedir'] . '/vikbooking/overrides/modules/');
355
356 // get all folders at the specified path
357 $modules = JFolder::folders(VIKBOOKING_BASE . '/modules', '.', $recursive = false, $fullPath = true);
358
359 // iterate modules and extract all the supported templates
360 foreach ($modules as $module)
361 {
362 $modName = basename($module);
363
364 // make sure the module should not be excluded
365 if (!$this->isExcluded($modName, $this->_excludedModules))
366 {
367 // create node to inject within the tree
368 $node = [
369 'name' => preg_replace("/^mod_vikbooking_/i", '', $modName),
370 'path' => $module,
371 'folder' => true,
372 'files' => [],
373 ];
374
375 // build path containing the module templates
376 $tmpl = JPath::clean($module . '/tmpl');
377
378 // scan files within the module
379 $files = JFolder::files($tmpl, '\.php$', $recursive = false, $fullPath = true);
380
381 // iterate files
382 foreach ($files as $file)
383 {
384 $filename = basename($file);
385
386 // create override path
387 $fileOverridePath = $overridesPath . $modName . DIRECTORY_SEPARATOR . $filename;
388
389 $published = false;
390
391 // look for an existing override
392 if (JFile::exists($fileOverridePath))
393 {
394 // the file owns an override
395 $override = $published = true;
396 }
397 else
398 {
399 // look for an unpublished override
400 $unpublishedPath = $overridesPath . $modName . DIRECTORY_SEPARATOR . '__' . $filename;
401
402 // check whether the file exists
403 if (JFile::exists($unpublishedPath))
404 {
405 // the file owns an unpublished override
406 $override = true;
407 }
408 else
409 {
410 // missing override
411 $override = false;
412 }
413 }
414
415 // register node within the parent
416 $node['files'][] = [
417 'name' => $filename,
418 'path' => $file,
419 'override' => $fileOverridePath,
420 'folder' => false,
421 'has' => $override,
422 'published' => $published,
423 ];
424 }
425
426 // append node to the tree
427 $tree[] = $node;
428 }
429 }
430
431 return $tree;
432 }
433
434 /**
435 * Recursive function used to scan the folder and files within the specified node.
436 *
437 * @param array &$node The node to scan.
438 * @param string $base The base path in which the overrides should locate.
439 *
440 * @return void
441 */
442 protected function _scanNode(array &$node, string $base)
443 {
444 // get all folders at the node path
445 $folders = JFolder::folders($node['path'], '.', $recursive = false, $fullPath = true);
446
447 // get all files at the node path
448 $files = JFolder::files($node['path'], '\.php$', $recursive = false, $fullPath = true);
449
450 // iterate folders
451 foreach ($folders as $folder)
452 {
453 $folderName = basename($folder);
454
455 // create folder node
456 $tmp = [
457 'name' => basename($folder),
458 'path' => $folder,
459 'folder' => true,
460 'files' => [],
461 ];
462
463 // folder recursive scan
464 $this->_scanNode($tmp, $base . $folderName . DIRECTORY_SEPARATOR);
465
466 // append folder to main node
467 $node['files'][] = $tmp;
468 }
469
470 // iterate files
471 foreach ($files as $file)
472 {
473 // make sure the file should not be excluded
474 if (!$this->isExcluded($file, $this->_excludedLayouts))
475 {
476 $filename = basename($file);
477
478 // create override path
479 $fileOverridePath = $base . $filename;
480
481 $published = false;
482
483 // look for an existing override
484 if (JFile::exists($fileOverridePath))
485 {
486 // the file owns an override
487 $override = $published = true;
488 }
489 else
490 {
491 // look for an unpublished override
492 $unpublishedPath = $base . DIRECTORY_SEPARATOR . '__' . $filename;
493
494 // check whether the file exists
495 if (JFile::exists($unpublishedPath))
496 {
497 // the file owns an unpublished override
498 $override = true;
499 }
500 else
501 {
502 // missing override
503 $override = false;
504 }
505 }
506
507 // create file node
508 $tmp = [
509 'name' => $filename,
510 'path' => $file,
511 'override' => $fileOverridePath,
512 'folder' => false,
513 'has' => $override,
514 'published' => $published,
515 ];
516
517 // append folder to main node
518 $node['files'][] = $tmp;
519 }
520 }
521 }
522
523 /**
524 * Check whether the specified path matches one of
525 * the specified regex.
526 *
527 * @param string $path The path to look for.
528 * @param array $pool An array of regex.
529 *
530 * @return bool True if excluded, false otherwise.
531 */
532 protected function isExcluded(string $path, array $pool)
533 {
534 $path = preg_replace("/[\\\\]/", '/', $path);
535
536 // iterate pool
537 foreach ($pool as $match)
538 {
539 // exec regex
540 if (preg_match("/$match/i", $path))
541 {
542 // inside the pool, exclude file
543 return true;
544 }
545 }
546
547 // can include file
548 return false;
549 }
550
551 /**
552 * Returns a lookup containing all the existing (and published) overrides,
553 * categorized by override group (admin, site, layouts, modules).
554 *
555 * Only the files that are an actual override of the core files will be taken here.
556 * In example, default_foo_bar.php is not part of VikBooking and therefore it
557 * will be discarded.
558 *
559 * @return array
560 */
561 public function getAllOverrides()
562 {
563 // retrieve temporary uploads path
564 $upload = wp_upload_dir();
565
566 // fetch all the files created on each section
567 $lookup = [
568 'admin' => JFolder::files($upload['basedir'] . '/vikbooking/overrides/admin/', '\.php$', true, true),
569 'site' => JFolder::files($upload['basedir'] . '/vikbooking/overrides/site/', '\.php$', true, true),
570 'layouts' => JFolder::files($upload['basedir'] . '/vikbooking/layouts/', '\.php$', true, true),
571 'modules' => JFolder::files($upload['basedir'] . '/vikbooking/overrides/modules/', '\.php$', true, true),
572 ];
573
574 // exclude all the overrides that are actually unpublished
575 foreach ($lookup as &$files)
576 {
577 if (!is_array($files))
578 {
579 $files = [];
580 }
581
582 $files = array_values(array_filter($files, function($file)
583 {
584 // the override file name must not start with 2 underscores
585 return strpos(basename($file), '__') !== 0;
586 }));
587 }
588
589 // get rid of the sections without files
590 return array_filter($lookup);
591 }
592 }
593