Passed
Push — 5.x ( d855a0...4d7971 )
by Enjoys
02:08
created

Form::addElement()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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