Test Failed
Push — validate-by-validator ( a015d2 )
by Dmitriy
03:11
created

Form::begin()   B

Complexity

Conditions 8
Paths 8

Size

Total Lines 40
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 20
c 0
b 0
f 0
nc 8
nop 0
dl 0
loc 40
rs 8.4444
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Form\Widget;
6
7
use Yiisoft\Arrays\ArrayHelper;
8
use Yiisoft\Html\Html;
9
use Yiisoft\Http\Method;
10
use Yiisoft\Widget\Widget;
11
12
use function explode;
13
use function implode;
14
use function strcasecmp;
15
use function strpos;
16
use function substr;
17
use function urldecode;
18
19
/**
20
 * A widget for rendering a form
21
 */
22
final class Form extends Widget
23
{
24
    private string $action = '';
25
    private string $method = Method::POST;
26
    private array $options = [];
27
28
    /**
29
     * Generates a form start tag.
30
     *
31
     * @throws \JsonException
32
     *
33
     * @return string the generated form start tag.
34
     *
35
     * {@see end())}
36
     */
37
    public function begin(): ?string
38
    {
39
        parent::begin();
40
41
        $hiddenInputs = [];
42
43
        $csrfToken = ArrayHelper::remove($this->options, 'csrf', false);
44
45
        if ($csrfToken && strcasecmp($this->method, Method::POST) === 0) {
46
            $hiddenInputs[] = Html::hiddenInput('_csrf', $csrfToken);
47
        }
48
49
        if (!strcasecmp($this->method, 'get') && ($pos = strpos($this->action, '?')) !== false) {
50
            /**
51
             * Query parameters in the action are ignored for GET method we use hidden fields to add them back.
52
             */
53
            foreach (explode('&', substr($this->action, $pos + 1)) as $pair) {
54
                if (($pos1 = strpos($pair, '=')) !== false) {
55
                    $hiddenInputs[] = Html::hiddenInput(
56
                        urldecode(substr($pair, 0, $pos1)),
57
                        urldecode(substr($pair, $pos1 + 1))
58
                    );
59
                } else {
60
                    $hiddenInputs[] = Html::hiddenInput(urldecode($pair), '');
61
                }
62
            }
63
64
            $this->action = substr($this->action, 0, $pos);
65
        }
66
67
        $this->options['action'] = $this->action;
68
        $this->options['method'] = $this->method;
69
70
        $form = Html::beginTag('form', $this->options);
71
72
        if (!empty($hiddenInputs)) {
73
            $form .= "\n" . implode("\n", $hiddenInputs);
74
        }
75
76
        return $form;
77
    }
78
79
    /**
80
     * Generates a form end tag.
81
     *
82
     * @return string the generated tag.
83
     *
84
     * {@see beginForm()}
85
     */
86
    public function run(): string
87
    {
88
        return '</form>';
89
    }
90
91
    public function action(string $value): self
92
    {
93
        $new = clone $this;
94
        $new->action = $value;
95
        return $new;
96
    }
97
98
    public function method(string $value): self
99
    {
100
        $new = clone $this;
101
        $new->method = $value;
102
        return $new;
103
    }
104
105
    public function options(array $value = []): self
106
    {
107
        $new = clone $this;
108
        $new->options = $value;
109
        return $new;
110
    }
111
}
112