Passed
Pull Request — develop (#889)
by Shandak
04:24
created

JFormField::isDebugEnabled()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 1
c 1
b 1
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
/**
3
 * @package     Joomla.Platform
4
 * @subpackage  Form
5
 *
6
 * @copyright   Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved.
7
 * @license     GNU General Public License version 2 or later; see LICENSE
8
 */
9
10
defined('JPATH_PLATFORM') or die;
11
12
use Joomla\String\Normalise;
13
use Joomla\String\StringHelper;
14
15
/**
16
 * Abstract Form Field class for the Joomla Platform.
17
 *
18
 * @since  11.1
19
 */
20
abstract class JFormField
21
{
22
	/**
23
	 * The description text for the form field. Usually used in tooltips.
24
	 *
25
	 * @var    string
26
	 * @since  11.1
27
	 */
28
	protected $description;
29
30
	/**
31
	 * The hint text for the form field used to display hint inside the field.
32
	 *
33
	 * @var    string
34
	 * @since  3.2
35
	 */
36
	protected $hint;
37
38
	/**
39
	 * The autocomplete state for the form field.  If 'off' element will not be automatically
40
	 * completed by browser.
41
	 *
42
	 * @var    mixed
43
	 * @since  3.2
44
	 */
45
	protected $autocomplete = 'on';
46
47
	/**
48
	 * The spellcheck state for the form field.
49
	 *
50
	 * @var    boolean
51
	 * @since  3.2
52
	 */
53
	protected $spellcheck = true;
54
55
	/**
56
	 * The autofocus request for the form field.  If true element will be automatically
57
	 * focused on document load.
58
	 *
59
	 * @var    boolean
60
	 * @since  3.2
61
	 */
62
	protected $autofocus = false;
63
64
	/**
65
	 * The SimpleXMLElement object of the `<field>` XML element that describes the form field.
66
	 *
67
	 * @var    SimpleXMLElement
68
	 * @since  11.1
69
	 */
70
	protected $element;
71
72
	/**
73
	 * The JForm object of the form attached to the form field.
74
	 *
75
	 * @var    JForm
76
	 * @since  11.1
77
	 */
78
	protected $form;
79
80
	/**
81
	 * The form control prefix for field names from the JForm object attached to the form field.
82
	 *
83
	 * @var    string
84
	 * @since  11.1
85
	 */
86
	protected $formControl;
87
88
	/**
89
	 * The hidden state for the form field.
90
	 *
91
	 * @var    boolean
92
	 * @since  11.1
93
	 */
94
	protected $hidden = false;
95
96
	/**
97
	 * True to translate the field label string.
98
	 *
99
	 * @var    boolean
100
	 * @since  11.1
101
	 */
102
	protected $translateLabel = true;
103
104
	/**
105
	 * True to translate the field description string.
106
	 *
107
	 * @var    boolean
108
	 * @since  11.1
109
	 */
110
	protected $translateDescription = true;
111
112
	/**
113
	 * True to translate the field hint string.
114
	 *
115
	 * @var    boolean
116
	 * @since  3.2
117
	 */
118
	protected $translateHint = true;
119
120
	/**
121
	 * The document id for the form field.
122
	 *
123
	 * @var    string
124
	 * @since  11.1
125
	 */
126
	protected $id;
127
128
	/**
129
	 * The input for the form field.
130
	 *
131
	 * @var    string
132
	 * @since  11.1
133
	 */
134
	protected $input;
135
136
	/**
137
	 * The label for the form field.
138
	 *
139
	 * @var    string
140
	 * @since  11.1
141
	 */
142
	protected $label;
143
144
	/**
145
	 * The multiple state for the form field.  If true then multiple values are allowed for the
146
	 * field.  Most often used for list field types.
147
	 *
148
	 * @var    boolean
149
	 * @since  11.1
150
	 */
151
	protected $multiple = false;
152
153
	/**
154
	 * Allows extensions to create repeat elements
155
	 *
156
	 * @var    mixed
157
	 * @since  3.2
158
	 */
159
	public $repeat = false;
160
161
	/**
162
	 * The pattern (Reg Ex) of value of the form field.
163
	 *
164
	 * @var    string
165
	 * @since  11.1
166
	 */
167
	protected $pattern;
168
169
	/**
170
	 * The name of the form field.
171
	 *
172
	 * @var    string
173
	 * @since  11.1
174
	 */
175
	protected $name;
176
177
	/**
178
	 * The name of the field.
179
	 *
180
	 * @var    string
181
	 * @since  11.1
182
	 */
183
	protected $fieldname;
184
185
	/**
186
	 * The group of the field.
187
	 *
188
	 * @var    string
189
	 * @since  11.1
190
	 */
191
	protected $group;
192
193
	/**
194
	 * The required state for the form field.  If true then there must be a value for the field to
195
	 * be considered valid.
196
	 *
197
	 * @var    boolean
198
	 * @since  11.1
199
	 */
200
	protected $required = false;
201
202
	/**
203
	 * The disabled state for the form field.  If true then the field will be disabled and user can't
204
	 * interact with the field.
205
	 *
206
	 * @var    boolean
207
	 * @since  3.2
208
	 */
209
	protected $disabled = false;
210
211
	/**
212
	 * The readonly state for the form field.  If true then the field will be readonly.
213
	 *
214
	 * @var    boolean
215
	 * @since  3.2
216
	 */
217
	protected $readonly = false;
218
219
	/**
220
	 * The form field type.
221
	 *
222
	 * @var    string
223
	 * @since  11.1
224
	 */
225
	protected $type;
226
227
	/**
228
	 * The validation method for the form field.  This value will determine which method is used
229
	 * to validate the value for a field.
230
	 *
231
	 * @var    string
232
	 * @since  11.1
233
	 */
234
	protected $validate;
235
236
	/**
237
	 * The value of the form field.
238
	 *
239
	 * @var    mixed
240
	 * @since  11.1
241
	 */
242
	protected $value;
243
244
	/**
245
	 * The default value of the form field.
246
	 *
247
	 * @var    mixed
248
	 * @since  11.1
249
	 */
250
	protected $default;
251
252
	/**
253
	 * The size of the form field.
254
	 *
255
	 * @var    integer
256
	 * @since  3.2
257
	 */
258
	protected $size;
259
260
	/**
261
	 * The class of the form field
262
	 *
263
	 * @var    mixed
264
	 * @since  3.2
265
	 */
266
	protected $class;
267
268
	/**
269
	 * The label's CSS class of the form field
270
	 *
271
	 * @var    mixed
272
	 * @since  11.1
273
	 */
274
	protected $labelclass;
275
276
	/**
277
	 * The javascript onchange of the form field.
278
	 *
279
	 * @var    string
280
	 * @since  3.2
281
	 */
282
	protected $onchange;
283
284
	/**
285
	 * The javascript onclick of the form field.
286
	 *
287
	 * @var    string
288
	 * @since  3.2
289
	 */
290
	protected $onclick;
291
292
	/**
293
	 * The conditions to show/hide the field.
294
	 *
295
	 * @var    string
296
	 * @since  3.7.0
297
	 */
298
	protected $showon;
299
300
	/**
301
	 * The count value for generated name field
302
	 *
303
	 * @var    integer
304
	 * @since  11.1
305
	 */
306
	protected static $count = 0;
307
308
	/**
309
	 * The string used for generated fields names
310
	 *
311
	 * @var    string
312
	 * @since  11.1
313
	 */
314
	protected static $generated_fieldname = '__field';
315
316
	/**
317
	 * Name of the layout being used to render the field
318
	 *
319
	 * @var    string
320
	 * @since  3.5
321
	 */
322
	protected $layout;
323
324
	/**
325
	 * Layout to render the form field
326
	 *
327
	 * @var  string
328
	 */
329
	protected $renderLayout = 'joomla.form.renderfield';
330
331
	/**
332
	 * Layout to render the label
333
	 *
334
	 * @var  string
335
	 */
336
	protected $renderLabelLayout = 'joomla.form.renderlabel';
337
338
	/**
339
	 * Method to instantiate the form field object.
340
	 *
341
	 * @param   JForm  $form  The form to attach to the form field object.
342
	 *
343
	 * @since   11.1
344
	 */
345
	public function __construct($form = null)
346
	{
347
		// If there is a form passed into the constructor set the form and form control properties.
348
		if ($form instanceof JForm)
349
		{
350
			$this->form = $form;
351
			$this->formControl = $form->getFormControl();
352
		}
353
354
		// Detect the field type if not set
355
		if (!isset($this->type))
356
		{
357
			$parts = Normalise::fromCamelCase(get_called_class(), true);
358
359
			if ($parts[0] == 'J')
360
			{
361
				$this->type = StringHelper::ucfirst($parts[count($parts) - 1], '_');
0 ignored issues
show
Bug introduced by
$parts of type string is incompatible with the type Countable|array expected by parameter $var of count(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

361
				$this->type = StringHelper::ucfirst($parts[count(/** @scrutinizer ignore-type */ $parts) - 1], '_');
Loading history...
362
			}
363
			else
364
			{
365
				$this->type = StringHelper::ucfirst($parts[0], '_') . StringHelper::ucfirst($parts[count($parts) - 1], '_');
366
			}
367
		}
368
	}
369
370
	/**
371
	 * Method to get certain otherwise inaccessible properties from the form field object.
372
	 *
373
	 * @param   string  $name  The property name for which to the the value.
374
	 *
375
	 * @return  mixed  The property value or null.
376
	 *
377
	 * @since   11.1
378
	 */
379
	public function __get($name)
380
	{
381
		switch ($name)
382
		{
383
			case 'description':
384
			case 'hint':
385
			case 'formControl':
386
			case 'hidden':
387
			case 'id':
388
			case 'multiple':
389
			case 'name':
390
			case 'required':
391
			case 'type':
392
			case 'validate':
393
			case 'value':
394
			case 'class':
395
			case 'layout':
396
			case 'labelclass':
397
			case 'size':
398
			case 'onchange':
399
			case 'onclick':
400
			case 'fieldname':
401
			case 'group':
402
			case 'disabled':
403
			case 'readonly':
404
			case 'autofocus':
405
			case 'autocomplete':
406
			case 'spellcheck':
407
			case 'showon':
408
				return $this->$name;
409
410
			case 'input':
411
				// If the input hasn't yet been generated, generate it.
412
				if (empty($this->input))
413
				{
414
					$this->input = $this->getInput();
415
				}
416
417
				return $this->input;
418
419
			case 'label':
420
				// If the label hasn't yet been generated, generate it.
421
				if (empty($this->label))
422
				{
423
					$this->label = $this->getLabel();
424
				}
425
426
				return $this->label;
427
428
			case 'title':
429
				return $this->getTitle();
430
		}
431
432
		return;
433
	}
434
435
	/**
436
	 * Method to check if certain otherwise inaccessible properties from the form field object are accessible.
437
	 *
438
	 * @param   string  $name  The property name for which to set the value.
439
	 *
440
	 * @return  boolean
441
	 *
442
	 * @since   1.10.2
443
	 */
444
	public function __isset($name)
445
	{
446
		switch ($name)
447
		{
448
			case 'description':
449
			case 'hint':
450
			case 'formControl':
451
			case 'hidden':
452
			case 'id':
453
			case 'multiple':
454
			case 'name':
455
			case 'required':
456
			case 'type':
457
			case 'validate':
458
			case 'value':
459
			case 'class':
460
			case 'layout':
461
			case 'labelclass':
462
			case 'size':
463
			case 'onchange':
464
			case 'onclick':
465
			case 'fieldname':
466
			case 'group':
467
			case 'disabled':
468
			case 'readonly':
469
			case 'autofocus':
470
			case 'autocomplete':
471
			case 'spellcheck':
472
			case 'showon':
473
			case 'input':
474
			case 'label':
475
			case 'title':
476
				return true;
477
		}
478
479
		return false;
480
	}
481
482
	/**
483
	 * Method to set certain otherwise inaccessible properties of the form field object.
484
	 *
485
	 * @param   string  $name   The property name for which to the the value.
486
	 * @param   mixed   $value  The value of the property.
487
	 *
488
	 * @return  void
489
	 *
490
	 * @since   3.2
491
	 */
492
	public function __set($name, $value)
493
	{
494
		switch ($name)
495
		{
496
			case 'class':
497
				// Removes spaces from left & right and extra spaces from middle
498
				$value = preg_replace('/\s+/', ' ', trim((string) $value));
499
500
			case 'description':
501
			case 'hint':
502
			case 'value':
503
			case 'labelclass':
504
			case 'layout':
505
			case 'onchange':
506
			case 'onclick':
507
			case 'validate':
508
			case 'pattern':
509
			case 'group':
510
			case 'showon':
511
			case 'default':
512
				$this->$name = (string) $value;
513
				break;
514
515
			case 'id':
516
				$this->id = $this->getId((string) $value, $this->fieldname);
517
				break;
518
519
			case 'fieldname':
520
				$this->fieldname = $this->getFieldName((string) $value);
521
				break;
522
523
			case 'name':
524
				$this->fieldname = $this->getFieldName((string) $value);
525
				$this->name = $this->getName($this->fieldname);
526
				break;
527
528
			case 'multiple':
529
				// Allow for field classes to force the multiple values option.
530
				$value = (string) $value;
531
				$value = $value === '' && isset($this->forceMultiple) ? (string) $this->forceMultiple : $value;
0 ignored issues
show
Bug Best Practice introduced by
The property forceMultiple does not exist on JFormField. Since you implemented __get, consider adding a @property annotation.
Loading history...
532
533
			case 'required':
534
			case 'disabled':
535
			case 'readonly':
536
			case 'autofocus':
537
			case 'hidden':
538
				$value = (string) $value;
539
				$this->$name = ($value === 'true' || $value === $name || $value === '1');
540
				break;
541
542
			case 'autocomplete':
543
				$value = (string) $value;
544
				$value = ($value == 'on' || $value == '') ? 'on' : $value;
545
				$this->$name = ($value === 'false' || $value === 'off' || $value === '0') ? false : $value;
546
				break;
547
548
			case 'spellcheck':
549
			case 'translateLabel':
550
			case 'translateDescription':
551
			case 'translateHint':
552
				$value = (string) $value;
553
				$this->$name = !($value === 'false' || $value === 'off' || $value === '0');
554
				break;
555
556
			case 'translate_label':
557
				$value = (string) $value;
558
				$this->translateLabel = $this->translateLabel && !($value === 'false' || $value === 'off' || $value === '0');
559
				break;
560
561
			case 'translate_description':
562
				$value = (string) $value;
563
				$this->translateDescription = $this->translateDescription && !($value === 'false' || $value === 'off' || $value === '0');
564
				break;
565
566
			case 'size':
567
				$this->$name = (int) $value;
568
				break;
569
570
			default:
571
				if (property_exists(__CLASS__, $name))
572
				{
573
					JLog::add("Cannot access protected / private property $name of " . __CLASS__);
574
				}
575
				else
576
				{
577
					$this->$name = $value;
578
				}
579
		}
580
	}
581
582
	/**
583
	 * Method to attach a JForm object to the field.
584
	 *
585
	 * @param   JForm  $form  The JForm object to attach to the form field.
586
	 *
587
	 * @return  JFormField  The form field object so that the method can be used in a chain.
588
	 *
589
	 * @since   11.1
590
	 */
591
	public function setForm(JForm $form)
592
	{
593
		$this->form = $form;
594
		$this->formControl = $form->getFormControl();
595
596
		return $this;
597
	}
598
599
	/**
600
	 * Method to attach a JForm object to the field.
601
	 *
602
	 * @param   SimpleXMLElement  $element  The SimpleXMLElement object representing the `<field>` tag for the form field object.
603
	 * @param   mixed             $value    The form field value to validate.
604
	 * @param   string            $group    The field name group control value. This acts as as an array container for the field.
605
	 *                                      For example if the field has name="foo" and the group value is set to "bar" then the
606
	 *                                      full field name would end up being "bar[foo]".
607
	 *
608
	 * @return  boolean  True on success.
609
	 *
610
	 * @since   11.1
611
	 */
612
	public function setup(SimpleXMLElement $element, $value, $group = null)
613
	{
614
		// Make sure there is a valid JFormField XML element.
615
		if ((string) $element->getName() != 'field')
616
		{
617
			return false;
618
		}
619
620
		// Reset the input and label values.
621
		$this->input = null;
622
		$this->label = null;
623
624
		// Set the XML element object.
625
		$this->element = $element;
626
627
		// Set the group of the field.
628
		$this->group = $group;
629
630
		$attributes = array(
631
			'multiple', 'name', 'id', 'hint', 'class', 'description', 'labelclass', 'onchange', 'onclick', 'validate', 'pattern', 'default',
632
			'required', 'disabled', 'readonly', 'autofocus', 'hidden', 'autocomplete', 'spellcheck', 'translateHint', 'translateLabel',
633
			'translate_label', 'translateDescription', 'translate_description', 'size', 'showon');
634
635
		$this->default = isset($element['value']) ? (string) $element['value'] : $this->default;
636
637
		// Set the field default value.
638
		$this->value = $value;
639
640
		foreach ($attributes as $attributeName)
641
		{
642
			$this->__set($attributeName, $element[$attributeName]);
643
		}
644
645
		// Allow for repeatable elements
646
		$repeat = (string) $element['repeat'];
647
		$this->repeat = ($repeat == 'true' || $repeat == 'multiple' || (!empty($this->form->repeat) && $this->form->repeat == 1));
648
649
		// Set the visibility.
650
		$this->hidden = ($this->hidden || (string) $element['type'] == 'hidden');
651
652
		$this->layout = !empty($this->element['layout']) ? (string) $this->element['layout'] : $this->layout;
653
654
		// Add required to class list if field is required.
655
		if ($this->required)
656
		{
657
			$this->class = trim($this->class . ' required');
658
659
			if (version_compare(JVERSION, '3.0', 'lt'))
660
			{
661
				$elementClass = (string) $element['class'];
662
663
				if ($elementClass)
664
				{
665
					if (strpos($elementClass, 'required') === false)
666
					{
667
						$this->element['class'] = $elementClass . ' required';
668
					}
669
				}
670
				else
671
				{
672
					$this->element->addAttribute('class', 'required');
673
				}
674
			}
675
		}
676
677
		return true;
678
	}
679
680
	/**
681
	 * Simple method to set the value
682
	 *
683
	 * @param   mixed  $value  Value to set
684
	 *
685
	 * @return  void
686
	 *
687
	 * @since   3.2
688
	 */
689
	public function setValue($value)
690
	{
691
		$this->value = $value;
692
	}
693
694
	/**
695
	 * Method to get the id used for the field input tag.
696
	 *
697
	 * @param   string  $fieldId    The field element id.
698
	 * @param   string  $fieldName  The field element name.
699
	 *
700
	 * @return  string  The id to be used for the field input tag.
701
	 *
702
	 * @since   11.1
703
	 */
704
	protected function getId($fieldId, $fieldName)
705
	{
706
		$id = '';
707
708
		// If there is a form control set for the attached form add it first.
709
		if ($this->formControl)
710
		{
711
			$id .= $this->formControl;
712
		}
713
714
		// If the field is in a group add the group control to the field id.
715
		if ($this->group)
716
		{
717
			// If we already have an id segment add the group control as another level.
718
			if ($id)
719
			{
720
				$id .= '_' . str_replace('.', '_', $this->group);
721
			}
722
			else
723
			{
724
				$id .= str_replace('.', '_', $this->group);
725
			}
726
		}
727
728
		// If we already have an id segment add the field id/name as another level.
729
		if ($id)
730
		{
731
			$id .= '_' . ($fieldId ? $fieldId : $fieldName);
732
		}
733
		else
734
		{
735
			$id .= ($fieldId ? $fieldId : $fieldName);
736
		}
737
738
		// Clean up any invalid characters.
739
		$id = preg_replace('#\W#', '_', $id);
740
741
		// If this is a repeatable element, add the repeat count to the ID
742
		if ($this->repeat)
743
		{
744
			$repeatCounter = empty($this->form->repeatCounter) ? 0 : $this->form->repeatCounter;
0 ignored issues
show
Bug introduced by
The property repeatCounter does not exist on JForm. Did you mean repeat?
Loading history...
745
			$id .= '-' . $repeatCounter;
746
747
			if (strtolower($this->type) == 'radio')
748
			{
749
				$id .= '-';
750
			}
751
		}
752
753
		return $id;
754
	}
755
756
	/**
757
	 * Method to get the field input markup.
758
	 *
759
	 * @return  string  The field input markup.
760
	 *
761
	 * @since   11.1
762
	 */
763
	protected function getInput()
764
	{
765
		if (empty($this->layout))
766
		{
767
			throw new UnexpectedValueException(sprintf('%s has no layout assigned.', $this->name));
768
		}
769
770
		return $this->getRenderer($this->layout)->render($this->getLayoutData());
771
	}
772
773
	/**
774
	 * Method to get the field title.
775
	 *
776
	 * @return  string  The field title.
777
	 *
778
	 * @since   11.1
779
	 */
780
	protected function getTitle()
781
	{
782
		$title = '';
783
784
		if ($this->hidden)
785
		{
786
			return $title;
787
		}
788
789
		// Get the label text from the XML element, defaulting to the element name.
790
		$title = $this->element['label'] ? (string) $this->element['label'] : (string) $this->element['name'];
791
		$title = $this->translateLabel ? JText::_($title) : $title;
792
793
		return $title;
794
	}
795
796
	/**
797
	 * Method to get the field label markup.
798
	 *
799
	 * @return  string  The field label markup.
800
	 *
801
	 * @since   11.1
802
	 */
803
	protected function getLabel()
804
	{
805
		if ($this->hidden)
806
		{
807
			return '';
808
		}
809
810
		$data = $this->getLayoutData();
811
812
		// Forcing the Alias field to display the tip below
813
		$position = $this->element['name'] == 'alias' ? ' data-placement="bottom" ' : '';
0 ignored issues
show
introduced by
The condition $this->element['name'] == 'alias' is always false.
Loading history...
814
815
		// Here mainly for B/C with old layouts. This can be done in the layouts directly
816
		$extraData = array(
817
			'text'        => $data['label'],
818
			'for'         => $this->id,
819
			'classes'     => explode(' ', $data['labelclass']),
820
			'position'    => $position,
821
		);
822
823
		return $this->getRenderer($this->renderLabelLayout)->render(array_merge($data, $extraData));
824
	}
825
826
	/**
827
	 * Method to get the name used for the field input tag.
828
	 *
829
	 * @param   string  $fieldName  The field element name.
830
	 *
831
	 * @return  string  The name to be used for the field input tag.
832
	 *
833
	 * @since   11.1
834
	 */
835
	protected function getName($fieldName)
836
	{
837
		// To support repeated element, extensions can set this in plugin->onRenderSettings
838
839
		$name = '';
840
841
		// If there is a form control set for the attached form add it first.
842
		if ($this->formControl)
843
		{
844
			$name .= $this->formControl;
845
		}
846
847
		// If the field is in a group add the group control to the field name.
848
		if ($this->group)
849
		{
850
			// If we already have a name segment add the group control as another level.
851
			$groups = explode('.', $this->group);
852
853
			if ($name)
854
			{
855
				foreach ($groups as $group)
856
				{
857
					$name .= '[' . $group . ']';
858
				}
859
			}
860
			else
861
			{
862
				$name .= array_shift($groups);
863
864
				foreach ($groups as $group)
865
				{
866
					$name .= '[' . $group . ']';
867
				}
868
			}
869
		}
870
871
		// If we already have a name segment add the field name as another level.
872
		if ($name)
873
		{
874
			$name .= '[' . $fieldName . ']';
875
		}
876
		else
877
		{
878
			$name .= $fieldName;
879
		}
880
881
		// If the field should support multiple values add the final array segment.
882
		if ($this->multiple)
883
		{
884
			switch (strtolower((string) $this->element['type']))
885
			{
886
				case 'text':
887
				case 'textarea':
888
				case 'email':
889
				case 'password':
890
				case 'radio':
891
				case 'calendar':
892
				case 'editor':
893
				case 'hidden':
894
					break;
895
				default:
896
					$name .= '[]';
897
			}
898
		}
899
900
		return $name;
901
	}
902
903
	/**
904
	 * Method to get the field name used.
905
	 *
906
	 * @param   string  $fieldName  The field element name.
907
	 *
908
	 * @return  string  The field name
909
	 *
910
	 * @since   11.1
911
	 */
912
	protected function getFieldName($fieldName)
913
	{
914
		if ($fieldName)
915
		{
916
			return $fieldName;
917
		}
918
		else
919
		{
920
			self::$count = self::$count + 1;
921
922
			return self::$generated_fieldname . self::$count;
923
		}
924
	}
925
926
	/**
927
	 * Method to get an attribute of the field
928
	 *
929
	 * @param   string  $name     Name of the attribute to get
930
	 * @param   mixed   $default  Optional value to return if attribute not found
931
	 *
932
	 * @return  mixed             Value of the attribute / default
933
	 *
934
	 * @since   3.2
935
	 */
936
	public function getAttribute($name, $default = null)
937
	{
938
		if ($this->element instanceof SimpleXMLElement)
0 ignored issues
show
introduced by
$this->element is always a sub-type of SimpleXMLElement.
Loading history...
939
		{
940
			$attributes = $this->element->attributes();
941
942
			// Ensure that the attribute exists
943
			if (property_exists($attributes, $name))
944
			{
945
				$value = $attributes->$name;
946
947
				if ($value !== null)
948
				{
949
					return (string) $value;
950
				}
951
			}
952
		}
953
954
		return $default;
955
	}
956
957
	/**
958
	 * Method to get a control group with label and input.
959
	 *
960
	 * @return  string  A string containing the html for the control group
961
	 *
962
	 * @since      3.2
963
	 * @deprecated 3.2.3 Use renderField() instead
964
	 */
965
	public function getControlGroup()
966
	{
967
		JLog::add('JFormField->getControlGroup() is deprecated use JFormField->renderField().', JLog::WARNING, 'deprecated');
968
969
		return $this->renderField();
970
	}
971
972
	/**
973
	 * Render a layout of this field
974
	 *
975
	 * @param   string  $layoutId  Layout identifier
976
	 * @param   array   $data      Optional data for the layout
977
	 *
978
	 * @return  string
979
	 *
980
	 * @since   3.5
981
	 */
982
	public function render($layoutId, $data = array())
983
	{
984
		$data = array_merge($this->getLayoutData(), $data);
985
986
		return $this->getRenderer($layoutId)->render($data);
987
	}
988
989
	/**
990
	 * Method to get a control group with label and input.
991
	 *
992
	 * @param   array  $options  Options to be passed into the rendering of the field
993
	 *
994
	 * @return  string  A string containing the html for the control group
995
	 *
996
	 * @since   3.2
997
	 */
998
	public function renderField($options = array())
999
	{
1000
		if ($this->hidden)
1001
		{
1002
			return $this->getInput();
1003
		}
1004
1005
		if (!isset($options['class']))
1006
		{
1007
			$options['class'] = '';
1008
		}
1009
1010
		$options['rel'] = '';
1011
1012
		if (empty($options['hiddenLabel']) && $this->getAttribute('hiddenLabel'))
1013
		{
1014
			$options['hiddenLabel'] = true;
1015
		}
1016
1017
		if ($this->showon)
1018
		{
1019
			$options['rel']           = ' data-showon=\'' .
1020
				json_encode(RJoomlaLegacy::parseShowOnConditions($this->showon, $this->formControl, $this->group)) . '\'';
1021
			$options['showonEnabled'] = true;
1022
		}
1023
1024
		$data = array(
1025
			'input'   => $this->getInput(),
1026
			'label'   => $this->getLabel(),
1027
			'options' => $options,
1028
		);
1029
1030
		return $this->getRenderer($this->renderLayout)->render($data);
1031
	}
1032
1033
	/**
1034
	 * Method to get the data to be passed to the layout for rendering.
1035
	 *
1036
	 * @return  array
1037
	 *
1038
	 * @since 3.5
1039
	 */
1040
	protected function getLayoutData()
1041
	{
1042
		// Label preprocess
1043
		$label = $this->element['label'] ? (string) $this->element['label'] : (string) $this->element['name'];
1044
		$label = $this->translateLabel ? JText::_($label) : $label;
1045
1046
		// Description preprocess
1047
		$description = !empty($this->description) ? $this->description : null;
1048
		$description = !empty($description) && $this->translateDescription ? JText::_($description) : $description;
1049
1050
		$alt = preg_replace('/[^a-zA-Z0-9_\-]/', '_', $this->fieldname);
1051
1052
		return array(
1053
			'autocomplete' => $this->autocomplete,
1054
			'autofocus'    => $this->autofocus,
1055
			'class'        => $this->class,
1056
			'description'  => $description,
1057
			'disabled'     => $this->disabled,
1058
			'field'        => $this,
1059
			'group'        => $this->group,
1060
			'hidden'       => $this->hidden,
1061
			'hint'         => $this->translateHint ? JText::alt($this->hint, $alt) : $this->hint,
1062
			'id'           => $this->id,
1063
			'label'        => $label,
1064
			'labelclass'   => $this->labelclass,
1065
			'multiple'     => $this->multiple,
1066
			'name'         => $this->name,
1067
			'onchange'     => $this->onchange,
1068
			'onclick'      => $this->onclick,
1069
			'pattern'      => $this->pattern,
1070
			'readonly'     => $this->readonly,
1071
			'repeat'       => $this->repeat,
1072
			'required'     => (bool) $this->required,
1073
			'size'         => $this->size,
1074
			'spellcheck'   => $this->spellcheck,
1075
			'validate'     => $this->validate,
1076
			'value'        => $this->value,
1077
		);
1078
	}
1079
1080
	/**
1081
	 * Allow to override renderer include paths in child fields
1082
	 *
1083
	 * @return  array
1084
	 *
1085
	 * @since   3.5
1086
	 */
1087
	protected function getLayoutPaths()
1088
	{
1089
		return array();
1090
	}
1091
1092
	/**
1093
	 * Get the renderer
1094
	 *
1095
	 * @param   string  $layoutId  Id to load
1096
	 *
1097
	 * @return  JLayout
1098
	 *
1099
	 * @since   3.5
1100
	 */
1101
	protected function getRenderer($layoutId = 'default')
1102
	{
1103
		$renderer = new JLayoutFile($layoutId);
1104
1105
		$renderer->setDebug($this->isDebugEnabled());
1106
1107
		$layoutPaths = $this->getLayoutPaths();
1108
1109
		if ($layoutPaths)
0 ignored issues
show
Bug Best Practice introduced by
The expression $layoutPaths of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
introduced by
$layoutPaths is an empty array, thus is always false.
Loading history...
1110
		{
1111
			$renderer->setIncludePaths($layoutPaths);
1112
		}
1113
1114
		return $renderer;
1115
	}
1116
1117
	/**
1118
	 * Is debug enabled for this field
1119
	 *
1120
	 * @return  boolean
1121
	 *
1122
	 * @since   3.5
1123
	 */
1124
	protected function isDebugEnabled()
1125
	{
1126
		return $this->getAttribute('debug', 'false') === 'true';
1127
	}
1128
1129
	/**
1130
	 * Transforms the field into an XML element and appends it as child on the given parent. This
1131
	 * is the default implementation of a field. Form fields which do support to be transformed into
1132
	 * an XML Element mut implemet the JFormDomfieldinterface.
1133
	 *
1134
	 * @param   stdClass    $field   The field.
1135
	 * @param   DOMElement  $parent  The field node parent.
1136
	 * @param   JForm       $form    The form.
1137
	 *
1138
	 * @return  DOMElement
1139
	 *
1140
	 * @since   3.7.0
1141
	 * @see     JFormDomfieldinterface::appendXMLFieldTag
1142
	 */
1143
	public function appendXMLFieldTag($field, DOMElement $parent, JForm $form)
1144
	{
1145
		$app = JFactory::getApplication();
1146
1147
		if ($field->params->get('show_on') == 1 && (version_compare(JVERSION, '3.7', '<') ? $app->isAdmin() : $app->isClient('administrator')))
0 ignored issues
show
Deprecated Code introduced by
The function JApplicationCms::isAdmin() has been deprecated: Use isClient('administrator') instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1147
		if ($field->params->get('show_on') == 1 && (version_compare(JVERSION, '3.7', '<') ? /** @scrutinizer ignore-deprecated */ $app->isAdmin() : $app->isClient('administrator')))

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1148
		{
1149
			return;
1150
		}
1151
		elseif ($field->params->get('show_on') == 2
1152
			&& (version_compare(JVERSION, '3.7', '<') ? $app->isSite() : $app->isClient('site')))
0 ignored issues
show
Deprecated Code introduced by
The function JApplicationCms::isSite() has been deprecated: Use isClient('site') instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1152
			&& (version_compare(JVERSION, '3.7', '<') ? /** @scrutinizer ignore-deprecated */ $app->isSite() : $app->isClient('site')))

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1153
		{
1154
			return;
1155
		}
1156
1157
		$node = $parent->appendChild(new DOMElement('field'));
0 ignored issues
show
Bug introduced by
The call to DOMElement::__construct() has too few arguments starting with value. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1157
		$node = $parent->appendChild(/** @scrutinizer ignore-call */ new DOMElement('field'));

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
1158
1159
		$node->setAttribute('name', $field->alias);
1160
		$node->setAttribute('type', $field->type);
1161
		$node->setAttribute('default', $field->default_value);
1162
		$node->setAttribute('label', $field->label);
1163
		$node->setAttribute('description', $field->description);
1164
		$node->setAttribute('class', $field->params->get('class'));
1165
		$node->setAttribute('hint', $field->params->get('hint'));
1166
		$node->setAttribute('required', $field->required ? 'true' : 'false');
1167
		$node->setAttribute('readonly', $field->params->get('readonly', 0) ? 'true' : 'false');
1168
1169
		// Set the disabled state based on the parameter and the permission
1170
		if ($field->params->get('disabled', 0))
1171
		{
1172
			$node->setAttribute('disabled', 'true');
1173
		}
1174
1175
		foreach ($field->fieldparams->toArray() as $key => $param)
1176
		{
1177
			if (is_array($param))
1178
			{
1179
				// Multidimensional arrays (eg. list options) can't be transformed properly
1180
				$param = count($param) == count($param, COUNT_RECURSIVE) ? implode(',', $param) : '';
1181
			}
1182
1183
			if (!$param)
1184
			{
1185
				continue;
1186
			}
1187
1188
			$node->setAttribute($key, $param);
1189
		}
1190
1191
		$this->postProcessDomNode($field, $node, $form);
1192
1193
		return $node;
1194
	}
1195
1196
	/**
1197
	 * Function to manipulate the DOM element of the field. The form can be
1198
	 * manipulated at that point.
1199
	 *
1200
	 * @param   stdClass    $field      The field.
1201
	 * @param   DOMElement  $fieldNode  The field node.
1202
	 * @param   JForm       $form       The form.
1203
	 *
1204
	 * @return  void
1205
	 *
1206
	 * @since   3.7.0
1207
	 */
1208
	protected function postProcessDomNode($field, DOMElement $fieldNode, JForm $form)
0 ignored issues
show
Unused Code introduced by
The parameter $form is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1208
	protected function postProcessDomNode($field, DOMElement $fieldNode, /** @scrutinizer ignore-unused */ JForm $form)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $field is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1208
	protected function postProcessDomNode(/** @scrutinizer ignore-unused */ $field, DOMElement $fieldNode, JForm $form)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $fieldNode is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1208
	protected function postProcessDomNode($field, /** @scrutinizer ignore-unused */ DOMElement $fieldNode, JForm $form)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1209
	{
1210
	}
1211
1212
	/**
1213
	 * Returns the attributes of the field as an XML string which can be loaded
1214
	 * into JForm.
1215
	 *
1216
	 * @return  string
1217
	 *
1218
	 * @since   3.7.0
1219
	 */
1220
	public function getFormParameters()
1221
	{
1222
		JLoader::import('joomla.filesystem.file');
1223
1224
		$reflectionClass = new ReflectionClass($this);
1225
		$fileName        = dirname($reflectionClass->getFileName()) . '/../parameters/';
1226
		$fileName       .= str_replace('.php', '.xml', basename($reflectionClass->getFileName()));
1227
1228
		if (JFile::exists($fileName))
1229
		{
1230
			return file_get_contents($fileName);
1231
		}
1232
1233
		return '';
1234
	}
1235
}
1236