Completed
Push — master ( 4456af...82a1a1 )
by Henry
08:38
created

Form::_appendInput()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 1
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->_appendInput($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->_appendButton($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->_appendLink($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 1
			$attributeArray = array_merge($this->_attributeArray['legend'], $attributeArray);
361
		}
362
		else
363
		{
364 1
			$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 2
			$attributeArray = array_merge($this->_attributeArray['label'], $attributeArray);
390
		}
391
		else
392
		{
393 1
			$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 2
			$attributeArray = array_merge($this->_attributeArray['textarea'], $attributeArray);
418
		}
419
		else
420
		{
421 1
			$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 3
			$attributeArray = array_merge($this->_attributeArray['select'], $attributeArray);
449
		}
450
		else
451
		{
452 7
			$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
	 * append the input
576
	 *
577
	 * @since 4.3.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 _appendInput(string $type = 'text', ?array $attributeArray = []) : self
586
	{
587 37
		$this->append($this->_createInput($type, $attributeArray));
588
		return $this;
589
	}
590 20
591
	/**
592
	 * create the input
593
	 *
594 17
	 * @since 4.3.0
595
	 *
596 37
	 * @param string $type type of the input
597 37
	 * @param array|null $attributeArray attributes of the input
598 37
	 *
599 37
	 * @return Element
600
	 */
601
602
	protected function _createInput(string $type = 'text', ?array $attributeArray = []) : Element
603
	{
604
		if (is_array($attributeArray))
605
		{
606
607
			$attributeArray = array_merge($this->_attributeArray['input'][$type], $attributeArray);
608
		}
609
		else
610
		{
611
			$attributeArray = $this->_attributeArray['input'][$type];
612
		}
613 10
		$inputElement = new Element();
614
		return $inputElement->init('input', $attributeArray);
615 10
	}
616 10
617 10
	/**
618
	 * create the option
619
	 *
620
	 * @since 3.0.0
621 10
	 *
622
	 * @param array $optionArray option of the select
623 8
	 * @param array $selectArray values to be selected
624
	 *
625
	 * @return string|null
626 6
	 */
627 6
628
	protected function _createOption(array $optionArray = [], array $selectArray = []) : ?string
629 6
	{
630 6
		$output = null;
631
		$optionElement = new Element();
632 6
		$optionElement->init('option');
633
634
		/* process values */
635 10
636
		foreach ($optionArray as $key => $value)
637
		{
638
			if ($key || $value)
639
			{
640
				$output .= $optionElement
641
					->copy()
642
					->attr(
643
					[
644
						'selected' => is_array($selectArray) && in_array($value, $selectArray) ? 'selected' : null,
645
						'value' => $value
646
					])
647
					->text(is_string($key) ? $key : $value);
648
			}
649
		}
650 6
		return $output;
651
	}
652 6
653
	/**
654 3
	 * append the button
655
	 *
656
	 * @since 4.3.0
657
	 *
658 3
	 * @param string $type type of the button
659
	 * @param string $text text of the button
660 6
	 * @param array|null $attributeArray attributes of the button
661
	 *
662 6
	 * @return self
663 6
	 */
664 6
665 6
	protected function _appendButton(string $type = null, string $text = null, ?array $attributeArray = []) : self
666
	{
667
		return $this->append($this->_createButton($type, $text, $attributeArray));
668
	}
669
670
	/**
671
	 * create the button
672
	 *
673
	 * @since 4.3.0
674
	 *
675
	 * @param string $type type of the button
676
	 * @param string $text text of the button
677
	 * @param array|null $attributeArray attributes of the button
678
	 *
679
	 * @return Element
680 2
	 */
681
682 2
	protected function _createButton(string $type = null, string $text = null, ?array $attributeArray = []) : Element
683
	{
684 1
		if (is_array($attributeArray))
685
		{
686
			$attributeArray = array_merge($this->_attributeArray['button'][$type], $attributeArray);
687
		}
688 1
		else
689
		{
690 2
			$attributeArray = $this->_attributeArray['button'][$type];
691
		}
692 2
		$buttonElement = new Element();
693 2
		return $buttonElement
694 2
			->init('button', $attributeArray)
695 2
			->text($text ? : $this->_language->get($this->_languageArray['button'][$type]));
0 ignored issues
show
Bug introduced by
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...
696
	}
697
698
	/**
699
	 * append the link
700
	 *
701
	 * @since 4.3.0
702
	 *
703
	 * @param string $type type of the link
704
	 * @param string $text text of the link
705
	 * @param array|null $attributeArray attributes of the link
706
	 *
707
	 * @return self
708
	 */
709
710
	protected function _appendLink(string $type = null, string $text = null, ?array $attributeArray = []) : self
711
	{
712
		return $this->append($this->_createLink($type, $text, $attributeArray));
713
	}
714
715
	/**
716
	 * append the link
717
	 *
718
	 * @since 4.3.0
719
	 *
720
	 * @param string $type type of the link
721
	 * @param string $text text of the link
722
	 * @param array|null $attributeArray attributes of the link
723
	 *
724
	 * @return Element
725
	 */
726
727
	protected function _createLink(string $type = null, string $text = null, ?array $attributeArray = []) : Element
728
	{
729
		if (is_array($attributeArray))
730
		{
731
			$attributeArray = array_merge($this->_attributeArray['link'][$type], $attributeArray);
732
		}
733
		else
734
		{
735
			$attributeArray = $this->_attributeArray['link'][$type];
736
		}
737
		$linkElement = new Element();
738
		return $linkElement
739
			->init('a', $attributeArray)
740
			->text($text ? : $this->_language->get($this->_languageArray['link'][$type]));
0 ignored issues
show
Bug introduced by
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...
741
	}
742
}
743