Completed
Push — master ( a52438...bf8826 )
by Henry
06:30
created

Form   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 646
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 46
lcom 1
cbo 7
dl 0
loc 646
ccs 127
cts 127
cp 1
rs 8.674
c 0
b 0
f 0

How to fix   Complexity   

Complex Class

Complex classes like Form often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Form, and based on these observations, apply Extract Interface, too.

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
	 * captcha of the form
53
	 *
54
	 * @var object
55
	 */
56
57
	protected $_captcha;
58
59
	/**
60
	 * languages of the form
61
	 *
62
	 * @var array
63
	 */
64
65
	protected $_languageArray =
66
	[
67
		'legend' => 'fields_required',
68
		'button' =>
69
		[
70
			'button' => 'ok',
71
			'reset' => 'reset',
72
			'submit' => 'submit'
73
		],
74
		'link' =>
75
		[
76
			'cancel' => 'cancel'
77
		]
78
	];
79
80
	/**
81
	 * attributes of the form
82
	 *
83
	 * @var array
84
	 */
85
86
	protected $_attributeArray =
87
	[
88
		'form' =>
89
		[
90
			'class' => 'rs-js-validate rs-form-default',
91
			'method' => 'post'
92
		],
93
		'legend' =>
94
		[
95
			'class' => 'rs-legend-default'
96
		],
97
		'label' =>
98
		[
99
			'class' => 'rs-label-default'
100
		],
101
		'select' =>
102
		[
103
			'class' => 'rs-field-select'
104
		],
105
		'textarea' =>
106
		[
107
			'class' => 'rs-js-resize rs-field-textarea',
108
			'cols' => 100,
109
			'rows' => 5
110
		],
111
		'input' =>
112
		[
113
			'checkbox' =>
114
			[
115
				'class' => 'rs-field-checkbox',
116
				'type' => 'checkbox'
117
			],
118
			'color' =>
119
			[
120
				'class' => 'rs-field-color',
121
				'type' => 'color'
122
			],
123
			'date' =>
124
			[
125
				'class' => 'rs-field-default rs-field-date',
126
				'type' => 'date'
127
			],
128
			'datetime' =>
129
			[
130
				'class' => 'rs-field-default rs-field-date',
131
				'type' => 'datetime-local'
132
			],
133
			'email' =>
134
			[
135
				'class' => 'rs-field-default rs-field-email',
136
				'type' => 'email'
137
			],
138
			'file' =>
139
			[
140
				'class' => 'rs-field-file',
141
				'type' => 'file'
142
			],
143
			'hidden' =>
144
			[
145
				'class' => 'rs-field-hidden',
146
				'type' => 'hidden'
147
			],
148
			'number' =>
149
			[
150
				'class' => 'rs-field-default rs-field-number',
151
				'type' => 'number'
152
			],
153
			'password' =>
154
			[
155
				'class' => 'rs-js-password rs-field-default rs-field-password',
156
				'type' => 'password'
157
			],
158
			'radio' =>
159
			[
160
				'class' => 'rs-field-radio',
161
				'type' => 'radio'
162
			],
163
			'range' =>
164
			[
165
				'class' => 'rs-field-range',
166
				'type' => 'range'
167
			],
168
			'search' =>
169
			[
170
				'class' => 'rs-js-search rs-field-search',
171
				'type' => 'search'
172
			],
173
			'tel' =>
174
			[
175
				'class' => 'rs-field-default rs-field-tel',
176
				'type' => 'tel'
177
			],
178
			'time' =>
179
			[
180
				'class' => 'rs-field-default rs-field-date',
181
				'type' => 'time'
182
			],
183
			'text' =>
184
			[
185
				'class' => 'rs-field-default rs-field-text',
186
				'type' => 'text'
187
			],
188
			'url' =>
189
			[
190
				'class' => 'rs-field-default rs-field-url',
191
				'type' => 'url'
192
			],
193
			'week' =>
194
			[
195
				'class' => 'rs-field-default rs-field-date',
196
				'type' => 'week'
197
			]
198
		],
199
		'button' =>
200
		[
201
			'button' =>
202
			[
203
				'class' => 'rs-js-button rs-button-default',
204
				'type' => 'button'
205
			],
206
			'reset' =>
207
			[
208
				'class' => 'rs-js-reset rs-button-default rs-button-reset',
209
				'type' => 'reset'
210
			],
211
			'submit' =>
212
			[
213
				'class' => 'rs-js-submit rs-button-default rs-button-submit',
214
				'type' => 'submit',
215
				'value' => 'submit'
216
			]
217
		],
218
		'link' =>
219
		[
220
			'cancel' =>
221
			[
222
				'class' => 'rs-js-cancel rs-button-default rs-button-cancel',
223
				'href' => 'javascript:history.back()'
224
			]
225
		]
226
	];
227
228
	/**
229
	 * options of the form
230
	 *
231
	 * @var array
232
	 */
233
234
	protected array $_optionArray =
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected T_ARRAY, expecting T_FUNCTION or T_CONST
Loading history...
235
	[
236
		'captcha' => 0
237
	];
238
239
	/**
240
	 * constructor of the class
241
	 *
242
	 * @since 2.6.0
243
	 *
244
	 * @param Registry $_registry instance of the registry class
245
	 * @param Language $_language instance of the language class
246
	 */
247
248
	public function __construct(protected Registry $_registry, protected Language $_language)
249
	{
250
	}
251
252
	/**
253
	 * call method as needed
254
	 *
255
	 * @since 2.6.0
256
	 *
257
	 * @param string $method name of the method
258
	 * @param array|null $argumentArray arguments of the method
259
	 *
260
	 * @return self
261
	 */
262
263
	public function __call(string $method = null, ?array $argumentArray = []) : self
264 67
	{
265
		$text = array_key_exists(0, $argumentArray) ? $argumentArray[0] : null;
266 67
		$attributeArray = array_key_exists(1, $argumentArray) ? $argumentArray[1] : [];
267 67
268 67
		/* input */
269
270
		if (is_array($this->_attributeArray['input']) && array_key_exists($method, $this->_attributeArray['input']))
271
		{
272
			return $this->append($this->_createInput($method, $text));
273
		}
274
275
		/* button */
276
277
		if (is_array($this->_attributeArray['button']) && array_key_exists($method, $this->_attributeArray['button']))
278
		{
279
			return $this->append($this->_createButton($method, $text, $attributeArray));
280
		}
281 47
282
		/* link */
283 47
284 47
		if (is_array($this->_attributeArray['link']) && array_key_exists($method, $this->_attributeArray['link']))
285
		{
286
			return $this->append($this->_createLink($method, $text, $attributeArray));
287
		}
288 47
		return $this;
289
	}
290 37
291
	/**
292
	 * stringify the form
293
	 *
294
	 * @since 2.6.0
295 10
	 *
296
	 * @return string
297 6
	 */
298
299
	public function __toString() : string
300
	{
301
		return $this->render();
302 4
	}
303
304 2
	/**
305
	 * init the class
306 2
	 *
307
	 * @since 2.6.0
308
	 *
309
	 * @param array $attributeArray attributes of the form
310
	 * @param array $optionArray options of the form
311
	 *
312
	 * @return self
313
	 */
314
315
	public function init(array $attributeArray = [], array $optionArray = []) : self
316
	{
317 30
		$this->_attributeArray = array_replace_recursive($this->_attributeArray, $attributeArray);
318
		$this->_optionArray = array_replace_recursive($this->_optionArray, $optionArray);
319 30
320
		/* captcha */
321
322
		if ($this->_optionArray['captcha'] > 0)
323
		{
324
			$this->_captcha = new Captcha($this->_language->getInstance());
325
			$this->_captcha->init();
326
		}
327
		return $this;
328
	}
329
330
	/**
331
	 * append the legend
332
	 *
333 67
	 * @since 3.0.0
334
	 *
335 67
	 * @param string $html html of the legend
336 67
	 * @param array|null $attributeArray attributes of the legend
337
	 *
338
	 * @return self
339
	 */
340 67
341
	public function legend(string $html = null, ?array $attributeArray = []) : self
342 3
	{
343 3
		if (is_array($attributeArray))
344
		{
345 67
			$attributeArray = array_merge($this->_attributeArray['legend'], $attributeArray);
346
		}
347
		else
348
		{
349
			$attributeArray = $this->_attributeArray['legend'];
350
		}
351
		$legendElement = new Element();
352
		$legendElement
353
			->init('legend', $attributeArray)
354
			->html($html ? : $this->_language->get($this->_languageArray['legend']) . $this->_language->get('point'));
355
		$this->append($legendElement);
356
		return $this;
357
	}
358
359 2
	/**
360
	 * append the label
361 2
	 *
362
	 * @since 3.0.0
363 1
	 *
364
	 * @param string $html html of the label
365
	 * @param array|null $attributeArray attributes of the label
366
	 *
367 1
	 * @return self
368
	 */
369 2
370
	public function label(string $html = null, ?array $attributeArray = []) : self
371 2
	{
372 2
		if (is_array($attributeArray))
373 2
		{
374 2
			$attributeArray = array_merge($this->_attributeArray['label'], $attributeArray);
375
		}
376
		else
377
		{
378
			$attributeArray = $this->_attributeArray['label'];
379
		}
380
		$labelElement = new Element();
381
		$labelElement
382
			->init('label', $attributeArray)
383
			->html($html);
384
		$this->append($labelElement);
385
		return $this;
386
	}
387
388 3
	/**
389
	 * append the textarea
390 3
	 *
391
	 * @since 2.6.0
392 2
	 *
393
	 * @param array|null $attributeArray attributes of the textarea
394
	 *
395
	 * @return self
396 1
	 */
397
398 3
	public function textarea(?array $attributeArray = []) : self
399
	{
400 3
		if (is_array($attributeArray))
401 3
		{
402 3
			$attributeArray = array_merge($this->_attributeArray['textarea'], $attributeArray);
403 3
		}
404
		else
405
		{
406
			$attributeArray = $this->_attributeArray['textarea'];
407
		}
408
		$textareaElement = new Element();
409
		$textareaElement
410
			->init('textarea', $attributeArray)
411
			->text($attributeArray['value'] ?? null)
412
			->val(null);
413
		$this->append($textareaElement);
414
		return $this;
415
	}
416 3
417
	/**
418 3
	 * append the select
419
	 *
420 2
	 * @since 2.6.0
421
	 *
422
	 * @param array $optionArray option of the select
423
	 * @param array $selectArray values to be selected
424 1
	 * @param array|null $attributeArray attributes of the select
425
	 *
426 3
	 * @return self
427
	 */
428 3
429 3
	public function select(array $optionArray = [], array $selectArray = [], ?array $attributeArray = []) : self
430 3
	{
431 3
		if (is_array($attributeArray))
432 3
		{
433
			$attributeArray = array_merge($this->_attributeArray['select'], $attributeArray);
434
		}
435
		else
436
		{
437
			$attributeArray = $this->_attributeArray['select'];
438
		}
439
		$selectElement = new Element();
440
		$selectElement
441
			->init('select', $attributeArray)
442
			->html($this->_createOption($optionArray, $selectArray));
443
		$this->append($selectElement);
444
		return $this;
445
	}
446
447 10
	/**
448
	 * append the select range
449 10
	 *
450
	 * @since 3.0.0
451 3
	 *
452
	 * @param array $rangeArray range of the select
453
	 * @param array $selectArray values to be selected
454
	 * @param array|null $attributeArray attributes of the select
455 7
	 *
456
	 * @return self
457 10
	 */
458
459 10
	public function selectRange(array $rangeArray = [], array $selectArray = [], ?array $attributeArray = []) : self
460 10
	{
461 10
		$range = range($rangeArray['min'] ?? 0, $rangeArray['max'] ?? 0);
462 10
		$this->select($range, $selectArray, $attributeArray);
463
		return $this;
464
	}
465
466
	/**
467
	 * append the captcha
468
	 *
469
	 * @since 2.6.0
470
	 *
471
	 * @param string $type type of the captcha
472
	 *
473
	 * @return self
474
	 */
475
476
	public function captcha(string $type = null) : self
477 4
	{
478
		/* task */
479 4
480 4
		if ($this->_optionArray['captcha'] > 0 && $type === 'task')
481 4
		{
482
			$this->label('* ' . $this->_captcha->getTask(),
483
			[
484
				'for' => 'task'
485
			]);
486
487
			/* number */
488
489
			$this->number(
490
			[
491
				'id' => 'task',
492
				'min' => $this->_captcha->getMin(),
493
				'max' => $this->_captcha->getMax() * 2,
494 2
				'name' => 'task',
495
				'required' => 'required'
496
			]);
497
		}
498 2
499
		/* solution */
500 1
501
		if ($this->_optionArray['captcha'] > 0 && $type === 'solution')
502 1
		{
503
			$captchaHash = new Hash();
504
			$captchaHash->init($this->_captcha->getSolution());
505
506
			/* hidden */
507 1
508
			$this->hidden(
509 1
			[
510 1
				'name' => 'solution',
511 1
				'value' => $captchaHash->getHash()
512 1
			]);
513 1
		}
514
		return $this;
515
	}
516
517
	/**
518
	 * append the token
519 2
	 *
520
	 * @since 2.6.0
521 1
	 *
522 1
	 * @return self
523
	 */
524
525
	public function token() : self
526 1
	{
527
		$token = $this->_registry->get('token');
528 1
		if ($token)
529 1
		{
530
			$this->hidden(
531
			[
532 2
				'name' => 'token',
533
				'value' => $token
534
			]);
535
		}
536
		return $this;
537
	}
538
539
	/**
540
	 * render the form
541
	 *
542
	 * @since 2.6.0
543 2
	 *
544
	 * @return string
545 2
	 */
546 2
547
	public function render() : string
548 1
	{
549
		$output = Module\Hook::trigger('formStart');
550 1
		$formElement = new Element();
551 1
		$formElement->init('form', $this->_attributeArray['form']);
552
553
		/* collect output */
554 2
555
		$output .= $formElement->html($this->_html);
556
		$output .= Module\Hook::trigger('formEnd');
557
		return $output;
558
	}
559
560
	/**
561
	 * create the input
562
	 *
563
	 * @since 4.3.0
564
	 *
565 67
	 * @param string $type type of the input
566
	 * @param array|null $attributeArray attributes of the input
567 67
	 *
568 67
	 * @return Element
569 67
	 */
570
571
	protected function _createInput(string $type = 'text', ?array $attributeArray = []) : Element
572
	{
573 67
		if (is_array($attributeArray))
574 67
		{
575 67
			$attributeArray = array_merge($this->_attributeArray['input'][$type], $attributeArray);
576
		}
577
		else
578
		{
579
			$attributeArray = $this->_attributeArray['input'][$type];
580
		}
581
		$inputElement = new Element();
582
		return $inputElement->init('input', $attributeArray);
583
	}
584
585
	/**
586
	 * create the option
587
	 *
588
	 * @since 3.0.0
589 37
	 *
590
	 * @param array $optionArray option of the select
591 37
	 * @param array $selectArray values to be selected
592
	 *
593 20
	 * @return string|null
594
	 */
595
596
	protected function _createOption(array $optionArray = [], array $selectArray = []) : ?string
597 17
	{
598
		$output = null;
599 37
		$optionElement = new Element();
600 37
		$optionElement->init('option');
601
602
		/* process values */
603
604
		foreach ($optionArray as $key => $value)
605
		{
606
			if ($key || $value)
607
			{
608
				$output .= $optionElement
609
					->copy()
610
					->attr(
611
					[
612
						'selected' => is_array($selectArray) && in_array($value, $selectArray) ? 'selected' : null,
613
						'value' => $value
614 10
					])
615
					->text(is_string($key) ? $key : $value);
616 10
			}
617 10
		}
618 10
		return $output;
619
	}
620
621
	/**
622 10
	 * create the button
623
	 *
624 8
	 * @since 4.3.0
625
	 *
626
	 * @param string $type type of the button
627 6
	 * @param string $text text of the button
628 6
	 * @param array|null $attributeArray attributes of the button
629
	 *
630 6
	 * @return Element
631 6
	 */
632
633 6
	protected function _createButton(string $type = null, string $text = null, ?array $attributeArray = []) : Element
634
	{
635
		if (is_array($attributeArray))
636 10
		{
637
			$attributeArray = array_merge($this->_attributeArray['button'][$type], $attributeArray);
638
		}
639
		else
640
		{
641
			$attributeArray = $this->_attributeArray['button'][$type];
642
		}
643
		$buttonElement = new Element();
644
		return $buttonElement
645
			->init('button', $attributeArray)
646
			->text($text ? : $this->_language->get($this->_languageArray['button'][$type]));
647
	}
648
649
	/**
650
	 * append the link
651 6
	 *
652
	 * @since 4.3.0
653 6
	 *
654
	 * @param string $type type of the link
655 3
	 * @param string $text text of the link
656
	 * @param array|null $attributeArray attributes of the link
657
	 *
658
	 * @return Element
659 3
	 */
660
661 6
	protected function _createLink(string $type = null, string $text = null, ?array $attributeArray = []) : Element
662
	{
663 6
		if (is_array($attributeArray))
664 6
		{
665
			$attributeArray = array_merge($this->_attributeArray['link'][$type], $attributeArray);
666
		}
667
		else
668
		{
669
			$attributeArray = $this->_attributeArray['link'][$type];
670
		}
671
		$linkElement = new Element();
672
		return $linkElement
673
			->init('a', $attributeArray)
674
			->text($text ? : $this->_language->get($this->_languageArray['link'][$type]));
675
	}
676
}
677