Test Failed
Push — master ( ecdde5...dd7a53 )
by Enjoys
06:21
created

Form::getName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 1
c 2
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
/*
4
 * The MIT License
5
 *
6
 * Copyright 2020 Enjoys.
7
 *
8
 * Permission is hereby granted, free of charge, to any person obtaining a copy
9
 * of this software and associated documentation files (the "Software"), to deal
10
 * in the Software without restriction, including without limitation the rights
11
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
 * copies of the Software, and to permit persons to whom the Software is
13
 * furnished to do so, subject to the following conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be included in
16
 * all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
 * THE SOFTWARE.
25
 */
26
27
declare(strict_types=1);
28
29
namespace Enjoys\Forms;
30
31
use Enjoys\Forms\Renderer\RendererInterface;
32
use Enjoys\Forms\Traits;
33
use Enjoys\Http\ServerRequestInterface;
34
use Enjoys\Traits\Options;
35
36
use function json_encode;
37
use function strtoupper;
38
39
/**
40
 *
41
 * Class Forms
42
 *
43
 *
44
 * @author Enjoys
45
 *
46
 */
47
class Form
48
{
49
    use Traits\Attributes;
50
    use Traits\Request;
51
    use Options;
52
    use Traits\Container {
53
        addElement as private parentAddElement;
54
    }
55
56
    /**
57
     * Разрешенные методы формы
58
     */
59
    private const _ALLOWED_FORM_METHOD_ = ['GET', 'POST'];
60
61
    /**
62
     * Название переменной для хранения токена для проверки от аттак CSRF
63
     */
64
    public const _TOKEN_CSRF_ = '_token_csrf';
65
66
    /**
67
     * Название переменной для хранения токена для проверки отправлена форма или нет
68
     */
69
    public const _TOKEN_SUBMIT_ = '_token_submit';
70
    //public const _FLAG_FORMMETHOD_ = '_form_method';
71
    public const ATTRIBUTES_DESC = '_desc_attributes_';
72
    public const ATTRIBUTES_VALIDATE = '_validate_attributes_';
73
    public const ATTRIBUTES_LABEL = '_label_attributes_';
74
    public const ATTRIBUTES_FIELDSET = '_fieldset_attributes_';
75
76
    /**
77
     * @var string|null
78
     */
79
    private ?string $name = null;
80
81
    /**
82
     *
83
     * @var string POST|GET
84
     */
85
    private string $method = 'GET';
86
87
    /**
88
     *
89
     * @var string|null
90
     */
91
    private ?string $action = null;
92
93
    /**
94
     *
95
     * @var DefaultsHandlerInterface
96
     */
97
    private DefaultsHandlerInterface $defaultsHandler;
98
99
    /**
100
     *
101
     * @var bool По умолчанию форма не отправлена
102
     */
103
    private bool $formSubmitted;
104
105
    /**
106
     * @static int Глобальный счетчик форм на странице
107
     * @readonly
108
     * @psalm-allow-private-mutation
109
     */
110
    private static int $formCounter = 0;
111
112
    /**
113
     * @param array $options
114
     * @param ServerRequestInterface|null $request
115
     * @param DefaultsHandlerInterface|null $defaults
116
     * @example example/initform.php description
117
     */
118 80
    public function __construct(array $options = [], ServerRequestInterface $request = null, DefaultsHandlerInterface $defaults = null)
119
    {
120 80
        $this->defaultsHandler = $defaults ?? new DefaultsHandler();
121 80
        $this->setRequest($request);
122
123 80
        static::$formCounter++;
0 ignored issues
show
Bug introduced by
Since $formCounter is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $formCounter to at least protected.
Loading history...
124
125
126
127 80
        $tockenSubmit = $this->tockenSubmit(md5(json_encode($options) . $this->getFormCounter()));
128 80
        $this->formSubmitted = $tockenSubmit->getSubmitted();
129
130 80
        if ($this->formSubmitted === true) {
131 3
            $this->setDefaults([]);
132
        }
133
134 80
        $this->setOptions($options);
135 80
    }
136
137 68
    public function __destruct()
138
    {
139 68
        static::$formCounter = 0;
0 ignored issues
show
Bug introduced by
Since $formCounter is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $formCounter to at least protected.
Loading history...
140 68
    }
141
142 80
    public function getFormCounter(): int
143
    {
144 80
        return static::$formCounter;
0 ignored issues
show
Bug introduced by
Since $formCounter is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $formCounter to at least protected.
Loading history...
145
    }
146
147
    /**
148
     * Устанавливает метод формы, заодно пытается установить защиту от CSRF аттак,
149
     * если она требуется
150
     * @param string|null $method
151
     * @return void
152
     */
153 20
    public function setMethod(?string $method = null): void
154
    {
155 20
        if (is_null($method)) {
156 1
            $this->removeAttribute('method');
157 1
            return;
158
        }
159 19
        if (in_array(strtoupper($method), self::_ALLOWED_FORM_METHOD_)) {
160 18
            $this->method = strtoupper($method);
161
        }
162 19
        $this->setAttribute('method', $this->method);
163
164 19
        $this->csrf();
165 19
    }
166
167
    /**
168
     * Получение метода формы
169
     * @return string GET|POST
170
     */
171 20
    public function getMethod(): string
172
    {
173 20
        return $this->method;
174
    }
175
176
    /**
177
     * Получение аттрибута action формы
178
     * @return string|null
179
     */
180 5
    public function getAction(): ?string
181
    {
182 5
        return $this->action;
183
    }
184
185
    /**
186
     * Установка аттрибута action формы
187
     * @param string|null $action
188
     * @return $this
189
     */
190 5
    protected function setAction(?string $action = null): self
191
    {
192 5
        $this->action = $action;
193
194 5
        $this->setAttribute('action', $this->getAction());
195
196 5
        if (is_null($action)) {
197 4
            $this->removeAttribute('action');
198
        }
199
200 5
        return $this;
201
    }
202
203
    /**
204
     * Set \Enjoys\Forms\DefaultsHandlerInterface $defaultsHandler
205
     * @param \Closure|array $data
206
     * @return $this
207
     */
208 21
    public function setDefaults($data): self
209
    {
210 21
        if($data instanceof \Closure){
211 1
            $data = $data();
212
        }
213
214 21
        if(!is_array($data)){
215 1
            throw new \InvalidArgumentException('Invalid argument, expected array or closure with retun array.');
216
        }
217
218 20
        if ($this->formSubmitted === true) {
219 4
            $data = [];
220 4
            $method = $this->getRequest()->getMethod();
221 4
            foreach ($this->getRequest()->$method() as $key => $items) {
222 4
                if (in_array($key, [self::_TOKEN_CSRF_, self::_TOKEN_SUBMIT_])) {
223 1
                    continue;
224
                }
225 4
                $data[$key] = $items;
226
            }
227
        }
228 20
        $this->defaultsHandler->setData($data);
229 20
        return $this;
230
    }
231
232
    /**
233
     * @return DefaultsHandlerInterface
234
     */
235 80
    public function getDefaultsHandler(): DefaultsHandlerInterface
236
    {
237
238 80
        return $this->defaultsHandler;
239
    }
240
241
    /**
242
     * Получение имени формы
243
     * @return string|null
244
     */
245 1
    public function getName(): ?string
246
    {
247 1
        return $this->name;
248
    }
249
250
    /**
251
     * Установка аттрибута формы name
252
     * @param string|null $name
253
     * @return $this
254
     */
255 1
    protected function setName(?string $name = null): self
256
    {
257 1
        $this->name = $name;
258 1
        $this->setAttribute('name', $this->name);
259
260 1
        if (is_null($name)) {
261 1
            $this->removeAttribute('name');
262
        }
263
264 1
        return $this;
265
    }
266
267
    /**
268
     * Возвращает true если форма отправлена и валидна.
269
     * На валидацию форма проверяется по умолчанию, усли использовать параметр $validate
270
     * false, проверка будет только на отправку формы
271
     * @param bool $validate
272
     * @return bool
273
     */
274 4
    public function isSubmitted($validate = true): bool
275
    {
276
//        return $this->formSubmitted;
277 4
        if (!$this->formSubmitted) {
278 1
            return false;
279
        }
280
        //  dump($this->getElements());
281 3
        if ($validate !== false) {
282 2
            return Validator::check($this->getElements());
283
        }
284
285 1
        return true;
286
    }
287
288
    /**
289
     *
290
     * Если prepare() ничего не возвращает (NULL), то элемент добавляется,
291
     * если что-то вернула фунция, то элемент добален в коллекцию не будет.
292
     * @use Element::setForm()
293
     * @use Element::prepare()
294
     * @param Element $element
295
     * @return $this
296
     */
297 80
    public function addElement(Element $element): self
298
    {
299 80
        $element->setForm($this);
300 80
        if ($element->prepare() !== null) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of $element->prepare() targeting Enjoys\Forms\Element::prepare() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
introduced by
The condition $element->prepare() !== null is always true.
Loading history...
301 8
            return $this;
302
        }
303 80
        return $this->parentAddElement($element);
304
    }
305
306
    /**
307
     * Вывод формы в Renderer
308
     * @param RendererInterface $renderer
309
     * @return mixed Возвращается любой формат, в зависимоти от renderer`а, может
310
     * вернутся строка в html, или, например, xml или массив, все зависит от рендерера.
311
     */
312
    public function render(Renderer\RendererInterface $renderer)
313
    {
314
        $renderer->setForm($this);
315
        return $renderer->render();
316
    }
317
318
319
}
320
321
322