Passed
Push — 3.x ( afbb8c...a19ccf )
by Enjoys
08:15
created

Form::setName()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 5
c 2
b 0
f 0
dl 0
loc 10
ccs 6
cts 6
cp 1
rs 10
cc 2
nc 2
nop 1
crap 2
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
use function json_encode;
36
use function strtoupper;
37
38
/**
39
 *
40
 * Class Forms
41
 *
42
 *
43
 * @author Enjoys
44
 *
45
 */
46
class Form
47
{
48
    use Traits\Attributes;
49
    use Traits\Request;
50
    use Options;
51
    use Traits\Container {
52
        addElement as private parentAddElement;
53
    }
54
55
    /**
56
     * Разрешенные методы формы
57
     */
58
    private const _ALLOWED_FORM_METHOD_ = ['GET', 'POST'];
59
60
    /**
61
     * Название переменной для хранения токена для проверки от аттак CSRF
62
     */
63
    public const _TOKEN_CSRF_ = '_token_csrf';
64
65
    /**
66
     * Название переменной для хранения токена для проверки отправлена форма или нет
67
     */
68
    public const _TOKEN_SUBMIT_ = '_token_submit';
69
    //public const _FLAG_FORMMETHOD_ = '_form_method';
70
    public const ATTRIBUTES_DESC = '_desc_attributes_';
71
    public const ATTRIBUTES_VALIDATE = '_validate_attributes_';
72
    public const ATTRIBUTES_LABEL = '_label_attributes_';
73
    public const ATTRIBUTES_FIELDSET = '_fieldset_attributes_';
74
75
    /**
76
     * @var string|null
77
     */
78
    private ?string $name = null;
79
80
    /**
81
     *
82
     * @var string POST|GET
83
     */
84
    private string $method = 'GET';
85
86
    /**
87
     *
88
     * @var string|null
89
     */
90
    private ?string $action = null;
91
92
    /**
93
     *
94
     * @var DefaultsHandlerInterface
95
     */
96
    private DefaultsHandlerInterface $defaultsHandler;
97
98
    /**
99
     *
100
     * @var bool По умолчанию форма не отправлена
101
     */
102
    private bool $formSubmitted;
103
104
    /**
105
     * @static int Глобальный счетчик форм на странице
106
     * @readonly
107
     * @psalm-allow-private-mutation
108
     */
109
    private static int $formCounter = 0;
110
111
    /**
112
     * @param array $options
113
     * @param ServerRequestInterface|null $request
114
     * @param DefaultsHandlerInterface|null $defaults
115
     * @example example/initform.php description
116
     */
117 77
    public function __construct(array $options = [], ServerRequestInterface $request = null, DefaultsHandlerInterface $defaults = null)
118
    {
119 77
        $this->defaultsHandler = $defaults ?? new DefaultsHandler();
120 77
        $this->setRequest($request);
121
122 77
        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...
123
124
125
126 77
        $tockenSubmit = $this->tockenSubmit(md5(json_encode($options) . $this->getFormCounter()));
0 ignored issues
show
Bug introduced by
The method tockenSubmit() does not exist on Enjoys\Forms\Form. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

126
        /** @scrutinizer ignore-call */ 
127
        $tockenSubmit = $this->tockenSubmit(md5(json_encode($options) . $this->getFormCounter()));
Loading history...
127 77
        $this->formSubmitted = $tockenSubmit->getSubmitted();
0 ignored issues
show
Bug introduced by
The method getSubmitted() does not exist on Enjoys\Forms\Element. It seems like you code against a sub-type of Enjoys\Forms\Element such as Enjoys\Forms\Elements\Group or Enjoys\Forms\Elements\TockenSubmit. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

127
        /** @scrutinizer ignore-call */ 
128
        $this->formSubmitted = $tockenSubmit->getSubmitted();
Loading history...
128
129 77
        if ($this->formSubmitted === true) {
130 2
            $this->setDefaults([]);
131
        }
132
133 77
        $this->setOptions($options);
134 77
    }
135
136 66
    public function __destruct()
137
    {
138 66
        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...
139 66
    }
140
141 77
    public function getFormCounter(): int
142
    {
143 77
        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...
144
    }
145
146
    /**
147
     * Устанавливает метод формы, заодно пытается установить защиту от CSRF аттак,
148
     * если она требуется
149
     * @param string|null $method
150
     * @return void
151
     */
152 19
    public function setMethod(?string $method = null): void
153
    {
154 19
        if (is_null($method)) {
155 1
            $this->removeAttribute('method');
156 1
            return;
157
        }
158 18
        if (in_array(strtoupper($method), self::_ALLOWED_FORM_METHOD_)) {
159 17
            $this->method = strtoupper($method);
160
        }
161 18
        $this->setAttribute('method', $this->method);
162
163 18
        $this->csrf();
0 ignored issues
show
Bug introduced by
The method csrf() does not exist on Enjoys\Forms\Form. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

163
        $this->/** @scrutinizer ignore-call */ 
164
               csrf();
Loading history...
164 18
    }
165
166
    /**
167
     * Получение метода формы
168
     * @return string GET|POST
169
     */
170 19
    public function getMethod(): string
171
    {
172 19
        return $this->method;
173
    }
174
175
    /**
176
     * Получение аттрибута action формы
177
     * @return string|null
178
     */
179 5
    public function getAction(): ?string
180
    {
181 5
        return $this->action;
182
    }
183
184
    /**
185
     * Установка аттрибута action формы
186
     * @param string|null $action
187
     * @return $this
188
     */
189 5
    protected function setAction(?string $action = null): self
190
    {
191 5
        $this->action = $action;
192
193 5
        $this->setAttribute('action', $this->getAction());
194
195 5
        if (is_null($action)) {
196 4
            $this->removeAttribute('action');
197
        }
198
199 5
        return $this;
200
    }
201
202
    /**
203
     * Set \Enjoys\Forms\DefaultsHandlerInterface $defaultsHandler
204
     * @param array $data
205
     * @return $this
206
     */
207 18
    public function setDefaults(array $data): self
208
    {
209
210 18
        if ($this->formSubmitted === true) {
211 3
            $data = [];
212 3
            $method = $this->getRequest()->getMethod();
213 3
            foreach ($this->getRequest()->$method() as $key => $items) {
214 3
                if (in_array($key, [self::_TOKEN_CSRF_, self::_TOKEN_SUBMIT_])) {
215 1
                    continue;
216
                }
217 3
                $data[$key] = $items;
218
            }
219
        }
220 18
        $this->defaultsHandler->setData($data);
221 18
        return $this;
222
    }
223
224
    /**
225
     * @return DefaultsHandlerInterface
226
     */
227 77
    public function getDefaultsHandler(): DefaultsHandlerInterface
228
    {
229
230 77
        return $this->defaultsHandler;
231
    }
232
233
    /**
234
     * Получение имени формы
235
     * @return string|null
236
     */
237 1
    public function getName(): ?string
238
    {
239 1
        return $this->name;
240
    }
241
242
    /**
243
     * Установка аттрибута формы name
244
     * @param string|null $name
245
     * @return $this
246
     */
247 1
    protected function setName(?string $name = null): self
248
    {
249 1
        $this->name = $name;
250 1
        $this->setAttribute('name', $this->name);
251
252 1
        if (is_null($name)) {
253 1
            $this->removeAttribute('name');
254
        }
255
256 1
        return $this;
257
    }
258
259
    /**
260
     * Возвращает true если форма отправлена и валидна.
261
     * На валидацию форма проверяется по умолчанию, усли использовать параметр $validate
262
     * false, проверка будет только на отправку формы
263
     * @param bool $validate
264
     * @return bool
265
     */
266 4
    public function isSubmitted($validate = true): bool
267
    {
268
//        return $this->formSubmitted;
269 4
        if (!$this->formSubmitted) {
270 1
            return false;
271
        }
272
        //  dump($this->getElements());
273 3
        if ($validate !== false) {
274 2
            return Validator::check($this->getElements());
275
        }
276
277 1
        return true;
278
    }
279
280
    /**
281
     *
282
     * Если prepare() ничего не возвращает (NULL), то элемент добавляется,
283
     * если что-то вернула фунция, то элемент добален в коллекцию не будет.
284
     * @use Element::setForm()
285
     * @use Element::prepare()
286
     * @param Element $element
287
     * @return $this
288
     */
289 77
    public function addElement(Element $element): self
290
    {
291 77
        $element->setForm($this);
292 77
        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 false.
Loading history...
293 8
            return $this;
294
        }
295 77
        return $this->parentAddElement($element);
296
    }
297
298
    /**
299
     * Вывод формы в Renderer
300
     * @param RendererInterface $renderer
301
     * @return mixed Возвращается любой формат, в зависимоти от renderer`а, может
302
     * вернутся строка в html, или, например, xml или массив, все зависит от рендерера.
303
     */
304
    public function render(Renderer\RendererInterface $renderer)
305
    {
306
        $renderer->setForm($this);
307
        return $renderer->render();
308
    }
309
310
311
}
312
313
314