Form::_createInput()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2.0078

Importance

Changes 0
Metric Value
dl 0
loc 16
ccs 7
cts 8
cp 0.875
rs 9.7333
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 2.0078
1
<?php
2
namespace Redaxscript\Html;
3
4
use Redaxscript\Captcha;
5
use Redaxscript\Hash;
6
use Redaxscript\Language;
7
use Redaxscript\Module;
8
use Redaxscript\Registry;
9
use function array_key_exists;
10
use function array_merge;
11
use function array_replace_recursive;
12
use function in_array;
13
use function is_array;
14
use function is_string;
15
use function range;
16
17
/**
18
 * children class to create a form
19
 *
20
 * @since 2.6.0
21
 *
22
 * @package Redaxscript
23
 * @category Html
24
 * @author Henry Ruhs
25
 *
26
 * @method $this button(string $text = null, ?array $attributeArray = [])
27
 * @method $this cancel(string $text = null, ?array $attributeArray = [])
28
 * @method $this checkbox(?array $attributeArray = [])
29
 * @method $this color(?array $attributeArray = [])
30
 * @method $this date(?array $attributeArray = [])
31
 * @method $this datetime(?array $attributeArray = [])
32
 * @method $this email(?array $attributeArray = [])
33
 * @method $this file(?array $attributeArray = [])
34
 * @method $this hidden(?array $attributeArray = [])
35
 * @method $this number(?array $attributeArray = [])
36
 * @method $this password(?array $attributeArray = [])
37
 * @method $this radio(?array $attributeArray = [])
38
 * @method $this range(?array $attributeArray = [])
39
 * @method $this reset(string $text = null, ?array $attributeArray = [])
40
 * @method $this search(?array $attributeArray = [])
41
 * @method $this submit(string $text = null, ?array $attributeArray = [])
42
 * @method $this time(?array $attributeArray = [])
43
 * @method $this tel(?array $attributeArray = [])
44
 * @method $this text(?array $attributeArray = [])
45
 * @method $this url(?array $attributeArray = [])
46
 * @method $this week(?array $attributeArray = [])
47
 */
48
49
class Form extends HtmlAbstract
50
{
51
	/**
52
	 * instance of the registry class
53
	 *
54
	 * @var Registry
55
	 */
56
57
	protected $_registry;
58
59
	/**
60
	 * instance of the language class
61
	 *
62
	 * @var Language
63
	 */
64
65
	protected $_language;
66
67
	/**
68
	 * captcha of the form
69
	 *
70
	 * @var object
71
	 */
72
73
	protected $_captcha;
74
75
	/**
76
	 * languages of the form
77
	 *
78
	 * @var array
79
	 */
80
81
	protected $_languageArray =
82
	[
83
		'legend' => 'fields_required',
84
		'button' =>
85
		[
86
			'button' => 'ok',
87
			'reset' => 'reset',
88
			'submit' => 'submit'
89
		],
90
		'link' =>
91
		[
92
			'cancel' => 'cancel'
93
		]
94
	];
95
96
	/**
97
	 * attributes of the form
98
	 *
99
	 * @var array
100
	 */
101
102
	protected $_attributeArray =
103
	[
104
		'form' =>
105
		[
106
			'class' => 'rs-js-validate rs-form-default',
107
			'method' => 'post'
108
		],
109
		'legend' =>
110
		[
111
			'class' => 'rs-legend-default'
112
		],
113
		'label' =>
114
		[
115
			'class' => 'rs-label-default'
116
		],
117
		'select' =>
118
		[
119
			'class' => 'rs-field-select'
120
		],
121
		'textarea' =>
122
		[
123
			'class' => 'rs-js-resize rs-field-textarea',
124
			'cols' => 100,
125
			'rows' => 5
126
		],
127
		'input' =>
128
		[
129
			'checkbox' =>
130
			[
131
				'class' => 'rs-field-checkbox',
132
				'type' => 'checkbox'
133
			],
134
			'color' =>
135
			[
136
				'class' => 'rs-field-color',
137
				'type' => 'color'
138
			],
139
			'date' =>
140
			[
141
				'class' => 'rs-field-default rs-field-date',
142
				'type' => 'date'
143
			],
144
			'datetime' =>
145
			[
146
				'class' => 'rs-field-default rs-field-date',
147
				'type' => 'datetime-local'
148
			],
149
			'email' =>
150
			[
151
				'class' => 'rs-field-default rs-field-email',
152
				'type' => 'email'
153
			],
154
			'file' =>
155
			[
156
				'class' => 'rs-field-file',
157
				'type' => 'file'
158
			],
159
			'hidden' =>
160
			[
161
				'class' => 'rs-field-hidden',
162
				'type' => 'hidden'
163
			],
164
			'number' =>
165
			[
166
				'class' => 'rs-field-default rs-field-number',
167
				'type' => 'number'
168
			],
169
			'password' =>
170
			[
171
				'class' => 'rs-field-default rs-field-password',
172
				'type' => 'password'
173
			],
174
			'radio' =>
175
			[
176
				'class' => 'rs-field-radio',
177
				'type' => 'radio'
178
			],
179
			'range' =>
180
			[
181
				'class' => 'rs-field-range',
182
				'type' => 'range'
183
			],
184
			'search' =>
185
			[
186
				'class' => 'rs-js-search rs-field-search',
187
				'type' => 'search'
188
			],
189
			'tel' =>
190
			[
191
				'class' => 'rs-field-default rs-field-tel',
192
				'type' => 'tel'
193
			],
194
			'time' =>
195
			[
196
				'class' => 'rs-field-default rs-field-date',
197
				'type' => 'time'
198
			],
199
			'text' =>
200
			[
201
				'class' => 'rs-field-default rs-field-text',
202
				'type' => 'text'
203
			],
204
			'url' =>
205
			[
206
				'class' => 'rs-field-default rs-field-url',
207
				'type' => 'url'
208
			],
209
			'week' =>
210
			[
211
				'class' => 'rs-field-default rs-field-date',
212
				'type' => 'week'
213
			]
214
		],
215
		'button' =>
216
		[
217
			'button' =>
218
			[
219
				'class' => 'rs-js-button rs-button-default',
220
				'type' => 'button'
221
			],
222
			'reset' =>
223
			[
224
				'class' => 'rs-js-reset rs-button-default rs-button-reset',
225
				'type' => 'reset'
226
			],
227
			'submit' =>
228
			[
229
				'class' => 'rs-js-submit rs-button-default rs-button-submit',
230
				'type' => 'submit',
231
				'value' => 'submit'
232
			]
233
		],
234
		'link' =>
235
		[
236
			'cancel' =>
237
			[
238
				'class' => 'rs-js-cancel rs-button-default rs-button-cancel',
239
				'href' => 'javascript:history.back()'
240
			]
241
		]
242
	];
243
244
	/**
245
	 * options of the form
246
	 *
247
	 * @var array
248
	 */
249
250
	protected $_optionArray =
251
	[
252
		'captcha' => 0
253
	];
254
255
	/**
256
	 * constructor of the class
257
	 *
258
	 * @since 2.6.0
259
	 *
260
	 * @param Registry $registry instance of the registry class
261
	 * @param Language $language instance of the language class
262
	 */
263
264 67
	public function __construct(Registry $registry, Language $language)
265
	{
266 67
		$this->_registry = $registry;
267 67
		$this->_language = $language;
268 67
	}
269
270
	/**
271
	 * call method as needed
272
	 *
273
	 * @since 2.6.0
274
	 *
275
	 * @param string $method name of the method
276
	 * @param array|null $argumentArray arguments of the method
277
	 *
278
	 * @return self
279
	 */
280
281 47
	public function __call(string $method = null, ?array $argumentArray = []) : self
282
	{
283
		/* input */
284
285 47
		if (is_array($this->_attributeArray['input']) && array_key_exists($method, $this->_attributeArray['input']))
286
		{
287 37
			return $this->_createInput($method, $argumentArray[0]);
288
		}
289
290
		/* button */
291
292 10
		if (is_array($this->_attributeArray['button']) && array_key_exists($method, $this->_attributeArray['button']))
293
		{
294 6
			return $this->_createButton($method, $argumentArray[0], $argumentArray[1]);
295
		}
296
297
		/* link */
298
299 4
		if (is_array($this->_attributeArray['link']) && array_key_exists($method, $this->_attributeArray['link']))
300
		{
301 2
			return $this->_createLink($method, $argumentArray[0], $argumentArray[1]);
302
		}
303 2
		return $this;
304
	}
305
306
	/**
307
	 * stringify the form
308
	 *
309
	 * @since 2.6.0
310
	 *
311
	 * @return string
312
	 */
313
314 30
	public function __toString() : string
315
	{
316 30
		return $this->render();
317
	}
318
319
	/**
320
	 * init the class
321
	 *
322
	 * @since 2.6.0
323
	 *
324
	 * @param array $attributeArray attributes of the form
325
	 * @param array $optionArray options of the form
326
	 *
327
	 * @return self
328
	 */
329
330 67
	public function init(array $attributeArray = [], array $optionArray = []) : self
331
	{
332 67
		$this->_attributeArray = array_replace_recursive($this->_attributeArray, $attributeArray);
333 67
		$this->_optionArray = array_replace_recursive($this->_optionArray, $optionArray);
334
335
		/* captcha */
336
337 67
		if ($this->_optionArray['captcha'] > 0)
338
		{
339 3
			$this->_captcha = new Captcha($this->_language->getInstance());
340 3
			$this->_captcha->init();
341
		}
342 67
		return $this;
343
	}
344
345
	/**
346
	 * append the legend
347
	 *
348
	 * @since 3.0.0
349
	 *
350
	 * @param string $html html of the legend
351
	 * @param array|null $attributeArray attributes of the legend
352
	 *
353
	 * @return self
354
	 */
355
356 2
	public function legend(string $html = null, ?array $attributeArray = []) : self
357
	{
358 2
		if (is_array($attributeArray))
359
		{
360 2
			$attributeArray = array_merge($this->_attributeArray['legend'], $attributeArray);
361
		}
362
		else
363
		{
364
			$attributeArray = $this->_attributeArray['legend'];
365
		}
366 2
		$legendElement = new Element();
367
		$legendElement
368 2
			->init('legend', $attributeArray)
369 2
			->html($html ? : $this->_language->get($this->_languageArray['legend']) . $this->_language->get('point'));
370 2
		$this->append($legendElement);
371 2
		return $this;
372
	}
373
374
	/**
375
	 * append the label
376
	 *
377
	 * @since 3.0.0
378
	 *
379
	 * @param string $html html of the label
380
	 * @param array|null $attributeArray attributes of the label
381
	 *
382
	 * @return self
383
	 */
384
385 3
	public function label(string $html = null, ?array $attributeArray = []) : self
386
	{
387 3
		if (is_array($attributeArray))
388
		{
389 3
			$attributeArray = array_merge($this->_attributeArray['label'], $attributeArray);
390
		}
391
		else
392
		{
393
			$attributeArray = $this->_attributeArray['label'];
394
		}
395 3
		$labelElement = new Element();
396
		$labelElement
397 3
			->init('label', $attributeArray)
398 3
			->html($html);
399 3
		$this->append($labelElement);
400 3
		return $this;
401
	}
402
403
	/**
404
	 * append the textarea
405
	 *
406
	 * @since 2.6.0
407
	 *
408
	 * @param array|null $attributeArray attributes of the textarea
409
	 *
410
	 * @return self
411
	 */
412
413 3
	public function textarea(?array $attributeArray = []) : self
414
	{
415 3
		if (is_array($attributeArray))
416
		{
417 3
			$attributeArray = array_merge($this->_attributeArray['textarea'], $attributeArray);
418
		}
419
		else
420
		{
421
			$attributeArray = $this->_attributeArray['textarea'];
422
		}
423 3
		$textareaElement = new Element();
424
		$textareaElement
425 3
			->init('textarea', $attributeArray)
426 3
			->text($attributeArray['value'])
427 3
			->val(null);
428 3
		$this->append($textareaElement);
429 3
		return $this;
430
	}
431
432
	/**
433
	 * append the select
434
	 *
435
	 * @since 2.6.0
436
	 *
437
	 * @param array $optionArray option of the select
438
	 * @param array $selectArray values to be selected
439
	 * @param array|null $attributeArray attributes of the select
440
	 *
441
	 * @return self
442
	 */
443
444 10
	public function select(array $optionArray = [], array $selectArray = [], ?array $attributeArray = []) : self
445
	{
446 10
		if (is_array($attributeArray))
447
		{
448 10
			$attributeArray = array_merge($this->_attributeArray['select'], $attributeArray);
449
		}
450
		else
451
		{
452
			$attributeArray = $this->_attributeArray['select'];
453
		}
454 10
		$selectElement = new Element();
455
		$selectElement
456 10
			->init('select', $attributeArray)
457 10
			->html($this->_createOption($optionArray, $selectArray));
458 10
		$this->append($selectElement);
459 10
		return $this;
460
	}
461
462
	/**
463
	 * append the select range
464
	 *
465
	 * @since 3.0.0
466
	 *
467
	 * @param array $rangeArray range of the select
468
	 * @param array $selectArray values to be selected
469
	 * @param array|null $attributeArray attributes of the select
470
	 *
471
	 * @return self
472
	 */
473
474 4
	public function selectRange(array $rangeArray = [], array $selectArray = [], ?array $attributeArray = []) : self
475
	{
476 4
		$this->select(range($rangeArray['min'], $rangeArray['max']), $selectArray, $attributeArray);
477 4
		return $this;
478
	}
479
480
	/**
481
	 * append the captcha
482
	 *
483
	 * @since 2.6.0
484
	 *
485
	 * @param string $type type of the captcha
486
	 *
487
	 * @return self
488
	 */
489
490 2
	public function captcha(string $type = null) : self
491
	{
492
		/* task */
493
494 2
		if ($this->_optionArray['captcha'] > 0 && $type === 'task')
495
		{
496 1
			$this->label('* ' . $this->_captcha->getTask(),
497
			[
498 1
				'for' => 'task'
499
			]);
500
501
			/* number */
502
503 1
			$this->number(
504
			[
505 1
				'id' => 'task',
506 1
				'min' => $this->_captcha->getMin(),
507 1
				'max' => $this->_captcha->getMax() * 2,
508 1
				'name' => 'task',
509 1
				'required' => 'required'
510
			]);
511
		}
512
513
		/* solution */
514
515 2
		if ($this->_optionArray['captcha'] > 0 && $type === 'solution')
516
		{
517 1
			$captchaHash = new Hash();
518 1
			$captchaHash->init($this->_captcha->getSolution());
519
520
			/* hidden */
521
522 1
			$this->hidden(
523
			[
524 1
				'name' => 'solution',
525 1
				'value' => $captchaHash->getHash()
526
			]);
527
		}
528 2
		return $this;
529
	}
530
531
	/**
532
	 * append the token
533
	 *
534
	 * @since 2.6.0
535
	 *
536
	 * @return self
537
	 */
538
539 2
	public function token() : self
540
	{
541 2
		$token = $this->_registry->get('token');
542 2
		if ($token)
543
		{
544 1
			$this->hidden(
545
			[
546 1
				'name' => 'token',
547 1
				'value' => $token
548
			]);
549
		}
550 2
		return $this;
551
	}
552
553
	/**
554
	 * render the form
555
	 *
556
	 * @since 2.6.0
557
	 *
558
	 * @return string
559
	 */
560
561 67
	public function render() : string
562
	{
563 67
		$output = Module\Hook::trigger('formStart');
564 67
		$formElement = new Element();
565 67
		$formElement->init('form', $this->_attributeArray['form']);
566
567
		/* collect output */
568
569 67
		$output .= $formElement->html($this->_html);
570 67
		$output .= Module\Hook::trigger('formEnd');
571 67
		return $output;
572
	}
573
574
	/**
575
	 * create the input
576
	 *
577
	 * @since 2.6.0
578
	 *
579
	 * @param string $type type of the input
580
	 * @param array|null $attributeArray attributes of the input
581
	 *
582
	 * @return self
583
	 */
584
585 37
	protected function _createInput(string $type = 'text', ?array $attributeArray = []) : self
586
	{
587 37
		if (is_array($attributeArray))
588
		{
589
590 37
			$attributeArray = array_merge($this->_attributeArray['input'][$type], $attributeArray);
591
		}
592
		else
593
		{
594
			$attributeArray = $this->_attributeArray['input'][$type];
595
		}
596 37
		$inputElement = new Element();
597 37
		$inputElement->init('input', $attributeArray);
598 37
		$this->append($inputElement);
599 37
		return $this;
600
	}
601
602
	/**
603
	 * create the option
604
	 *
605
	 * @since 3.0.0
606
	 *
607
	 * @param array $optionArray option of the select
608
	 * @param array $selectArray values to be selected
609
	 *
610
	 * @return string|null
611
	 */
612
613 10
	protected function _createOption(array $optionArray = [], array $selectArray = []) : ?string
614
	{
615 10
		$output = null;
616 10
		$optionElement = new Element();
617 10
		$optionElement->init('option');
618
619
		/* process values */
620
621 10
		foreach ($optionArray as $key => $value)
622
		{
623 8
			if ($key || $value)
624
			{
625
				$output .= $optionElement
626 6
					->copy()
627 6
					->attr(
628
					[
629 6
						'selected' => is_array($selectArray) && in_array($value, $selectArray) ? 'selected' : null,
630 6
						'value' => $value
631
					])
632 6
					->text(is_string($key) ? $key : $value);
633
			}
634
		}
635 10
		return $output;
636
	}
637
638
	/**
639
	 * create the button
640
	 *
641
	 * @since 2.6.0
642
	 *
643
	 * @param string $type type of the button
644
	 * @param string $text text of the button
645
	 * @param array|null $attributeArray attributes of the button
646
	 *
647
	 * @return self
648
	 */
649
650 6
	protected function _createButton(string $type = null, string $text = null, ?array $attributeArray = []) : self
651
	{
652 6
		if (is_array($attributeArray))
653
		{
654 6
			$attributeArray = array_merge($this->_attributeArray['button'][$type], $attributeArray);
655
		}
656
		else
657
		{
658
			$attributeArray = $this->_attributeArray['button'][$type];
659
		}
660 6
		$buttonElement = new Element();
661
		$buttonElement
662 6
			->init('button', $attributeArray)
663 6
			->text($text ? : $this->_language->get($this->_languageArray['button'][$type]));
0 ignored issues
show
Bug introduced by redaxmedia
It seems like $text ?: $this->_languag...Array['button'][$type]) can also be of type array; however, Redaxscript\Html\Element::text() does only seem to accept string|integer|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
664 6
		$this->append($buttonElement);
665 6
		return $this;
666
	}
667
668
	/**
669
	 * create the link
670
	 *
671
	 * @since 3.0.0
672
	 *
673
	 * @param string $type type of the link
674
	 * @param string $text text of the link
675
	 * @param array|null $attributeArray attributes of the link
676
	 *
677
	 * @return self
678
	 */
679
680 2
	protected function _createLink(string $type = null, string $text = null, ?array $attributeArray = []) : self
681
	{
682 2
		if (is_array($attributeArray))
683
		{
684 2
			$attributeArray = array_merge($this->_attributeArray['link'][$type], $attributeArray);
685
		}
686
		else
687
		{
688
			$attributeArray = $this->_attributeArray['link'][$type];
689
		}
690 2
		$linkElement = new Element();
691
		$linkElement
692 2
			->init('a', $attributeArray)
693 2
			->text($text ? : $this->_language->get($this->_languageArray['link'][$type]));
0 ignored issues
show
Bug introduced by redaxmedia
It seems like $text ?: $this->_languag...geArray['link'][$type]) can also be of type array; however, Redaxscript\Html\Element::text() does only seem to accept string|integer|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
694 2
		$this->append($linkElement);
695 2
		return $this;
696
	}
697
}
698