Passed
Push — 5.x ( bef106...442566 )
by Enjoys
02:41
created

Form::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 18
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 8
c 2
b 0
f 0
dl 0
loc 18
ccs 9
cts 9
cp 1
rs 10
cc 2
nc 2
nop 6
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Enjoys\Forms;
6
7
use Closure;
8
use Enjoys\Forms\Elements\Csrf;
9
use Enjoys\Forms\Interfaces\DefaultsHandlerInterface;
10
use Enjoys\Forms\Traits;
11
use Enjoys\ServerRequestWrapper;
12
use Enjoys\ServerRequestWrapperInterface;
13
use Enjoys\Session\Session;
14
use Enjoys\Traits\Options;
15
use HttpSoft\ServerRequest\ServerRequestCreator;
16
use Webmozart\Assert\Assert;
17
18
use function strtoupper;
19
20
class Form
21
{
22
    use Traits\Attributes;
23
    use Options;
24
    use Traits\Container {
25
        addElement as private parentAddElement;
26
    }
27
28
    private const _ALLOWED_FORM_METHOD_ = ['GET', 'POST'];
29
30
    public const _TOKEN_CSRF_ = '_token_csrf';
31
    public const _TOKEN_SUBMIT_ = '_token_submit';
32
33
    public const ATTRIBUTES_DESC = '_desc_attributes_';
34
    public const ATTRIBUTES_VALIDATE = '_validate_attributes_';
35
    public const ATTRIBUTES_LABEL = '_label_attributes_';
36
    public const ATTRIBUTES_FIELDSET = '_fieldset_attributes_';
37
    public const ATTRIBUTES_FILLABLE_BASE = '_fillable_base_attributes_';
38
39
40
    private string $method = 'POST';
41
    private ?string $action = null;
42
    private ?string $id = null;
43
44
    private ServerRequestWrapperInterface $request;
45
    private DefaultsHandlerInterface $defaultsHandler;
46
47
    private bool $submitted = false;
48
    private Session $session;
49
50
    /**
51
     * @throws Exception\ExceptionRule
52
     */
53 82
    public function __construct(
54
        string $method = 'POST',
55
        string $action = null,
56
        string $id = null,
57
        ServerRequestWrapperInterface $request = null,
58
        DefaultsHandlerInterface $defaultsHandler = null,
59
        Session $session = null
60
    ) {
61 82
        $this->request = $request ?? new ServerRequestWrapper(ServerRequestCreator::createFromGlobals());
62 82
        $this->session = $session ?? new Session();
63 82
        $this->defaultsHandler = $defaultsHandler ?? new DefaultsHandler();
64
65 82
        $this->setMethod($method);
66 82
        $this->setAction($action);
67 82
        $this->setId($id);
68
69 82
        if ($this->submitted === true) {
70 1
            $this->setDefaults([]);
71
        }
72
    }
73
74 1
    private function setSubmitted(bool $submitted): Form
75
    {
76 1
        $this->submitted = $submitted;
77 1
        return $this;
78
    }
79
80
    /**
81
     * Возвращает true если форма отправлена и валидна.
82
     * На валидацию форма проверяется по умолчанию, если использовать параметр $validate
83
     * false, проверка будет только на отправку формы
84
     * @param bool $validate
85
     * @return bool
86
     */
87 5
    public function isSubmitted(bool $validate = true): bool
88
    {
89 5
        if ($this->submitted === false) {
90 2
            return false;
91
        }
92
93 4
        if ($validate !== false) {
94 2
            return Validator::check($this->getElements());
95
        }
96
97 2
        return true;
98
    }
99
100
101
    /**
102
     * @param array|Closure():array $data
103
     * @return $this
104
     */
105 22
    public function setDefaults(array|Closure $data): Form
106
    {
107
108 22
        if ($this->submitted === true) {
109 4
            $data = array_filter(
110 4
                match ($this->getMethod()) {
111 2
                    'GET' => $this->getRequest()->getQueryData()->toArray(),
112 2
                    'POST' => $this->getRequest()->getPostData()->toArray(),
113 4
                    default => [],
114
                },
115 4
                function ($k) {
116 4
                    return !in_array($k, [self::_TOKEN_CSRF_, self::_TOKEN_SUBMIT_]);
117
                },
118
                ARRAY_FILTER_USE_KEY
119
            );
120
        }
121
122 22
        if ($data instanceof Closure) {
0 ignored issues
show
introduced by
$data is never a sub-type of Closure.
Loading history...
123 2
            $data = $data();
124 2
            Assert::isArray($data);
125
        }
126
127 21
        $this->defaultsHandler->setData($data);
128 21
        return $this;
129
    }
130
131
132
    /**
133
     *
134
     * Если prepare() возвращает false, то элемент добавляется,
135
     * если true, то элемент добавлен в коллекцию не будет.
136
     * @use Element::setForm()
137
     * @use Element::prepare()
138
     * @param Element $element
139
     * @return $this
140
     */
141 82
    public function addElement(Element $element): self
142
    {
143 82
        $element->setForm($this);
144 82
        return $this->parentAddElement($element);
145
    }
146
147
148 82
    public function getDefaultsHandler(): DefaultsHandlerInterface
149
    {
150 82
        return $this->defaultsHandler;
151
    }
152
153 82
    public function getRequest(): ServerRequestWrapperInterface
154
    {
155 82
        return $this->request;
156
    }
157
158
    /**
159
     * @throws Exception\ExceptionRule
160
     */
161 82
    public function setMethod(string $method): void
162
    {
163 82
        if (in_array(strtoupper($method), self::_ALLOWED_FORM_METHOD_)) {
164 81
            $this->method = strtoupper($method);
165
        }
166 82
        $this->setAttribute(AttributeFactory::create('method', $this->method));
167 82
        $this->setOption('method', $this->method, false);
168 82
        $this->addElement(new Csrf($this->session));
169 82
        $this->setTokenSubmitElement();
170
    }
171
172 82
    public function getMethod(): string
173
    {
174 82
        return $this->method;
175
    }
176
177 82
    public function setAction(?string $action): self
178
    {
179 82
        $this->action = $action;
180 82
        $this->setAttribute(AttributeFactory::create('action', $this->action));
181 82
        $this->setOption('action', $this->action, false);
182 82
        $this->setTokenSubmitElement();
183 82
        return $this;
184
    }
185
186 5
    public function getAction(): ?string
187
    {
188 5
        return $this->action;
189
    }
190
191 82
    public function setId(?string $id): Form
192
    {
193 82
        $this->id = $id;
194 82
        $this->setAttribute(AttributeFactory::create('id', $this->id));
195 82
        $this->setOption('id', $this->id, false);
196 82
        $this->setTokenSubmitElement();
197 82
        return $this;
198
    }
199
200
201
    public function getId(): ?string
202
    {
203
        return $this->id;
204
    }
205
206 82
    private function setTokenSubmitElement(): void
207
    {
208 82
        $tokenSubmit = new TokenSubmit($this);
209 82
        $this->addElement($tokenSubmit->getElement());
210 82
        $this->submitted = $tokenSubmit->validate();
211
    }
212
213
//    /**
214
//     * Вывод формы в Renderer
215
//     * @param \Enjoys\Forms\Interfaces\RendererInterface $renderer
216
//     * @return mixed Возвращается любой формат, в зависимоти от renderer`а, может
217
//     * вернутся строка в html, или, например, xml или массив, все зависит от рендерера.
218
//     */
219
//    public function render(\Enjoys\Forms\Interfaces\RendererInterface $renderer): mixed
220
//    {
221
//        $renderer->setForm($this);
222
//        return $renderer->output();
223
//    }
224
}
225