ar_html_form::getHTML()   B
last analyzed

Complexity

Conditions 10
Paths 128

Size

Total Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 0
Metric Value
cc 10
nc 128
nop 0
dl 0
loc 33
rs 7.4333
c 0
b 0
f 0
ccs 0
cts 32
cp 0
crap 110

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
	ar_pinp::allow('ar_html_form', array(
4
		'configure', 'addField', 'addButton', 'setValue', 'getValue', 'getValues', 'getHTML', 'isValid', 'isSubmitted', 'validate', 'registerInputType', 'registerValidateCheck', 'findField'
5
	) );
6
7
	class ar_html_form extends arBase {
8
		// todo: file upload field, captcha
9
		static public $customTypes;
10
		static public $requiredTitle = 'Required';
11
12
		static public $checks = array(
13
			'alpha'        => '/^[[:alpha:]]+$/iD',
14
			'alphanumeric' => '/^[[:alnum:]]+$/iD',
15
			'abs_int'      => '/^\d+$/iD',
16
			'int'          => '/^[+-]?\d+$/iD',
17
			'abs_number'   => '/^([0-9]+\.?[0-9]*|\.[0-9]+)$/D',
18
			'number'       => '/^[+-]?([0-9]+\.?[0-9]*|\.[0-9]+)$/D',
19
			'abs_money_us' => '/^(\d{1,3}(\,\d{3})*|(\d+))(\.\d{2})?$/D',
20
			'money_us'     => '/^[+-]?(\d{1,3}(\,\d{3})*|(\d+))(\.\d{2})?$/D',
21
			'abs_money'    => '/^(\d{1,3}(\.\d{3})*|(\d+))(\,\d{2})?$/D',
22
			'money'        => '/^[+-]?(\d{1,3}(\.\d{3})*|(\d+))(\,\d{2})?$/D',
23
			'email'        => '/^[\w!#$%&\'*+\/=?^`{|}~.-]+@(?:[a-z\d][a-z\d-]*(?:\.[a-z\d][a-z\d-]*)?)+\.(?:[a-z][a-z\d-]+)$/iD',
24
			'domain_name'  => '/^([[:alnum:]]([a-zA-Z0-9\-]{0,61}[[:alnum:]])?\.)+[[:alpha:]]{2,}$/D',
25
			'url'          => '/^(http|https|ftp)\:\/\/[a-zA-Z0-9\-\.]+\.[[:alpha:]]{2,3}(:[[:alnum:]]*)?\/?([a-zA-Z0-9\-\._\?\,\'\/\\\+&amp;%\$#\=~])*$/D',
26
			'credit_card'  => '/^(\d{4}-){3}\d{4}$|^(\d{4} ){3}\d{4}$|^\d{16}$/D',
27
			'date'         => '/^(\d{1,2}[.-/]\d{1,2}[.-/](\d{2}|\d{4})$/D',
28
			'time'         => '/^(\d{1,2}[:]\d{2}([:]\d{2})?$/D'
29
		);
30
31
		protected $fields = array();
32
		protected $buttons = array();
33
34
		public    $action, $method, $name, $class, $id, $requiredLabel, $encType;
35
36
		public function __construct($fields=null, $buttons=null, $action='', $method="POST", $requiredLabel=null) {
37
			if ( isset($fields) ) {
38
				$this->fields = $this->parseFields($fields);
39
			}
40
			if (ar('loaderSession')->getvar("formSecret")) {
41
				$this->fields = array_merge($this->fields, $this->parseFields(
42
					array('formSecret' => array(
43
						'type' => 'hidden',
44
						'name' => 'formSecret',
45
						'value' => ar('loaderSession')->getvar("formSecret"),
46
						'checks' => '/^'.ar('loaderSession')->getvar("formSecret").'$/D'
47
					))
48
				));
49
			}
50
51
			if ( !isset($buttons)) {
52
				$buttons = array('Ok');
53
			}
54
			$this->buttons	= $this->parseButtons($buttons);
55
			$this->action	= $action;
56
			$this->method	= $method;
57
			$this->requiredLabel = isset($requiredLabel) ? $requiredLabel :
58
				ar_html::el('span', array('title' => self::$requiredTitle, 'class' => 'formRequired'), '*');
59
		}
60
61
		public function configure( $name, $value ) {
62
			switch ( $name ) {
63
				case 'requiredTitle' :
64
					self::$requiredTitle = $value;
65
				break;
66
			}
67
			return $this;
68
		}
69
70
		public function addField($value) {
71
			$this->fields[] = $this->parseField(0, $value);
72
		}
73
74
		public function addButton($value) {
75
			$this->buttons[] = $this->parseButton(0, $value);
76
		}
77
78
		public function setValue($name, $value) {
79
			$field = $this->findField($name);
80
			if ($field) {
81
				return $field->setValue($value);
82
			} else {
83
				return false; // FIXME exceptions gebruiken?
84
			}
85
		}
86
87
		public function getHTML() {
88
			$attributes = array();
89
90
			if (isset($this->name)) {
91
				$attributes['id'] = $this->name;
92
			}
93
			if (isset($this->class)) {
94
				$attributes['class'] = $this->class;
95
			}
96
			if (isset($this->action)) {
97
				$attributes['action'] = $this->action;
98
			}
99
			if (isset($this->method)) {
100
				$attributes['method'] = $this->method;
101
			}
102
			if (isset($this->encType) ) {
103
				$attributes['enctype'] = $this->encType;
104
			}
105
			$content = ar_html::nodes();
106
			if (is_array($this->fields)) {
107
				foreach ($this->fields as $key => $field) {
108
					$content[] = $field->getField();
109
				}
110
			}
111
			if ($this->buttons) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->buttons 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...
112
				$buttonContent = ar_html::nodes();
113
				foreach ($this->buttons as $key => $button) {
114
					$buttonContent[] = $button->getButton();
115
				}
116
				$content[] = ar_html::el('div', $buttonContent, array('class' => 'formButtons'));
117
			}
118
			return ar_html::el('form', $content, $attributes);
119
		}
120
121
		public function __toString() {
122
			return (string) $this->getHTML();
123
		}
124
125
		public function getValue($name) {
126
			$field = $this->findField($name);
127
			if ($field) {
128
				return $field->getValue();
129
			} else {
130
				return null;
131
			}
132
		}
133
134
		public function getValues() {
135
			$values = array();
136
			foreach ($this->fields as $key => $field) {
137
				$result = $field->getNameValue();
138
				$values = array_replace_recursive($values, $result);
139
			}
140
			return $values;
141
		}
142
143
		public function findField($searchName) {
144
			foreach ($this->fields as $key => $field) {
145
				$name = $field->name;
146
				if (!$name) {
147
					$name = $key;
148
				}
149
				if ($searchName === $name) {
150
					return $field;
151
				} else if ($field->hasChildren) {
152
					$result = $field->findField($searchName);
153
					if ($result) {
154
						return $result;
155
					}
156
				}
157
			}
158
			return false;
159
		}
160
161
		public function parseField($key, $field) {
162
			if (is_array($field)) {
163
				$type	= isset($field['type']) ? $field['type'] : null;
164
				$name	= isset($field['name']) ? $field['name'] : null;
165
				$label	= isset($field['label']) ? $field['label'] : null;
166
			} else {
167
				$type   = null;
168
				$name   = null;
169
				$label	= $field;
170
			}
171
			if (!$type) {
172
				$type	= 'text';
173
			}
174
			if (!$name) {
175
				if (!is_numeric($key)) {
176
					$name = $key;
177
				} else {
178
					$name = $label;
179
				}
180
			}
181
			if ( !$label && $label!==false ) { // false means 'don't add a lable'
182
				$label	= $name;
183
			}
184
			if (!is_array($field)) {
185
				$field	= array();
186
			}
187
			$field = $this->getField( new arObject( array_merge( $field, array(
188
				'type'	=> $type,
189
				'name'	=> $name,
190
				'label'	=> $label
191
			) ) ) );
192
			return $field;
193
		}
194
195
		public function parseFields($fields) {
196
			$newFields = array();
197
			if (is_array($fields)) {
198
				foreach ($fields as $key => $field) {
199
					$newFields[$key] = $this->parseField($key, $field);
200
				}
201
			}
202
			return $newFields;
203
		}
204
205
		protected function parseButton($key, $button) {
206
			if (is_array($button)) {
207
				$type	= isset($button['type']) ? $button['type'] : null;
208
				$name	= isset($button['name']) ? $button['name'] : null;
209
				$value	= isset($button['value']) ? $button['value'] : null;
210
			} else {
211
				$value	= $button;
212
				$button	= array();
213
			}
214
			if (!isset($type)) {
215
				$type	= 'submit';
216
			}
217
			if (!isset($name)) {
218
				if (!is_numeric($key)) {
219
					$name = $key;
220
				} else {
221
					$name = 'button_'.$key;
222
				}
223
			}
224
			if (!isset($value)) {
225
				$value	= $name;
226
			}
227
			$button = $this->getButton( new arObject( array_merge( $button, array(
228
				'type'	=> $type,
229
				'name'	=> $name,
230
				'value'	=> $value
231
			) ) ) );
232
			return $button;
233
		}
234
235
		protected function parseButtons($buttons) {
236
			if (is_array($buttons)) {
237
				$newButtons = array();
238
				foreach ($buttons as $key => $button) {
239
					$newButtons[$key] = $this->parseButton($key, $button);
240
				}
241
			}
242
			return $newButtons;
0 ignored issues
show
Bug introduced by
The variable $newButtons does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
243
		}
244
245
		protected function getButton($button) {
246
			$class = 'ar_html_formButton'.ucfirst($button->type);
247
			if (class_exists($class)) {
248
				return new $class($button, $this);
249
			} else {
250
				return new ar_html_formButton($button, $this);
251
			}
252
		}
253
254
		protected function getField($field) {
255
			$class	= 'ar_html_formInput'.ucfirst($field->type);
256
			if (class_exists($class)) {
257
				return new $class($field, $this);
258
			} else {
259
				return new ar_html_formInputMissing($field, $this);
260
			}
261
		}
262
263
		public function validate( $inputs = null ) {
264
			$valid = array();
265
			foreach ( $this->fields as $key => $field ) {
266
				$result = $field->validate( $inputs );
267
				$valid  = array_merge( $valid, $result );
268
			}
269
			return $valid;
270
		}
271
272
		public function isValid() {
273
			$valid = $this->validate();
274
			return count( $valid ) == 0;
275
		}
276
277
		public function isSubmitted( $name = null ) {
278
			// check if any of the submit buttons is available, if no submit buttons are set, check if any of the input values are
279
			if ( isset($name) ) {
280
				$value = ar('http')->getvar($name);
281
				return isset( $value );
282
			} else {
283
				if ( is_array( $this->buttons ) ) {
284
					foreach ( $this->buttons as $button ) {
285
						if ( $button->type=='submit' || $button->type=='image' ) {
286
							if ( ar('http')->getvar($button->name) == $button->value ) {
287
								return true;
288
							}
289
						}
290
					}
291
				}
292
				foreach ( $this->fields as $field ) {
293
					if ( ar('http')->getvar($field->name) !== null ) {
294
						return true;
295
					}
296
				}
297
			}
298
			return false;
299
		}
300
301
		public static function registerInputType( $type, $getInput, $getValue = null, $getLabel = null, $getField = null ) {
302
			self::$customTypes[ $type ] = array(
303
				'getInput' => $getInput,
304
				'getValue' => $getValue,
305
				'getLabel' => $getLabel,
306
				'getField' => $getField
307
			);
308
			foreach( self::$customTypes[ $type ] as $name => $method ) {
309
				if ( isset( $method ) && $method ) {
310
					if ( !is_callable($method) ) {
311
						if ( is_string($method) ) {
312
							$method = ar_pinp::getCallback($method, array('field') );
313
						} else {
314
							$method = null;
315
						}
316
					}
317
				} else {
318
					$method = null;
319
				}
320
				self::$customTypes[ $type ][ $name ] = $method;
321
			}
322
		}
323
324
		public static function registerValidateCheck( $name, $check, $message ) {
325
			if ( !is_string( $check ) || ( $check[0] != '/' && !is_callable( $check ) ) ) {
326
				$check = ar_pinp::getCallback( $check, array( 'value' ) );
327
			}
328
			self::$checks[ $name ] = array(
329
				'check' => $check,
330
				'message' => $message,
331
			);
332
		}
333
334 View Code Duplication
		public function __set($name, $value) {
335
			if ($name[0] == '_') {
336
				$name = substr($name, 1);
337
			}
338
			if ( in_array( $name, array('action', 'method', 'name', 'class', 'id', 'requiredLabel' ) ) ) {
339
				$this->{$name} = $value;
340
			}
341
		}
342
343 View Code Duplication
		public function __get($name) {
344
			if ($name[0] == '_') {
345
				$name = substr($name, 1);
346
			}
347
			if ( in_array( $name, array('action', 'method', 'name', 'class', 'id', 'requiredLabel') ) ) {
348
				return $this->{$name};
349
			}
350
		}
351
	}
352
353
	class ar_html_formButton {
354
355
		protected $form;
356
		public $type, $name, $value, $class, $id, $title;
357
358
		public function __construct($button, $form) {
359
			$this->form   = $form;
360
			$this->type   = isset($button->type) ? $button->type : null;
361
			$this->name   = isset($button->name) ? $button->name : null;
362
			$this->value  = isset($button->value) ? $button->value : null;
363
			$this->class  = isset($button->class) ? $button->class : null;
364
			$this->id     = isset($button->id) ? $button->id : null;
365
			$this->title  = isset($button->title) ? $button->title : null;
366
		}
367
368
		public function getButton($type=null, $name=null, $value=null, $class=null, $id=null, $title=null, $extra=null) {
369
			if (!isset($type)) {
370
				$type = $this->type;
371
			}
372
			if (!isset($name)) {
373
				$name = $this->name;
374
			}
375
			if (!isset($value)) {
376
				$value = $this->value;
377
			}
378
			if (!isset($class)) {
379
				$class = $this->class;
380
			}
381
			if (!isset($id)) {
382
				$id = $this->id;
383
			}
384
			if (!isset($title)) {
385
				$title = $this->title;
386
			}
387
			$attributes = array(
388
				'type'  => $type,
389
				'name'  => $name,
390
				'value' => $value
391
			);
392
			if (isset($class)) {
393
				$attributes['class'] = $class;
394
			}
395
			if (isset($title)) {
396
				$attributes['title'] = $title;
397
			}
398
			if (isset($id)) {
399
				$attributes['id'] = $id;
400
			}
401
			if ($extra) {
402
				$attributes = array_merge($attributes, $extra);
403
			}
404
			return ar_html::el('input', $attributes);
405
		}
406
407
		public function __toString() {
408
			return (string) $this->getButton();
409
		}
410
	}
411
412
	class ar_html_formButtonImage extends ar_html_formButton {
413
		public $src, $alt;
414
415
		public function __construct($button, $form) {
416
			parent::__construct($button, $form);
417
			$this->src = isset($button->src) ? $button->src : null;
418
			$this->alt = isset($button->alt) ? $button->alt : null;
419
		}
420
421
		public function getButton($type=null, $name=null, $value=null, $class=null, $id=null, $title=null, $src=null, $alt=null, $extra=null) {
422
			if (!isset($src)) {
423
				$src = $this->src;
424
			}
425
			if (!isset($alt)) {
426
				$alt = $this->alt;
427
			}
428
			return parent::getButton($type, $name, $value, $class, $id, $title, array_merge($extra, array('src' => $src, 'alt' => $alt )));
429
		}
430
	}
431
432
	class ar_html_formInput {
433
434
		protected $form;
435
		public    $type, $name, $class, $id, $label, $disabled, $default, $required, $conditional, $checks, $value, $title, $help;
436
437
		public function __construct($field, $form) {
438
			$this->form		= $form;
439
			$this->type		= isset($field->type) ? $field->type : null;
440
			$this->name		= isset($field->name) ? $field->name : null;
441
			$this->class	= isset($field->class) ? $field->class : null;
442
			$this->id		= isset($field->id) ? $field->id : null;
443
			$this->label	= isset($field->label) ? $field->label : null;
444
			$this->disabled	= isset($field->disabled) ? $field->disabled : false;
445
			$this->default	= isset($field->default) ? $field->default : null;
446
			$this->required = isset($field->required) ? $field->required : false;
447
			$this->checks   = isset($field->checks) ? $field->checks : array();
448
			$this->title    = isset($field->title) ? $field->title : null;
449
			$this->conditional = isset($field->conditional) ? $field->conditional : false;
450
451
			$this->help		= isset($field->help) ? $field->help : null;
452
453
			if ( isset($this->checks) && !is_array($this->checks) ) {
454
				$this->checks = array( $this->checks );
455
			}
456
			if (isset($field->value)) {
457
				$this->value = $field->value;
458
			} else {
459
				// Find the value, also allow for format like field[subfield]
460
				$name = $this->name;
461 View Code Duplication
				if (preg_match("/(\w+)\[(.*?)]/", $name, $matches)) {
462
					$arrayvalue = ar::getvar($matches[1]);
463
					$value = $this->getArrayValue( substr( $name, strlen( $matches[1] ) ), $arrayvalue );
464
				} else {
465
					$value = ar()->getvar($name);
466
				}
467
468
				if (isset($value)) {
469
					$this->value = $value;
470
				} else if (isset($this->default)) {
471
					$this->value = $this->default;
472
				} else {
473
					$this->value = null;
474
				}
475
			}
476
		}
477
478
		protected function getArrayValue( $name, $value ) {
479
			if ( !$name ) {
480
				return $value;
481
			}
482
			if ( preg_match( '/^\[([^\]]*)\]/', $name, $matches ) ) {
483
				$index = $matches[1];
484
				if ( isset($index) && isset( $value[ $index ] ) ) {
485
					return $this->getArrayValue( substr( $name, strlen( $index )+2 ), $value[ $index ] );
486
				} else {
487
					return null;
488
				}
489
			} else {
490
				return null;
491
			}
492
		}
493
494
		protected function getHelp($help=null) {
495
			if (!isset($help)) {
496
				$help = $this->help;
497
			}
498
			$class = array('formHelp', 'formHelp'.ucfirst($this->type) );
499
			if ($this->class) {
500
				$class[] = $this->class;
501
			}
502
			$attributes = array('class' => $class);
503
504
			if ( trim($help) ) {
505
				$help = ar_html::el('div', $help, array('class' => 'helpContent'));
506
				return ar_html::el('div', $help, $attributes);
507
			} else {
508
				return '';
509
			}
510
		}
511
512
		protected function getLabel($label=null, $id=null, $attributes=null) {
513
			if (!isset($attributes)) {
514
				$attributes = array();
515
			}
516
			if (!isset($label)) {
517
				$label = $this->label;
518
			}
519
			if (!isset($id)) {
520
				$id = $this->name;
521
			}
522
			if ($label!==false) {
523
				if ($this->required) {
524
					$label .= $this->form->requiredLabel;
525
				}
526
				if ($id) {
527
					$attributes['for'] = $id;
528
				}
529
				return ar_html::el('label', $label, $attributes);
530
			} else {
531
				return '';
532
			}
533
		}
534
535
		protected function getInput($type=null, $name=null, $value=null, $disabled=null, $id=null, $title=null) {
536
			if (!isset($type)) {
537
				$type = $this->type;
538
			}
539
			if (!isset($name)) {
540
				$name = $this->name;
541
			}
542
			if (!isset($value)) {
543
				$value = $this->value;
544
			}
545
			if (!isset($id)) {
546
				$id = $name; //this->id is for the field div, not the input tag
547
			}
548
			if (!isset($disabled)) {
549
				$disabled = $this->disabled;
550
			}
551
			if (!isset($title)) {
552
				$title = $this->title;
553
			}
554
			$attributes = array(
555
				'type'	=> $type,
556
				'name'	=> $name,
557
				'id'	=> $id,
558
				'value'	=> $value
559
			);
560
			if ($title) {
561
				$attributes['title'] = $title;
562
			}
563
			$content = ar_html::nodes();
564 View Code Duplication
			if ($disabled) {
565
				$attributes['disabled'] = true;
566
				$content[] = ar_html::el('input', array('type' => 'hidden', 'name' => $name, 'value' => $value));
567
			}
568
			$content[] = ar_html::el('input', $attributes);
569
			return $content;
570
		}
571
572
		public function getValue() {
573
			return $this->value;
574
		}
575
576
		public function setValue($value) {
577
			$this->value = $value;
578
			return true;
579
		}
580
581
		private function buildQuery( $name, $value ) {
582
			if ( is_array( $value ) ) {
583
				$result = '';
584
				foreach ( $value as $index => $subvalue ) {
585
					$result .= $this->buildQuery( $name.'['.$index.']', $subvalue ) . '&';
586
				}
587
			} else {
588
				$result = $name . '=' . RawUrlEncode( $value );
589
			}
590
			return $result;
591
		}
592
593
		public function getNameValue() {
594
			$nameArrayIndex = strpos( $this->name, '[' );
595
			if ( $nameArrayIndex ) {
596
				//FIXME: this results in \r\n being encoded as &#13;&#10;
597
				$urlQuery = $this->buildQuery( $this->name, $this->getValue() );
598
				parse_str( $urlQuery, $result );
599
				return $result;
600
			} else {
601
				return array( $this->name => $this->getValue() );
602
			}
603
		}
604
605
		public function getField( $content = null ) {
606
			if (!isset($content)) {
607
				$content = ar_html::nodes($this->getLabel(), $this->getInput());
608
			}
609
			$help = $this->getHelp();
610
			if ($help) {
611
				$content[] = $help;
612
			}
613
			$class = array('formField', 'form'.ucfirst($this->type) );
614
			if ($this->class) {
615
				$class[] = $this->class;
616
			}
617
			$attributes = array('class' => $class);
618
			if ($this->id) {
619
				$attributes['id'] = $this->id;
620
			}
621
			return ar_html::el('div', $content, $attributes);
622
		}
623
624
		public function validateConditional() {
625
			$conditionMet = true;
626
			if ($this->conditional) {
627
				$conditionMet = false;
628
				if (is_string($this->conditional)) {
629
					try {
630
						$condition = json_decode($this->conditional, true);
631
					} catch(Exception $e) {
632
						$condition = array();
633
					}
634
				}
635
636
				foreach ($condition as $key => $value) {
0 ignored issues
show
Bug introduced by
The variable $condition does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
637
					if (is_string($value)) {
638
						$checkValues = array($value);
639
					} else {
640
						$checkValues = $value;
641
					}
642
643
					foreach ($checkValues as $checkValue) {
644
						$conditionValue = $this->form->getValue($key);
645
646
						if (
647
							$conditionValue == $checkValue || 
648
							(is_array($conditionValue) && $conditionValue[$checkValue])
649
						) {
650
							$conditionMet = true;
651
						}
652
					}
653
				}
654
			}
655
656
			return $conditionMet;
657
		}
658
659
		public function validate() {
660
			$result = array();
661
			if (!$this->validateConditional()) {
662
				return $result;
663
			}
664
665
			$value  = $this->getValue();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $value is correct as $this->getValue() (which targets ar_html_formInput::getValue()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
666
667
			if ( $this->required && ( !isset($value) || $value === '' ) ) {
668
				$result[ $this->name ] = ar::error( 'Required input missing', 'required' );
669
			} else if ( is_array( $this->checks ) ) {
670
				foreach( $this->checks as $check ) {
671
					$regex = false;
672
					if ( isset(ar_html_form::$checks[$check]) ) {
673
						if ( is_array(ar_html_form::$checks[$check])
674
							&& isset(ar_html_form::$checks[$check]['check']) ) {
675
							$checkMethod = ar_html_form::$checks[$check]['check'];
676
							$message	 = ar_html_form::$checks[$check]['message'];
677
							if ( is_callable( $checkMethod ) ) {
678 View Code Duplication
								if ( !$checkMethod( $value ) ) {
679
									$result[ $this->name ] = ar::error(
680
										sprintf( $message, $value ),
681
										$check
682
									);
683
								}
684
							} else if ( is_string($checkMethod) && $checkMethod[0]=='/' ) {
685
								$regex = $checkMethod;
686
							}
687
						} else {
688
							$regex   = ar_html_form::$checks[$check];
689
							$message = 'Failed to match expected input: '.$check;
690
						}
691
					} else {
692
						$regex   = $check;
693
						$message = 'Failed to match expected input';
694
					}
695
					if ( $regex && !preg_match( $regex, $value ) ) {
696
						$result[ $this->name ] = ar::error( sprintf( $message, $value ), $check );
697
					}
698
				}
699
			}
700
			return $result;
701
		}
702
703
		public function __toString() {
704
			return (string)$this->getField();
705
		}
706
707
	}
708
709
	class ar_html_formInputMissing extends ar_html_formInput {
710
711
		public function __construct($field, $form) {
712
			parent::__construct( $field, $form );
713
			$fieldProps = get_object_vars($field);
714
			foreach ( $fieldProps as $name => $value ) {
715
				if ( !isset($this->{$name}) ) {
716
					$this->{$name} = $value;
717
				}
718
			}
719
		}
720
721
		public function getField( $content = null ) {
722
			if ( isset(ar_html_form::$customTypes[ $this->type ]) ) {
723
				$getField = ar_html_form::$customTypes[ $this->type ]['getField'];
724
				if ( isset( $getField) ) {
725
					return $getField($this, $content);
726
				}
727
			}
728
			return parent::getField(
729
				ar_html::nodes( $this->getLabel(), $this->getInput() )
730
			);
731
		}
732
733
		public function getLabel($label=null, $id=null, $attributes=null) {
734
			if ( isset(ar_html_form::$customTypes[ $this->type ]) ) {
735
				$getLabel = ar_html_form::$customTypes[ $this->type ]['getLabel'];
736
				if ( isset( $getLabel ) ) {
737
					return $getLabel($this);
738
				}
739
			}
740
			return parent::getLabel();
741
		}
742
743
		public function getInput($type=null, $name=null, $value=null, $disabled=null, $id=null, $title=null) {
744
			if ( isset(ar_html_form::$customTypes[ $this->type ]) ) {
745
				$getInput = ar_html_form::$customTypes[ $this->type ]['getInput'];
746
				return $getInput($this);
747
			}
748
			return ar_html::el('strong', 'Error: Field type ' . $this->type . ' does not exist.');
749
		}
750
751
		public function getValue() {
752
			if ( isset(ar_html_form::$customTypes[ $this->type ]) ) {
753
				$getValue = ar_html_form::$customTypes[ $this->type ]['getValue'];
754
				if ( isset($getValue) ) {
755
					return $getValue($this);
756
				}
757
			}
758
			return parent::getValue();
759
		}
760
761
		public function __set($name, $value) {
762
			if ($name[0] == '_') {
763
				$name = substr($name, 1);
764
			}
765
			$this->{$name} = $value;
766
		}
767
768
		public function __get($name) {
769
			if ($name[0] == '_') {
770
				$name = substr($name, 1);
771
			}
772
			return $this->{$name};
773
		}
774
775
	}
776
777
	class ar_html_formInputButton extends ar_html_formInput {
778
		public $buttonType, $buttonLabel;
779
780
		public function __construct( $field, $form ) {
781
			parent::__construct( $field, $form );
782
			$this->buttonType = isset($field->buttonType) ? $field->buttonType : null;
783
			$this->buttonLabel = isset($field->buttonLabel) ? $field->buttonLabel : $field->value;
784
		}
785
786
		protected function getInput($type=null, $name=null, $value=null, $disabled=null, $id=null, $title=null, $buttonType=null, $buttonLabel=null ) {
787
			if ( !isset($buttonType) ) {
788
				$buttonType = $this->buttonType;
789
			}
790
			if ( !isset($buttonLabel) ) {
791
				$buttonLabel = $this->buttonLabel;
792
			}
793
			if ( !isset($name) ) {
794
				$name = $this->name;
795
			}
796
			if ( !isset($value) ) {
797
				$value = $this->value;
798
			}
799
			if ( !isset($disabled) ) {
800
				$disabled = $this->disabled;
801
			}
802
			if ( !isset($title) ) {
803
				$title = $this->title;
804
			}
805
			$attributes = array(
806
				'type'	=> $buttonType,
807
				'name'	=> $name,
808
				'value'	=> $value
809
			);
810
			if ( $disabled ) {
811
				$attributes['disabled'] = $disabled;
812
			}
813
			if ( isset( $title ) ) {
814
				$attributes['title'] = $title;
815
			}
816
			return ar_html::el('button', $attributes, $buttonLabel);
817
		}
818
	}
819
820
	class ar_html_formInputText extends ar_html_formInput {
821
		public $maxlength, $size;
822
823
		public function __construct( $field, $form ) {
824
			parent::__construct( $field, $form );
825
			$this->maxlength = isset($field->maxlength) ? $field->maxlength : null;
826
			$this->size = isset($field->size) ? $field->size : null;
827
		}
828
829
		protected function getInput($type=null, $name=null, $value=null, $disabled=null, $id=null, $title=null, $maxlength=null, $size=null ) {
830
			if ( !isset($type) ) {
831
				$type = $this->type;
832
			}
833
			if ( !isset($name) ) {
834
				$name = $this->name;
835
			}
836
			if ( !isset($value) ) {
837
				$value = $this->value;
838
			}
839
			if ( !isset($id) ) {
840
				$id = $name; //this->id is for the field div, not the input tag
841
			}
842
			if ( !isset($disabled) ) {
843
				$disabled = $this->disabled;
844
			}
845
			if ( !isset($title) ) {
846
				$title = $this->title;
847
			}
848
			if ( !isset($maxlength) ) {
849
				$maxlength = $this->maxlength;
850
			}
851
			if ( !isset($size) ) {
852
				$size = $this->size;
853
			}
854
			$attributes = array(
855
				'type'	=> $type,
856
				'name'	=> $name,
857
				'id'	=> $id,
858
				'value'	=> $value
859
			);
860
			if ( $title ) {
861
				$attributes['title'] = $title;
862
			}
863
			if ( $maxlength ) {
864
				$attributes['maxlength'] = $maxlength;
865
			}
866
			if ( $size ) {
867
				$attributes['size'] = $size;
868
			}
869
			$content = ar_html::nodes();
870 View Code Duplication
			if ($disabled) {
871
				$attributes['disabled'] = true;
872
				$content[] = ar_html::el('input', array('type' => 'hidden', 'name' => $name, 'value' => $value));
873
			}
874
			$content[] = ar_html::el('input', $attributes);
875
			return $content;
876
		}
877
878
	}
879
880
	class ar_html_formInputPassword extends ar_html_formInputText {
881
882
		protected function getInput($type=null, $name=null, $value=null, $disabled=null, $id=null, $title=null, $maxlength=null, $size=null) {
883
			$value = ''; // never display a password's value
884
			return parent::getInput($type, $name, $value, $disabled, $id, $title);
885
		}
886
887
	}
888
889
	class ar_html_formInputFile extends ar_html_formInput {
890
891
		public $multiple = false;
892
893
		public function __construct( $field, $form ) {
894
			parent::__construct( $field, $form );
895
			$this->multiple = isset($field->multiple) ? $field->multiple : false;
896
		}
897
898
		protected function getInput($type=null, $name=null, $value=null, $disabled=null, $id=null, $title=null, $multiple=null ) {
899
			$content = parent::getInput( $type, $name, $value, $disabled, $id, $title );
900
			if ( !isset($multiple) ) {
901
				$multiple = $this->multiple;
902
			}
903
			if ( $multiple ) {
904
				$content->attributes['multiple'] = true;
905
			}
906
			return $content;
907
		}
908
909
	}
910
911
	class ar_html_formInputHidden extends ar_html_formInput {
912
913
		public function __construct($field, $form) {
914
			if ($field->label == $field->name) {
915
				$field->label = false;
916
			}
917
			parent::__construct($field, $form);
918
			$this->disabled = false;
919
		}
920
921
		public function __toString() {
922
			return (string)$this->getField($this->getInput());
923
		}
924
	}
925
926
	class ar_html_formInputTextarea extends ar_html_formInputText {
927
928
		public $rows, $cols;
929
930
		public function __construct( $field, $form ) {
931
			parent::__construct( $field, $form );
932
			$this->maxlength = ( isset($field->maxlength) ? $field->maxlength : null );
933
			$this->rows = ( isset($field->rows) ? $field->rows : null );
934
			$this->cols = ( isset($field->cols) ? $field->cols : null );
935
		}
936
937
		protected function getInput( $type=null, $name=null, $value=null, $disabled=null, $id=null, $title=null, $maxlength=null, $rows=null, $cols=null ) {
938
			if (!isset($name)) {
939
				$name = $this->name;
940
			}
941
			if (!isset($value)) {
942
				$value = $this->value;
943
			}
944
945
			if (!isset($id)) {
946
				$id = $name;
947
			}
948
			if (!isset($disabled)) {
949
				$disabled = $this->disabled;
950
			}
951
			if ( !isset($maxlength) ) {
952
				$maxlength = $this->maxlength;
953
			}
954
			if ( !isset($rows) ) {
955
				$rows = $this->rows;
956
			}
957
			if ( !isset($cols) ) {
958
				$cols = $this->cols;
959
			}
960
			$attributes = array(
961
				'name'	=> $name,
962
				'id'	=> $id
963
			);
964
			if (!isset($title)) {
965
				$title = $this->title;
966
			}
967
			if ($title) {
968
				$attributes['title'] = $title;
969
			}
970
			if ($disabled) {
971
				$attributes['disabled'] = true;
972
			}
973
			if ( $maxlength ) {
974
				$attributes['maxlength'] = $maxlength;
975
			}
976
			if ( $cols ) {
977
				$attributes['cols'] = $cols;
978
			}
979
			if ( $rows ) {
980
				$attributes['rows'] = $rows;
981
			}
982
			return ar_html::el('textarea', htmlspecialchars($value, ENT_QUOTES, 'UTF-8' ), $attributes);
983
		}
984
	}
985
986
	class ar_html_formInputSelect extends ar_html_formInput {
987
		public $options;
988
989
		public function __construct($field, $form) {
990
			parent::__construct($field, $form);
991
			$this->options	= isset($field->options) ? $field->options : array();
992
			$this->multiple = isset($field->multiple) ? $field->multiple : false;
0 ignored issues
show
Bug introduced by
The property multiple does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
993
		}
994
995
		protected function getInput($type=null, $name=null, $value=null, $disabled=null, $id=null, $title=null, $options=null, $multiple=null) {
996
			if (!isset($name)) {
997
				$name = $this->name;
998
			}
999
			if (!isset($value)) {
1000
				$value = $this->value;
1001
			}
1002
			if (!isset($id)) {
1003
				$id = $name;
1004
			}
1005
			if (!isset($multiple)) {
1006
				$multiple = $this->multiple;
1007
			}
1008
			if (!isset($disabled)) {
1009
				$disabled = $this->disabled;
1010
			}
1011
			$attributes = array(
1012
				'name'	=> $name,
1013
				'id'	=> $id
1014
			);
1015
			if (!isset($title)) {
1016
				$title = $this->title;
1017
			}
1018
			if ($title) {
1019
				$attributes['title'] = $title;
1020
			}
1021
1022
			if ($multiple) {
1023
				$attributes['multiple'] = "multiple";
1024
			}
1025
			$content = ar_html::nodes();
1026
			if ($disabled) {
1027
				$attributes['disabled'] = true;
1028
			}
1029
			$content[] = ar_html::el('select', $this->getOptions($options, $value), $attributes);
1030
			return $content;
1031
		}
1032
1033
		protected function getOptions($options=null, $selectedValues=false) {
1034
			$content = ar_html::nodes();
1035
			if (!isset($options)) {
1036
				$options = $this->options;
1037
			}
1038
			if (is_array($options)) {
1039
				foreach($options as $key => $option) {
1040
					if (!is_array($option)) {
1041
						$option = array(
1042
							'name' => $option
1043
						);
1044
					}
1045
					if (!isset($option['value'])) {
1046
						$option['value'] = $key;
1047
					}
1048
					$content[] = $this->getOption($option['name'], $option['value'], $selectedValues);
1049
				}
1050
			}
1051
			return $content;
1052
		}
1053
1054
		protected function getOption($name, $value='', $selectedValues=false) {
1055
			$attributes = array(
1056
				'value' => $value
1057
			);
1058
			if ($selectedValues!==false && ( (!$this->multiple && $selectedValues == $value) || ( is_array($selectedValues) && $selectedValues[$name] == $value ) ) ){
1059
				$attributes[] = 'selected';
1060
			}
1061
			return ar_html::el('option', $name, $attributes);
1062
		}
1063
	}
1064
1065
	class ar_html_formInputButtonList extends ar_html_formInputSelect {
1066
1067
		protected function getInput($type=null, $name=null, $value=null, $disabled=null, $id=null, $title=null, $options=null, $multiple=null) {
1068
			if (!isset($name)) {
1069
				$name = $this->name;
1070
			}
1071
			if (!isset($value)) {
1072
				$value = $this->value;
1073
			}
1074
			if (!isset($id)) {
1075
				$id = $name;
1076
			}
1077
			if (!isset($disabled)) {
1078
				$disabled = $this->disabled;
1079
			}
1080
			$attributes = array(
1081
				'class' => 'formButtonListButtons',
1082
				'id'    => $id
1083
			);
1084
			$buttonAttributes = array(
1085
				'name'	=> $name
1086
			);
1087
			if ($disabled) {
1088
				$buttonAttributes['disabled'] = true;
1089
			}
1090
			if (!isset($title)) {
1091
				$title = $this->title;
1092
			}
1093
			if ($title) {
1094
				$attributes['title'] = $title;
1095
			}
1096
			$content = ar_html::nodes();
1097
			$content[] = ar_html::el('div', $this->getButtons($name, $options, $value, $buttonAttributes), $attributes);
1098
			return $content;
1099
		}
1100
1101
		protected function getButtons( $name, $options, $value, $attributes ) {
1102
			$content = ar_html::nodes();
1103
			if ( !isset($options) ) {
1104
				$options = $this->options;
1105
			}
1106
			if ( is_array($options) ) {
1107
				foreach ( $options as $key => $button ) {
1108
					if ( !is_array($button) ) {
1109
						$button = array(
1110
							'label' => $button
1111
						);
1112
					}
1113
					if ( !isset($button['value']) ) {
1114
						$button['value'] = $key;
1115
					}
1116
					$content[] = $this->getButton($key, $name, $button, $value, $attributes);
1117
				}
1118
			}
1119
			$content->setAttribute('class', array(
1120
				'formButtonList' => ar::listPattern( 'formButtonListFirst .*', '.* formButtonListLast' )
1121
			) );
1122
			if ( !$this->multiple ) {
0 ignored issues
show
Bug introduced by
The property multiple does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
1123
				$content->insertBefore( ar_html::el('input', array(
1124
					'type' => 'hidden',
1125
					'name' => $name,
1126
					'value' => $value
1127
				) ), $content->firstChild );
0 ignored issues
show
Documentation introduced by
The property firstChild does not exist on object<ar_htmlNodes>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1128
			}
1129
			return $content;
1130
		}
1131
1132
		protected function getButton( $index, $name, $button, $selectedValues, $attributes ) {
0 ignored issues
show
Unused Code introduced by
The parameter $index is not used and could be removed.

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

Loading history...
1133
			// FIXME: add hidden inputs with current value when multiple values are allowed
1134
			// pressing button again will unset the corresponding value
1135
			if ($button['label']) {
1136
				$buttonLabel = $button['label'];
1137
				unset( $button['label'] );
1138
			} else {
1139
				$buttonLabel = $button['value'];
1140
			}
1141
			$attributes = array_merge( $button, $attributes );
1142
			$buttonEl = ar_html::el('button', $attributes, $buttonLabel);
1143
			if ( $selectedValues!==false
1144
				&& ( (!$this->multiple && $selectedValues == $button['value'])
1145
				|| ( is_array($selectedValues) && $selectedValues[$name] == $button['value'] ) )
1146
			) {
1147
				$buttonEl->setAttribute('class', array(
1148
					'formButtonListSelected' => 'formButtonListSelected'
1149
				) );
1150
			}
1151
			return $buttonEl;
1152
		}
1153
1154
	}
1155
1156
	class ar_html_formInputCheckbox extends ar_html_formInput {
1157
		public $checkedValue, $uncheckedValue;
1158
1159
		public function __construct($field, $form) {
1160
			parent::__construct($field, $form);
1161
			$this->checkedValue = $field->checkedValue;
1162
			$this->uncheckedValue = $field->uncheckedValue;
1163
		}
1164
1165
		public function __toString() {
1166
			return (string) $this->getField();
1167
		}
1168
1169
		public function getField($content=null) {
1170
			$content = ar_html::nodes();
1171
			if (isset($this->uncheckedValue)) {
1172
				$content[] = $this->getInput('hidden', $this->name, $this->uncheckedValue, false,
1173
					$this->name.'_uncheckedValue');
1174
			}
1175
			$content[] = $this->getCheckBox($this->name, $this->checkedValue,
1176
				($this->checkedValue==$this->value), $this->disabled, $this->uncheckedValue, $this->id);
1177
			$content[] = $this->getLabel($this->label, $this->name);
1178
			return parent::getField($content);
1179
		}
1180
1181
		protected function getCheckBox($name=null, $value=null, $checked=false, $disabled=null, $uncheckedValue=false, $id=null) {
1182
			$content = ar_html::nodes();
1183
			if (!isset($name)) {
1184
				$name = $this->name;
1185
			}
1186
			if (!isset($value)) {
1187
				$value = $this->value;
1188
			}
1189
			if (!isset($id)) {
1190
				$id = $name;
1191
			}
1192
			if (!isset($disabled)) {
1193
				$disabled = $this->disabled;
1194
			}
1195
			$attributes = array(
1196
				'type'	=> 'checkbox',
1197
				'name'	=> $name,
1198
				'id'	=> $id,
1199
				'value'	=> $value
1200
			);
1201
			if ($checked) {
1202
				$attributes[] = 'checked';
1203
			}
1204
			if ($disabled) {
1205
				$attributes['disabled'] = true;
1206
				if (!$checked && $uncheckedValue) {
1207
					$hiddenvalue = $uncheckedValue;
1208
				} else if ($checked) {
1209
					$hiddenvalue = $value;
1210
				} else {
1211
					$hiddenvalue = false;
1212
				}
1213 View Code Duplication
				if ($hiddenvalue) {
1214
					$content[] = ar_html::el('input', array('type' => 'hidden', 'name' => $name, 'value' => $hiddenvalue));
1215
				}
1216
			}
1217
			$content[] = ar_html::el('input', $attributes );
1218
			return $content;
1219
		}
1220
	}
1221
1222
	class ar_html_formInputRadio extends ar_html_formInputSelect {
1223
		public function __construct($field, $form) {
1224
			parent::__construct($field, $form);
1225
			$this->options	= isset($field->options) ? $field->options : array();
1226
		}
1227
1228
		protected function getInput($type=null, $name=null, $value=null, $disabled=null, $id=null, $title=null, $options=null, $multiple=null) {
1229
			if (!isset($name)) {
1230
				$name = $this->name;
1231
			}
1232
			if (!isset($value)) {
1233
				$value = $this->value;
1234
			}
1235
			if (!isset($id)) {
1236
				$id = $name;
1237
			}
1238
			$attributes = array(
1239
				'class'    => 'formRadioButtons',
1240
				'id'       => $id
1241
			);
1242
			if (!isset($disabled)) {
1243
				$disabled = $this->disabled;
1244
			}
1245
			if ( $disabled ) {
1246
				$attributes['disabled'] = true;
1247
			}
1248
			$content[] = ar_html::el('div', $this->getRadioButtons($name, $options, $value), $attributes);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$content was never initialized. Although not strictly required by PHP, it is generally a good practice to add $content = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1249
1250
			return $content;
1251
		}
1252
1253
		protected function getRadioButtons($name=null, $options=null, $selectedValue=null) {
1254
			$content = ar_html::nodes();
1255
			if (!isset($name)) {
1256
				$name = $this->name;
1257
			}
1258
			if (!isset($options)) {
1259
				$options = $this->options;
1260
			}
1261
			if (is_array($options)) {
1262
				$count = 0;
1263
				foreach($options as $key => $option) {
1264
					if (!is_array($option)) {
1265
						$option = array(
1266
							'name' => $option
1267
						);
1268
					}
1269
					if (!isset($option['value'])) {
1270
						$option['value'] = $key;
1271
					}
1272
					$content[] = $this->getRadioButton(
1273
						$name,
1274
						$option['value'],
1275
						$option['name'],
1276
						$selectedValue,
1277
						$option['disabled'],
1278
						'radioButton',
1279
						$name.'_'.$count
1280
					);
1281
					$count++;
1282
				}
1283
			}
1284
1285
			return $content;
1286
		}
1287
1288
		protected function getRadioButton( $name, $value='', $label=null, $selectedValue=false, $disabled=null, $class=null, $id=null ) {
1289
			if (isset($class)) {
1290
				$class = array('class' => $class);
1291
			}
1292
			$attributes = array(
1293
				'type'	=> 'radio',
1294
				'value' => $value,
1295
				'name'	=> $name,
1296
				'id'	=> $id
1297
			);
1298
			if ($selectedValue!==false && $selectedValue == $value) {
1299
				$attributes[] = 'checked';
1300
			}
1301
			if ($disabled) {
1302
				$attributes['disabled'] = true;
1303
			}
1304
1305
			return ar_html::el('div', $class, ar_html::nodes(
1306
				ar_html::el('input', $attributes),
1307
				$this->getLabel($label, $id)));
1308
		}
1309
	}
1310
1311
	class ar_html_formInputHtml extends ar_html_formInput {
1312
1313
		public function getField($content=null) {
1314
			$content = ar_html::nodes();
1315
			if ($this->label) {
1316
				$content[] = $this->getLabel($this->label);
1317
			}
1318
			$content[] = $this->value;
1319
			return parent::getField($content);
1320
		}
1321
1322
		public function __toString() {
1323
			return (string) $this->getField();
1324
		}
1325
	}
1326
1327
	class ar_html_formInputFieldset extends ar_html_formInput {
1328
		protected $children = null;
1329
1330
		public function __construct($field, $form) {
1331
			parent::__construct($field, $form);
1332
			$this->children = $this->form->parseFields($field->children);
1333
		}
1334
1335
		public function hasChildren() {
1336
			return count($this->children)>0;
1337
		}
1338
1339
		public function getField($content=null) {
1340
			$legend = null;
1341
			if ($this->label) {
1342
				$legend = ar_html::el('legend', $this->label);
1343
			}
1344
			if (!isset($content)) {
1345
				$content = ar_html::nodes();
1346
				foreach( $this->children as $child ) {
1347
					$content[] = $child->getField();
1348
				}
1349
			}
1350
			$content = ar_html::nodes($legend, $content);
1351
			$help = $this->getHelp();
1352
			if ( $help ) {
1353
				$content[] = $help;
1354
			}
1355
			$class = array('formField', 'form' . ucfirst($this->type) );
1356
			if ($this->class) {
1357
				$class[] = $this->class;
1358
			}
1359
			$attributes = array('class' => $class);
1360
			if ($this->id) {
1361
				$attributes['id'] = $this->id;
1362
			}
1363
			return ar_html::el('fieldset', $content, $attributes);
1364
		}
1365
1366
		public function getNameValue() {
1367
			$result = Array();
1368
			foreach ($this->children as $child) {
1369
				$childResult = $child->getNameValue();
1370
				$result = array_replace_recursive($result, $childResult);
1371
			}
1372
			return $result;
1373
		}
1374
1375
		public function validate( $inputs = null ) {
1376
			$valid = array();
1377
			if (!$this->validateConditional()) {
1378
				return $valid;
1379
			}
1380
			foreach ( $this->children as $key => $child ) {
1381
				$result = $child->validate( $inputs );
1382
				$valid  = array_merge( $valid, $result );
1383
			}
1384
1385
			$value  = $this->getValue();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $value is correct as $this->getValue() (which targets ar_html_formInput::getValue()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1386
			if ( is_array( $this->checks ) ) {
1387
				foreach( $this->checks as $check ) {
1388
					if ( is_array(ar_html_form::$checks[$check])
1389
						&& isset(ar_html_form::$checks[$check]['check'])
1390
					) {
1391
						$checkMethod = ar_html_form::$checks[$check]['check'];
1392
						$message = ar_html_form::$checks[$check]['message'];
1393
						if ( is_callable( $checkMethod ) ) {
1394 View Code Duplication
							if ( !$checkMethod( $value ) ) {
1395
								$valid[ $this->name ] = ar::error(
1396
									sprintf( $message, $value ),
1397
									$check
1398
								);
1399
							}
1400
						} else {
1401
							$valid[ $this->name ] = ar::error('incompatible check for this field',$check);
1402
						}
1403
					}
1404
				}
1405
			}
1406
			return $valid;
1407
		}
1408
1409
	}
1410
1411
	class ar_html_formInputFieldList extends ar_html_formInputFieldset {
1412
		public $defaultField, $newField;
1413
1414
		protected function normalizeChildren( $value ) {
1415
			// make sure the children are a simple array, with numeric keys and that the name of the field
1416
			// is always an array
1417
			// and apply the default formfield on the given values and add those as children
1418
			$this->children = array();
1419
			$count = 0;
1420
			if ( is_array($value) ) {
1421
				foreach ( $value as $key => $child ) {
1422
					if ( !$child ) {
1423
						continue;
1424
					}
1425
					if ( !is_numeric( $key ) ) {
1426
						continue; // skip [Add] and [Delete] entries
1427
					}
1428
					ar::untaint( $child, FILTER_UNSAFE_RAW );
1429
					if ( !is_array($child) || !isset($child['value']) ) {
1430
						$child = array(
1431
							'value' => $child
1432
						);
1433
					}
1434
					$child['name'] = $this->name.'['.$count.']';
1435
					if ( $this->defaultField ) {
1436
						$childOb = clone( $this->defaultField );
1437
						$childOb->name = $child['name'];
1438
						$childOb->setValue( $child['value'] );
1439
					} else {
1440
						$childOb = $this->form->parseField( 0, $child );
1441
					}
1442
					$this->children[] = $childOb;
1443
					$count++;
1444
				}
1445
			}
1446
		}
1447
1448
		protected function getvar( $name ) {
1449 View Code Duplication
			if (preg_match("/(\w+)\[(.*?)]/", $name, $matches)) {
1450
				$arrayvalue = ar::getvar($matches[1]);
1451
				$value = $this->getArrayValue( substr( $name, strlen( $matches[1] ) ), $arrayvalue );
1452
			} else {
1453
				$value = ar()->getvar($name);
1454
			}
1455
			return $value;
1456
		}
1457
1458
		protected function handleUpdates($default) {
1459
			$check = $this->getvar( $this->name ); //$check = ar('http')->getvar( $this->name );
1460
			if ( isset($check['Delete']) ) {
1461
				$delete = $check['Delete'];
1462
				ar::untaint($delete);
1463
				if ( $this->children[$delete] ) {
1464
					unset( $this->children[$delete] );
1465
				}
1466
			} else if ( isset( $check['Add'] ) ) {
1467
				$addedField = $this->getvar( $this->newField->name ); //ar('http')->getvar( $this->newField->name );
1468
				if ( $addedField ) {
1469
					// add a copy of default to the children of this field
1470
					$newField = $default;
1471
					$newField['value'] = $addedField; // FIXME: generiek maken
1472
					$this->children[] = $this->form->parseField(0, $newField );
1473
				}
1474
			}
1475
		}
1476
1477
		public function __construct($field, $form) {
1478
			parent::__construct ($field, $form);
1479
			if ( isset( $field->value ) ) { // apply default behaviour, step 1
1480
				if ( !isset( $field->newField ) ) {
1481
					$field->newField = array(
1482
						'name' => $this->name.'[]',
1483
						'value' => '',
1484
						'label' => false
1485
					);
1486
				}
1487
1488
				if ( !isset( $field->defaultField ) ) {
1489
					$field->defaultField = array(
1490
						'name' => $this->name.'[]',
1491
						'label' => false
1492
					);
1493
				}
1494
			}
1495
1496
			if ( $field->newField ) {
1497
				$this->newField = $form->parseField( 0, $field->newField );
1498
			}
1499
			if ( $field->defaultField ) {
1500
				$this->defaultField = $form->parseField( 0, $field->defaultField );
1501
			}
1502
1503
			if ( isset( $field->value ) ) { // apply default behaviour, step 2
1504
				$this->normalizeChildren( $field->value );
1505
				$this->handleUpdates( $field->default );
1506
			}
1507
		}
1508
1509
		public function getField($content=null) {
1510
			$fieldset = parent::getField($content);
1511
			$count = 0;
1512
			foreach( $fieldset->div as $field ) {
0 ignored issues
show
Documentation introduced by
The property div does not exist on object<ar_htmlElement>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1513
				$field->appendChild( ar_html::el('button', array(
1514
					'class' => 'formFieldListDelete',
1515
					'type' => 'submit',
1516
					'name' => $this->name.'[Delete]',
1517
					'value' => $count
1518
				), '-' ) );
1519
				$count++;
1520
			}
1521
			if ( $this->newField ) {
1522
				$newField = $this->newField->getField();
1523
				$newField->appendChild( ar_html::el('button', array(
1524
					'class' => 'formFieldListAdd',
1525
					'type' => 'submit',
1526
					'name' => $this->name.'[Add]',
1527
					'value' => $this->name.'NewField'
1528
				), '+' ) );
1529
				$fieldset->appendChild(
1530
					ar_html::el('div', array('class' => 'formFieldListAdd'), $newField )
1531
				);
1532
			}
1533
			return $fieldset;
1534
		}
1535
1536
	}
1537