PageRenderTime 33ms CodeModel.GetById 14ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 0ms

/libraries/joomla/form/field.php

https://gitlab.com/vitaliylukin91/alex-lavka
PHP | 923 lines | 404 code | 118 blank | 401 comment | 62 complexity | 2092abae953f8a2f2ba02901f356d4b8 MD5 | raw file
  1<?php
  2/**
  3 * @package     Joomla.Platform
  4 * @subpackage  Form
  5 *
  6 * @copyright   Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved.
  7 * @license     GNU General Public License version 2 or later; see LICENSE
  8 */
  9
 10defined('JPATH_PLATFORM') or die;
 11
 12/**
 13 * Abstract Form Field class for the Joomla Platform.
 14 *
 15 * @since  11.1
 16 */
 17abstract class JFormField
 18{
 19	/**
 20	 * The description text for the form field. Usually used in tooltips.
 21	 *
 22	 * @var    string
 23	 * @since  11.1
 24	 */
 25	protected $description;
 26
 27	/**
 28	 * The hint text for the form field used to display hint inside the field.
 29	 *
 30	 * @var    string
 31	 * @since  3.2
 32	 */
 33	protected $hint;
 34
 35	/**
 36	 * The autocomplete state for the form field.  If 'off' element will not be automatically
 37	 * completed by browser.
 38	 *
 39	 * @var    mixed
 40	 * @since  3.2
 41	 */
 42	protected $autocomplete = 'on';
 43
 44	/**
 45	 * The spellcheck state for the form field.
 46	 *
 47	 * @var    boolean
 48	 * @since  3.2
 49	 */
 50	protected $spellcheck = true;
 51
 52	/**
 53	 * The autofocus request for the form field.  If true element will be automatically
 54	 * focused on document load.
 55	 *
 56	 * @var    boolean
 57	 * @since  3.2
 58	 */
 59	protected $autofocus = false;
 60
 61	/**
 62	 * The SimpleXMLElement object of the <field /> XML element that describes the form field.
 63	 *
 64	 * @var    SimpleXMLElement
 65	 * @since  11.1
 66	 */
 67	protected $element;
 68
 69	/**
 70	 * The JForm object of the form attached to the form field.
 71	 *
 72	 * @var    JForm
 73	 * @since  11.1
 74	 */
 75	protected $form;
 76
 77	/**
 78	 * The form control prefix for field names from the JForm object attached to the form field.
 79	 *
 80	 * @var    string
 81	 * @since  11.1
 82	 */
 83	protected $formControl;
 84
 85	/**
 86	 * The hidden state for the form field.
 87	 *
 88	 * @var    boolean
 89	 * @since  11.1
 90	 */
 91	protected $hidden = false;
 92
 93	/**
 94	 * True to translate the field label string.
 95	 *
 96	 * @var    boolean
 97	 * @since  11.1
 98	 */
 99	protected $translateLabel = true;
100
101	/**
102	 * True to translate the field description string.
103	 *
104	 * @var    boolean
105	 * @since  11.1
106	 */
107	protected $translateDescription = true;
108
109	/**
110	 * True to translate the field hint string.
111	 *
112	 * @var    boolean
113	 * @since  3.2
114	 */
115	protected $translateHint = true;
116
117	/**
118	 * The document id for the form field.
119	 *
120	 * @var    string
121	 * @since  11.1
122	 */
123	protected $id;
124
125	/**
126	 * The input for the form field.
127	 *
128	 * @var    string
129	 * @since  11.1
130	 */
131	protected $input;
132
133	/**
134	 * The label for the form field.
135	 *
136	 * @var    string
137	 * @since  11.1
138	 */
139	protected $label;
140
141	/**
142	 * The multiple state for the form field.  If true then multiple values are allowed for the
143	 * field.  Most often used for list field types.
144	 *
145	 * @var    boolean
146	 * @since  11.1
147	 */
148	protected $multiple = false;
149
150	/**
151	 * Allows extensions to create repeat elements
152	 *
153	 * @var    mixed
154	 * @since  3.2
155	 */
156	public $repeat = false;
157
158	/**
159	 * The pattern (Reg Ex) of value of the form field.
160	 *
161	 * @var    string
162	 * @since  11.1
163	 */
164	protected $pattern;
165
166	/**
167	 * The name of the form field.
168	 *
169	 * @var    string
170	 * @since  11.1
171	 */
172	protected $name;
173
174	/**
175	 * The name of the field.
176	 *
177	 * @var    string
178	 * @since  11.1
179	 */
180	protected $fieldname;
181
182	/**
183	 * The group of the field.
184	 *
185	 * @var    string
186	 * @since  11.1
187	 */
188	protected $group;
189
190	/**
191	 * The required state for the form field.  If true then there must be a value for the field to
192	 * be considered valid.
193	 *
194	 * @var    boolean
195	 * @since  11.1
196	 */
197	protected $required = false;
198
199	/**
200	 * The disabled state for the form field.  If true then the field will be disabled and user can't
201	 * interact with the field.
202	 *
203	 * @var    boolean
204	 * @since  3.2
205	 */
206	protected $disabled = false;
207
208	/**
209	 * The readonly state for the form field.  If true then the field will be readonly.
210	 *
211	 * @var    boolean
212	 * @since  3.2
213	 */
214	protected $readonly = false;
215
216	/**
217	 * The form field type.
218	 *
219	 * @var    string
220	 * @since  11.1
221	 */
222	protected $type;
223
224	/**
225	 * The validation method for the form field.  This value will determine which method is used
226	 * to validate the value for a field.
227	 *
228	 * @var    string
229	 * @since  11.1
230	 */
231	protected $validate;
232
233	/**
234	 * The value of the form field.
235	 *
236	 * @var    mixed
237	 * @since  11.1
238	 */
239	protected $value;
240
241	/**
242	 * The default value of the form field.
243	 *
244	 * @var    mixed
245	 * @since  11.1
246	 */
247	protected $default;
248
249	/**
250	 * The size of the form field.
251	 *
252	 * @var    integer
253	 * @since  3.2
254	 */
255	protected $size;
256
257	/**
258	 * The class of the form field
259	 *
260	 * @var    mixed
261	 * @since  3.2
262	 */
263	protected $class;
264
265	/**
266	 * The label's CSS class of the form field
267	 *
268	 * @var    mixed
269	 * @since  11.1
270	 */
271	protected $labelclass;
272
273	/**
274	 * The javascript onchange of the form field.
275	 *
276	 * @var    string
277	 * @since  3.2
278	 */
279	protected $onchange;
280
281	/**
282	 * The javascript onclick of the form field.
283	 *
284	 * @var    string
285	 * @since  3.2
286	 */
287	protected $onclick;
288
289	/**
290	 * The count value for generated name field
291	 *
292	 * @var    integer
293	 * @since  11.1
294	 */
295	protected static $count = 0;
296
297	/**
298	 * The string used for generated fields names
299	 *
300	 * @var    string
301	 * @since  11.1
302	 */
303	protected static $generated_fieldname = '__field';
304
305	/**
306	 * Layout to render the form field
307	 *
308	 * @var  string
309	 */
310	protected $renderLayout = 'joomla.form.renderfield';
311
312	/**
313	 * Layout to render the label
314	 *
315	 * @var  string
316	 */
317	protected $renderLabelLayout = 'joomla.form.renderlabel';
318
319	/**
320	 * Method to instantiate the form field object.
321	 *
322	 * @param   JForm  $form  The form to attach to the form field object.
323	 *
324	 * @since   11.1
325	 */
326	public function __construct($form = null)
327	{
328		// If there is a form passed into the constructor set the form and form control properties.
329		if ($form instanceof JForm)
330		{
331			$this->form = $form;
332			$this->formControl = $form->getFormControl();
333		}
334
335		// Detect the field type if not set
336		if (!isset($this->type))
337		{
338			$parts = JStringNormalise::fromCamelCase(get_called_class(), true);
339
340			if ($parts[0] == 'J')
341			{
342				$this->type = JString::ucfirst($parts[count($parts) - 1], '_');
343			}
344			else
345			{
346				$this->type = JString::ucfirst($parts[0], '_') . JString::ucfirst($parts[count($parts) - 1], '_');
347			}
348		}
349	}
350
351	/**
352	 * Method to get certain otherwise inaccessible properties from the form field object.
353	 *
354	 * @param   string  $name  The property name for which to the the value.
355	 *
356	 * @return  mixed  The property value or null.
357	 *
358	 * @since   11.1
359	 */
360	public function __get($name)
361	{
362		switch ($name)
363		{
364			case 'description':
365			case 'hint':
366			case 'formControl':
367			case 'hidden':
368			case 'id':
369			case 'multiple':
370			case 'name':
371			case 'required':
372			case 'type':
373			case 'validate':
374			case 'value':
375			case 'class':
376			case 'labelclass':
377			case 'size':
378			case 'onchange':
379			case 'onclick':
380			case 'fieldname':
381			case 'group':
382			case 'disabled':
383			case 'readonly':
384			case 'autofocus':
385			case 'autocomplete':
386			case 'spellcheck':
387				return $this->$name;
388
389			case 'input':
390				// If the input hasn't yet been generated, generate it.
391				if (empty($this->input))
392				{
393					$this->input = $this->getInput();
394				}
395
396				return $this->input;
397
398			case 'label':
399				// If the label hasn't yet been generated, generate it.
400				if (empty($this->label))
401				{
402					$this->label = $this->getLabel();
403				}
404
405				return $this->label;
406
407			case 'title':
408				return $this->getTitle();
409		}
410
411		return null;
412	}
413
414	/**
415	 * Method to set certain otherwise inaccessible properties of the form field object.
416	 *
417	 * @param   string  $name   The property name for which to the the value.
418	 * @param   mixed   $value  The value of the property.
419	 *
420	 * @return  void
421	 *
422	 * @since   3.2
423	 */
424	public function __set($name, $value)
425	{
426		switch ($name)
427		{
428			case 'class':
429				// Removes spaces from left & right and extra spaces from middle
430				$value = preg_replace('/\s+/', ' ', trim((string) $value));
431
432			case 'description':
433			case 'hint':
434			case 'value':
435			case 'labelclass':
436			case 'onchange':
437			case 'onclick':
438			case 'validate':
439			case 'pattern':
440			case 'group':
441			case 'default':
442				$this->$name = (string) $value;
443				break;
444
445			case 'id':
446				$this->id = $this->getId((string) $value, $this->fieldname);
447				break;
448
449			case 'fieldname':
450				$this->fieldname = $this->getFieldName((string) $value);
451				break;
452
453			case 'name':
454				$this->fieldname = $this->getFieldName((string) $value);
455				$this->name = $this->getName($this->fieldname);
456				break;
457
458			case 'multiple':
459				// Allow for field classes to force the multiple values option.
460				$value = (string) $value;
461				$value = $value === '' && isset($this->forceMultiple) ? (string) $this->forceMultiple : $value;
462
463			case 'required':
464			case 'disabled':
465			case 'readonly':
466			case 'autofocus':
467			case 'hidden':
468				$value = (string) $value;
469				$this->$name = ($value === 'true' || $value === $name || $value === '1');
470				break;
471
472			case 'autocomplete':
473				$value = (string) $value;
474				$value = ($value == 'on' || $value == '') ? 'on' : $value;
475				$this->$name = ($value === 'false' || $value === 'off' || $value === '0') ? false : $value;
476				break;
477
478			case 'spellcheck':
479			case 'translateLabel':
480			case 'translateDescription':
481			case 'translateHint':
482				$value = (string) $value;
483				$this->$name = !($value === 'false' || $value === 'off' || $value === '0');
484				break;
485
486			case 'translate_label':
487				$value = (string) $value;
488				$this->translateLabel = $this->translateLabel && !($value === 'false' || $value === 'off' || $value === '0');
489				break;
490
491			case 'translate_description':
492				$value = (string) $value;
493				$this->translateDescription = $this->translateDescription && !($value === 'false' || $value === 'off' || $value === '0');
494				break;
495
496			case 'size':
497				$this->$name = (int) $value;
498				break;
499
500			default:
501				if (property_exists(__CLASS__, $name))
502				{
503					JLog::add("Cannot access protected / private property $name of " . __CLASS__);
504				}
505				else
506				{
507					$this->$name = $value;
508				}
509		}
510	}
511
512	/**
513	 * Method to attach a JForm object to the field.
514	 *
515	 * @param   JForm  $form  The JForm object to attach to the form field.
516	 *
517	 * @return  JFormField  The form field object so that the method can be used in a chain.
518	 *
519	 * @since   11.1
520	 */
521	public function setForm(JForm $form)
522	{
523		$this->form = $form;
524		$this->formControl = $form->getFormControl();
525
526		return $this;
527	}
528
529	/**
530	 * Method to attach a JForm object to the field.
531	 *
532	 * @param   SimpleXMLElement  $element  The SimpleXMLElement object representing the <field /> tag for the form field object.
533	 * @param   mixed             $value    The form field value to validate.
534	 * @param   string            $group    The field name group control value. This acts as as an array container for the field.
535	 *                                      For example if the field has name="foo" and the group value is set to "bar" then the
536	 *                                      full field name would end up being "bar[foo]".
537	 *
538	 * @return  boolean  True on success.
539	 *
540	 * @since   11.1
541	 */
542	public function setup(SimpleXMLElement $element, $value, $group = null)
543	{
544		// Make sure there is a valid JFormField XML element.
545		if ((string) $element->getName() != 'field')
546		{
547			return false;
548		}
549
550		// Reset the input and label values.
551		$this->input = null;
552		$this->label = null;
553
554		// Set the XML element object.
555		$this->element = $element;
556
557		// Set the group of the field.
558		$this->group = $group;
559
560		$attributes = array(
561			'multiple', 'name', 'id', 'hint', 'class', 'description', 'labelclass', 'onchange',
562			'onclick', 'validate', 'pattern', 'default', 'required',
563			'disabled', 'readonly', 'autofocus', 'hidden', 'autocomplete', 'spellcheck',
564			'translateHint', 'translateLabel','translate_label', 'translateDescription',
565			'translate_description' ,'size');
566
567		$this->default = isset($element['value']) ? (string) $element['value'] : $this->default;
568
569		// Set the field default value.
570		$this->value = $value;
571
572		foreach ($attributes as $attributeName)
573		{
574			$this->__set($attributeName, $element[$attributeName]);
575		}
576
577		// Allow for repeatable elements
578		$repeat = (string) $element['repeat'];
579		$this->repeat = ($repeat == 'true' || $repeat == 'multiple' || (!empty($this->form->repeat) && $this->form->repeat == 1));
580
581		// Set the visibility.
582		$this->hidden = ($this->hidden || (string) $element['type'] == 'hidden');
583
584		// Add required to class list if field is required.
585		if ($this->required)
586		{
587			$this->class = trim($this->class . ' required');
588		}
589
590		return true;
591	}
592
593	/**
594	 * Simple method to set the value
595	 *
596	 * @param   mixed  $value  Value to set
597	 *
598	 * @return  void
599	 *
600	 * @since   3.2
601	 */
602	public function setValue($value)
603	{
604		$this->value = $value;
605	}
606
607	/**
608	 * Method to get the id used for the field input tag.
609	 *
610	 * @param   string  $fieldId    The field element id.
611	 * @param   string  $fieldName  The field element name.
612	 *
613	 * @return  string  The id to be used for the field input tag.
614	 *
615	 * @since   11.1
616	 */
617	protected function getId($fieldId, $fieldName)
618	{
619		$id = '';
620
621		// If there is a form control set for the attached form add it first.
622		if ($this->formControl)
623		{
624			$id .= $this->formControl;
625		}
626
627		// If the field is in a group add the group control to the field id.
628		if ($this->group)
629		{
630			// If we already have an id segment add the group control as another level.
631			if ($id)
632			{
633				$id .= '_' . str_replace('.', '_', $this->group);
634			}
635			else
636			{
637				$id .= str_replace('.', '_', $this->group);
638			}
639		}
640
641		// If we already have an id segment add the field id/name as another level.
642		if ($id)
643		{
644			$id .= '_' . ($fieldId ? $fieldId : $fieldName);
645		}
646		else
647		{
648			$id .= ($fieldId ? $fieldId : $fieldName);
649		}
650
651		// Clean up any invalid characters.
652		$id = preg_replace('#\W#', '_', $id);
653
654		// If this is a repeatable element, add the repeat count to the ID
655		if ($this->repeat)
656		{
657			$repeatCounter = empty($this->form->repeatCounter) ? 0 : $this->form->repeatCounter;
658			$id .= '-' . $repeatCounter;
659
660			if (strtolower($this->type) == 'radio')
661			{
662				$id .= '-';
663			}
664		}
665
666		return $id;
667	}
668
669	/**
670	 * Method to get the field input markup.
671	 *
672	 * @return  string  The field input markup.
673	 *
674	 * @since   11.1
675	 */
676	abstract protected function getInput();
677
678	/**
679	 * Method to get the field title.
680	 *
681	 * @return  string  The field title.
682	 *
683	 * @since   11.1
684	 */
685	protected function getTitle()
686	{
687		$title = '';
688
689		if ($this->hidden)
690		{
691			return $title;
692		}
693
694		// Get the label text from the XML element, defaulting to the element name.
695		$title = $this->element['label'] ? (string) $this->element['label'] : (string) $this->element['name'];
696		$title = $this->translateLabel ? JText::_($title) : $title;
697
698		return $title;
699	}
700
701	/**
702	 * Method to get the field label markup.
703	 *
704	 * @return  string  The field label markup.
705	 *
706	 * @since   11.1
707	 */
708	protected function getLabel()
709	{
710		if ($this->hidden)
711		{
712			return '';
713		}
714
715		// Get the label text from the XML element, defaulting to the element name.
716		$text = $this->element['label'] ? (string) $this->element['label'] : (string) $this->element['name'];
717		$text = $this->translateLabel ? JText::_($text) : $text;
718
719		// Forcing the Alias field to display the tip below
720		$position = $this->element['name'] == 'alias' ? ' data-placement="bottom" ' : '';
721
722		$description = ($this->translateDescription && !empty($this->description)) ? JText::_($this->description) : $this->description;
723
724		$displayData = array(
725				'text'        => $text,
726				'description' => $description,
727				'for'         => $this->id,
728				'required'    => (bool) $this->required,
729				'classes'     => explode(' ', $this->labelclass),
730				'position'    => $position
731			);
732
733		return JLayoutHelper::render($this->renderLabelLayout, $displayData);
734	}
735
736	/**
737	 * Method to get the name used for the field input tag.
738	 *
739	 * @param   string  $fieldName  The field element name.
740	 *
741	 * @return  string  The name to be used for the field input tag.
742	 *
743	 * @since   11.1
744	 */
745	protected function getName($fieldName)
746	{
747		// To support repeated element, extensions can set this in plugin->onRenderSettings
748		$repeatCounter = empty($this->form->repeatCounter) ? 0 : $this->form->repeatCounter;
749
750		$name = '';
751
752		// If there is a form control set for the attached form add it first.
753		if ($this->formControl)
754		{
755			$name .= $this->formControl;
756		}
757
758		// If the field is in a group add the group control to the field name.
759		if ($this->group)
760		{
761			// If we already have a name segment add the group control as another level.
762			$groups = explode('.', $this->group);
763
764			if ($name)
765			{
766				foreach ($groups as $group)
767				{
768					$name .= '[' . $group . ']';
769				}
770			}
771			else
772			{
773				$name .= array_shift($groups);
774
775				foreach ($groups as $group)
776				{
777					$name .= '[' . $group . ']';
778				}
779			}
780		}
781
782		// If we already have a name segment add the field name as another level.
783		if ($name)
784		{
785			$name .= '[' . $fieldName . ']';
786		}
787		else
788		{
789			$name .= $fieldName;
790		}
791
792		// If the field should support multiple values add the final array segment.
793		if ($this->multiple)
794		{
795			switch (strtolower((string) $this->element['type']))
796			{
797				case 'text':
798				case 'textarea':
799				case 'email':
800				case 'password':
801				case 'radio':
802				case 'calendar':
803				case 'editor':
804				case 'hidden':
805					break;
806				default:
807					$name .= '[]';
808			}
809		}
810
811		return $name;
812	}
813
814	/**
815	 * Method to get the field name used.
816	 *
817	 * @param   string  $fieldName  The field element name.
818	 *
819	 * @return  string  The field name
820	 *
821	 * @since   11.1
822	 */
823	protected function getFieldName($fieldName)
824	{
825		if ($fieldName)
826		{
827			return $fieldName;
828		}
829		else
830		{
831			self::$count = self::$count + 1;
832
833			return self::$generated_fieldname . self::$count;
834		}
835	}
836
837	/**
838	 * Method to get an attribute of the field
839	 *
840	 * @param   string  $name     Name of the attribute to get
841	 * @param   mixed   $default  Optional value to return if attribute not found
842	 *
843	 * @return  mixed             Value of the attribute / default
844	 *
845	 * @since   3.2
846	 */
847	public function getAttribute($name, $default = null)
848	{
849		if ($this->element instanceof SimpleXMLElement)
850		{
851			$attributes = $this->element->attributes();
852
853			// Ensure that the attribute exists
854			if (property_exists($attributes, $name))
855			{
856				$value = $attributes->$name;
857
858				if ($value !== null)
859				{
860					return (string) $value;
861				}
862			}
863		}
864
865		return $default;
866	}
867
868	/**
869	 * Method to get a control group with label and input.
870	 *
871	 * @return  string  A string containing the html for the control group
872	 *
873	 * @since      3.2
874	 * @deprecated 3.2.3 Use renderField() instead
875	 */
876	public function getControlGroup()
877	{
878		JLog::add('JFormField->getControlGroup() is deprecated use JFormField->renderField().', JLog::WARNING, 'deprecated');
879
880		return $this->renderField();
881	}
882
883	/**
884	 * Method to get a control group with label and input.
885	 *
886	 * @param   array  $options  Options to be passed into the rendering of the field
887	 *
888	 * @return  string  A string containing the html for the control group
889	 *
890	 * @since   3.2
891	 */
892	public function renderField($options = array())
893	{
894		if ($this->hidden)
895		{
896			return $this->getInput();
897		}
898
899		if (!isset($options['class']))
900		{
901			$options['class'] = '';
902		}
903
904		$options['rel'] = '';
905
906		if (empty($options['hiddenLabel']) && $this->getAttribute('hiddenLabel'))
907		{
908			$options['hiddenLabel'] = true;
909		}
910
911		if ($showon = $this->getAttribute('showon'))
912		{
913			$showon   = explode(':', $showon, 2);
914			$options['class'] .= ' showon_' . implode(' showon_', explode(',', $showon[1]));
915			$id = $this->getName($showon[0]);
916			$id = $this->multiple ? str_replace('[]', '', $id) : $id;
917			$options['rel'] = ' rel="showon_' . $id . '"';
918			$options['showonEnabled'] = true;
919		}
920
921		return JLayoutHelper::render($this->renderLayout, array('input' => $this->getInput(), 'label' => $this->getLabel(), 'options' => $options));
922	}
923}