PluginProbe ʕ •ᴥ•ʔ
VikAppointments Services Booking Calendar / 1.2.21
VikAppointments Services Booking Calendar v1.2.21
1.2.21 1.2.20 trunk 1.2.17 1.2.18 1.2.19
vikappointments / libraries / adapter / mvc / view.php
vikappointments / libraries / adapter / mvc Last commit date
controllers 2 days ago models 2 days ago controller.php 2 days ago model.php 2 days ago view.php 2 days ago
view.php
342 lines
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 /**
15 * The view class used by the MVC framework to render a layout.
16 * The view is dispatched by the main controller if the value contained
17 * in $_REQUEST['task'] is equals to 'ComponentView' + $_REQUEST['task'].
18 *
19 * e.g. $_REQUEST['task'] = 'groups' -> ComponentViewGroups
20 *
21 * A view can be related to a model and/or to a controller (both optional).
22 *
23 * It is possible to create theme overrides for the views by adding the specific
24 * file into a path built as follows:
25 * /wp-content/uploads/[PLUGIN_NAME]/overrides/[CLIENT]/[VIEW_NAME]/[LAYOUT].php
26 *
27 * For example, in case we need to override the default.php file of the site 'groups' view
28 * that belong to the 'vik' plugin, the path will look like:
29 * /wp-content/uploads/vik/overrides/site/groups/default.php
30 *
31 * The client can assume only 2 values: site or admin.
32 *
33 * @since 10.0
34 */
35 #[\AllowDynamicProperties]
36 abstract class JView
37 {
38 /**
39 * The view base path.
40 *
41 * @var string
42 */
43 protected $_basePath;
44
45 /**
46 * The name of the default template source file.
47 *
48 * @var string
49 */
50 protected $_template = null;
51
52 /**
53 * The name of the layout source file.
54 *
55 * @var string
56 */
57 protected $_layout = null;
58
59 /**
60 * The view model.
61 *
62 * @var JModel
63 */
64 protected $_model = null;
65
66 /**
67 * The view name.
68 *
69 * @var string
70 * @since 10.1.15
71 */
72 protected $_name = null;
73
74 /**
75 * The document instance.
76 *
77 * @var JDocument
78 * @since 10.1.19
79 */
80 public $document = null;
81
82 /**
83 * Class constructor.
84 *
85 * @param string $base The view base path.
86 */
87 public function __construct($base)
88 {
89 $this->_basePath = $base;
90
91 $this->document = JFactory::getDocument();
92 }
93
94 /**
95 * Execute and display a template script.
96 *
97 * @param string $tpl The name of the template file to parse;
98 * automatically searches through the template paths.
99 *
100 * @return void
101 *
102 * @uses loadTemplate()
103 */
104 public function display($tpl = null)
105 {
106 $str = $this->loadTemplate($tpl);
107
108 if (is_string($str))
109 {
110 echo $str;
111 }
112 }
113
114 /**
115 * Sets a specific layout to use.
116 *
117 * @param string $layout The layout name.
118 *
119 * @return void
120 */
121 public function setLayout($layout)
122 {
123 $this->_layout = $layout;
124 }
125
126 /**
127 * Load a template file within the /tmpl folder of the view.
128 *
129 * @param string $tpl The name of the template source file;
130 * automatically searches the template paths and compiles as needed.
131 *
132 * @return string The output of the template script.
133 *
134 * @throws Exception
135 *
136 * @uses _getTemplateBasePath()
137 */
138 public function loadTemplate($tpl = null)
139 {
140 $file = 'default';
141
142 /**
143 * Custom layout should be evaluated first in order to
144 * prevent URL injection when setLayout() is called.
145 *
146 * @since 10.1.18
147 */
148 if (!is_null($this->_layout))
149 {
150 $file = $this->_layout;
151 }
152
153 /**
154 * Do not use an ELSEIF statement (as it was earlier) because we have to append the given
155 * template also in case the configured layout is different than "default", otherwise we
156 * risk to enter in an infinite loop.
157 *
158 * @since 10.1.41
159 */
160 if (!is_null($tpl))
161 {
162 $file .= '_' . $tpl;
163 }
164
165 /**
166 * Try to search for an override of this view.
167 *
168 * @since 10.1.2
169 */
170 $this->_template = $this->_getTemplateBasePath($this->_basePath, $file);
171
172 if (!$this->_template)
173 {
174 /**
175 * It doesn't exist an override of this view.
176 * Take the default one declared by the plugin.
177 *
178 * @note Use _template property to avoid injecting a useless variable.
179 */
180 $this->_template = $this->_basePath . DIRECTORY_SEPARATOR . 'tmpl';
181 }
182
183 // concat the layout file to the template path
184 $this->_template .= DIRECTORY_SEPARATOR . $file . '.php';
185
186 if (!is_file($this->_template))
187 {
188 $err = JText::translate('TEMPLATE_VIEW_NOT_FOUND_ERR');
189
190 if (WP_DEBUG)
191 {
192 $err .= "\nFile: [" . $file . ".php].";
193 }
194
195 throw new Exception($err, 404);
196 }
197 // unset method vars to not introduce them in the template
198 unset($tpl, $file);
199
200 // start capturing output into a buffer
201 ob_start();
202
203 // include the requested template filename in the local scope
204 include $this->_template;
205
206 // obtain the requested template
207 $output = ob_get_contents();
208
209 // get the buffer and clear it
210 ob_end_clean();
211
212 return $output;
213 }
214
215 /**
216 * Sets the view model.
217 *
218 * @param JModel $model The view model to set.
219 *
220 * @return void
221 */
222 public function setModel(JModel $model)
223 {
224 $this->_model = $model;
225 }
226
227 /**
228 * Returns the view model.
229 *
230 * @return JModel The view model, if any.
231 */
232 public function getModel()
233 {
234 return $this->_model;
235 }
236
237 /**
238 * Searches for an override of the specified view and layout.
239 *
240 * @param string $base The default basepath containing the plugin and view name.
241 * @param string $layout The layout name.
242 *
243 * @return mixed The override base path if exists, otherwise false.
244 *
245 * @since 10.1.2
246 */
247 protected function _getTemplateBasePath($base, $layout)
248 {
249 /**
250 * Check whether the base path refers to a WordPress only view.
251 *
252 * @since 10.1.48
253 */
254 if (!preg_match("/[\/\\\\]plugins[\/\\\\](.*?)[\/\\\\]libraries[\/\\\\]mvc[\/\\\\](.*?)[\/\\\\]/", $base, $match))
255 {
256 /**
257 * Make sure the base path contains the "plugin" name and the "client" section.
258 *
259 * @since 10.1.27 Added support for Windows backslash.
260 */
261 if (!preg_match("/[\/\\\\]plugins[\/\\\\](.*?)[\/\\\\](.*?)[\/\\\\]/", $base, $match))
262 {
263 // malformed base path, don't proceed
264 return false;
265 }
266 }
267
268 $upload = wp_upload_dir();
269
270 $parts = array();
271 // push base upload path
272 $parts[] = $upload['basedir'];
273 // push plugin name
274 $parts[] = $match[1];
275 // push default overrides folder
276 $parts[] = 'overrides';
277 // push client dir (site or admin)
278 $parts[] = $match[2];
279 // push view name
280 $parts[] = basename($base);
281
282 // Implode parts to build the template base path.
283 // DO NOT concat the file name as this method must
284 // return only the base path.
285 $template = implode(DIRECTORY_SEPARATOR, $parts);
286
287 if (JFile::exists($template . DIRECTORY_SEPARATOR . $layout . '.php'))
288 {
289 // the resulting override exists, return the updated base path
290 return $template;
291 }
292
293 // override not found
294 return false;
295 }
296
297 /**
298 * Method to get the view name.
299 *
300 * @return string The name of the view.
301 *
302 * @since 10.1.15
303 */
304 public function getName()
305 {
306 if (is_null($this->_name))
307 {
308 $class = get_class($this);
309
310 if (preg_match("/View(.*?)$/", $class, $match))
311 {
312 $this->_name = strtolower($match[1]);
313 }
314 else
315 {
316 $this->_name = $class;
317 }
318 }
319
320 return $this->_name;
321 }
322
323 /**
324 * Method to escape output.
325 *
326 * @param string $output The output to escape.
327 *
328 * @return string The escaped output.
329 *
330 * @since 10.1.20
331 */
332 public function escape($output)
333 {
334 /**
335 * Attributes are now escaped by using the built-in WP function.
336 *
337 * @since 10.1.33
338 */
339 return esc_attr($output);
340 }
341 }
342