PluginProbe ʕ •ᴥ•ʔ
VikAppointments Services Booking Calendar / 1.2.20
VikAppointments Services Booking Calendar v1.2.20
1.2.21 1.2.20 trunk 1.2.17 1.2.18 1.2.19
vikappointments / libraries / adapter / form / field.php
vikappointments / libraries / adapter / form Last commit date
fields 1 month ago field.php 1 month ago form.php 1 month ago
field.php
414 lines
1 <?php
2 /**
3 * @package VikWP - Libraries
4 * @subpackage adapter.form
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 * Form field class to handle XML fields.
16 *
17 * @since 10.0
18 */
19 #[\AllowDynamicProperties]
20 abstract class JFormField
21 {
22 /**
23 * A list of paths in which to search for the fields to load.
24 *
25 * @var array
26 */
27 private static $_paths = array();
28
29 /**
30 * A map of relationships between the types and the handlers classnames.
31 *
32 * @var array
33 */
34 private static $_cache = array();
35
36 /**
37 * The layout identifier.
38 * Overwrite in children classes.
39 *
40 * @var string
41 * @since 10.1.20
42 */
43 protected $layoutId = null;
44
45 /**
46 * The JForm object of the form attached to the form field.
47 *
48 * @var JForm
49 * @since 10.1.31
50 */
51 protected $form;
52
53 /**
54 * Tries to instantiate the class used to handle
55 * the specified field XML element.
56 *
57 * @param SimpleXMLElement $field The field element.
58 *
59 * @return JFormField A new field instance.
60 */
61 public static function getInstance($field)
62 {
63 // get field type
64 $type = (string) $field->attributes()->type;
65
66 // text by default
67 if (empty($type))
68 {
69 $type = 'text';
70 }
71
72 // if not cached, search for a handler classname
73 if (!isset(static::$_cache[$type]))
74 {
75 // find the handler
76 $res = static::findField($type);
77
78 // on failure, text handler by default
79 if (!$res)
80 {
81 $res = 'JFormFieldText';
82 }
83
84 // cache the handler
85 static::$_cache[$type] = $res;
86 }
87
88 // obtain the classname from the cache
89 $classname = static::$_cache[$type];
90
91 // instantiate the handler
92 return new $classname($field);
93 }
94
95 /**
96 * Tries to search for the specified field type.
97 *
98 * @param string $type The field type.
99 *
100 * @return mixed The field classname on success, otherwise false.
101 */
102 protected static function findField($type)
103 {
104 // get default fields pool (./fields)
105 $paths = array();
106 $paths[] = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'fields';
107
108 // merge the default and additional paths
109 $paths = array_merge($paths, static::$_paths);
110
111 // iterate the paths
112 foreach ($paths as $path)
113 {
114 // try to load the handler
115 if (JLoader::import($type, $path))
116 {
117 // build classname
118 $classname = 'JFormField' . ucwords($type);
119
120 // make sure the handler exists
121 if (class_exists($classname))
122 {
123 // file found, return the classname
124 return $classname;
125 }
126 }
127 }
128
129 // load text field for unknown types
130 JLoader::import('adapter.form.fields.text');
131
132 return false;
133 }
134
135 /**
136 * Adds a new path containing custom fields handlers.
137 *
138 * @param string $path The directory path.
139 *
140 * @return void
141 */
142 public static function addIncludePath($path)
143 {
144 if (!in_array($path, static::$_paths))
145 {
146 static::$_paths[] = $path;
147 }
148 }
149
150 /**
151 * Class constructor.
152 *
153 * @param SimpleXMLElement $field The field element.
154 */
155 public function __construct($field)
156 {
157 $this->setup($field);
158 }
159
160 /**
161 * Helper method to setup the field.
162 *
163 * @param SimpleXMLElement $field The field element.
164 *
165 * @return void
166 */
167 protected function setup($element)
168 {
169 // workaround for sql fields with no default option
170 $this->option = array();
171
172 // iterate the attributes
173 foreach ($element->attributes() as $k => $v)
174 {
175 $this->{$k} = (string) $v;
176 }
177
178 if (count($element))
179 {
180 // iterate the children
181 foreach ($element as $k => $child)
182 {
183 // create the container if not set
184 if (!isset($this->{$k}))
185 {
186 $this->{$k} = array();
187 }
188
189 // get the value from attributes
190 $value = $child->attributes()->value;
191
192 if (is_null($value))
193 {
194 // push the element without key if the value is NULL
195 $this->{$k}[] = (string) $child;
196 }
197 else
198 {
199 // the value is set, make an associative list
200 $this->{$k}[(string) $value] = (string) $child;
201 }
202 }
203 }
204
205 /**
206 * In case value is not set, use default one.
207 *
208 * @since 10.1.29
209 */
210 if (!isset($this->value) && isset($this->default))
211 {
212 $this->value = $this->default;
213 }
214
215 // register original field name and ID
216 $this->fieldName = $this->name;
217 $this->fieldId = $this->id;
218
219 // set up field name
220 $this->name = $this->getName($this->fieldName);
221 // set up field ID
222 $this->id = $this->getId($this->fieldID, $this->fieldName);
223 }
224
225 /**
226 * Magic method to access internal properties.
227 *
228 * @param string $name The property to access.
229 *
230 * @return mixed The property value.
231 */
232 public function __get($name)
233 {
234 // protected properties are not allowed
235 $name = ltrim($name, '_');
236
237 // check if the property exists
238 if (isset($this->{$name}))
239 {
240 return $this->{$name};
241 }
242 // if name is equals to 'element' return an assoc
243 // list containing all the field attributes
244 else if ($name === 'element')
245 {
246 // get a list of public properties
247 return (array) get_object_vars($this);
248 }
249
250 return null;
251 }
252
253 /**
254 * Method used to bind the field properties.
255 *
256 * @param mixed $value The property value.
257 * @param string $key The property name (value by default).
258 *
259 * @return self This object to support chaining.
260 */
261 public function bind($value, $key = 'value')
262 {
263 $this->{$key} = $value;
264
265 return $this;
266 }
267
268 /**
269 * Placeholder used to render the form field.
270 *
271 * @return string The HTML field.
272 *
273 * @uses getInput()
274 */
275 public function render()
276 {
277 return $this->getInput();
278 }
279
280 /**
281 * Placeholder used to render the form field.
282 *
283 * @return string The HTML field.
284 *
285 * @uses getLayoutData()
286 */
287 public function getInput()
288 {
289 // make sure we have a layout id
290 if (!$this->layoutId)
291 {
292 return;
293 }
294
295 // create layout file
296 $layout = new JLayoutFile($this->layoutId);
297
298 if (!empty($this->modowner))
299 {
300 // in case of modowner property, add plugin include path to access layout files properly
301 $layout->addIncludePath(implode(DIRECTORY_SEPARATOR, array(WP_PLUGIN_DIR, $this->modowner, 'libraries')));
302 }
303
304 // obtain layout data and complete field rendering
305 return $layout->render($this->getLayoutData());
306 }
307
308 /**
309 * Method to get the data to be passed to the layout for rendering.
310 *
311 * @return array An associative array of display data.
312 *
313 * @since 10.1.20
314 */
315 public function getLayoutData()
316 {
317 return array();
318 }
319
320 /**
321 * Method to attach a JForm object to the field.
322 *
323 * @param Form $form The JForm object to attach to the form field.
324 *
325 * @return self this object to support chaining.
326 *
327 * @since 10.1.31
328 */
329 public function setForm(JForm $form)
330 {
331 $this->form = $form;
332
333 // set up field name
334 $this->name = $this->getName($this->fieldName);
335 // set up field ID
336 $this->id = $this->getId($this->fieldID, $this->fieldName);
337
338 return $this;
339 }
340
341 /**
342 * Method to get the name used for the field input tag.
343 *
344 * @param string $fieldName The field element name.
345 *
346 * @return string The name to be used for the field input tag.
347 *
348 * @since 10.1.31
349 */
350 protected function getName($fieldName)
351 {
352 $name = '';
353
354 $formControl = $this->form ? $this->form->getFormControl() : '';
355
356 // if there is a form control set for the attached form add it first
357 if ($formControl)
358 {
359 $name .= $formControl;
360 }
361
362 // if we already have a name segment add the field name as another level
363 if ($name)
364 {
365 $name .= '[' . $fieldName . ']';
366 }
367 else
368 {
369 $name .= $fieldName;
370 }
371
372 return $name;
373 }
374
375 /**
376 * Method to get the id used for the field input tag.
377 *
378 * @param string $fieldId The field element id.
379 * @param string $fieldName The field element name.
380 *
381 * @return string The id to be used for the field input tag.
382 *
383 * @since 10.1.31
384 */
385 protected function getId($fieldId, $fieldName)
386 {
387 $id = '';
388
389 $formControl = $this->form ? $this->form->getFormControl() : '';
390
391 // if there is a form control set for the attached form add it first
392 if ($formControl)
393 {
394 $id .= $formControl . '_';
395 }
396 else
397 {
398 // use default one for IDs
399 $id .= 'jform_';
400 }
401
402 if ($fieldId)
403 {
404 $id .= $fieldId;
405 }
406 else
407 {
408 $id .= preg_replace("/[^a-z0-9_\-]+/i", '', $fieldName);
409 }
410
411 return $id;
412 }
413 }
414