Completed
Push — master ( 60d066...9b845d )
by Shcherbak
03:05
created

Form::getUid()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 7
ccs 4
cts 4
cp 1
rs 9.4285
cc 2
eloc 4
nc 2
nop 0
crap 2
1
<?php
2
3
4
  namespace Fiv\Form;
5
6
  use Fiv\Form\Element;
7
  use Fiv\Form\Element\Checkbox;
8
  use Fiv\Form\Element\CheckboxList;
9
  use Fiv\Form\Element\ElementInterface;
10
  use Fiv\Form\Element\RadioList;
11
  use Fiv\Form\Element\Select;
12
  use Fiv\Form\Element\Submit;
13
  use Fiv\Form\Element\TextArea;
14
15
  /**
16
   * @author Ivan Shcherbak <[email protected]>
17
   */
18
  class Form extends Element\Html {
19
20
    /**
21
     * @var null|string
22
     */
23
    protected $uid = null;
24
25
    /**
26
     * @var boolean|null
27
     */
28
    protected $validationResult = null;
29
30
    /**
31
     * @var array
32
     */
33
    protected $errorList = [];
34
35
    /**
36
     * @var bool
37
     */
38
    protected $isSubmitted = false;
39
40
    /**
41
     * @var ElementInterface[]
42
     */
43
    protected $elements = [];
44
45
    /**
46
     * Default form attributes
47
     *
48
     * @var array
49
     */
50
    protected $attributes = [
51
      'method' => 'post',
52
    ];
53
54
55
    /**
56
     * @param $name
57
     * @return $this
58
     */
59 13
    public function setName($name) {
60 13
      $this->uid = $name;
61 13
      $this->attributes['name'] = $name;
62 13
      return $this;
63
    }
64
65
66
    /**
67
     * @param FormData $data
68
     * @return $this
69
     */
70 23
    public function handle(FormData $data) {
71 23
      $this->cleanValidationFlag();
72
73 23
      $this->isSubmitted = false;
74 23
      if ($data->isMethod($this->getMethod()) and $data->has($this->getUid())) {
75 22
        $this->isSubmitted = true;
76 22
        foreach ($this->getElements() as $element) {
77 21
          $element->handle($data);
78
        }
79
80
      }
81
82 23
      return $this;
83
    }
84
85
86
    /**
87
     * @return array
88
     */
89 2
    public function getData() {
90 2
      $data = [];
91 2
      foreach ($this->getElements() as $element) {
92 2
        $data[$element->getName()] = $element->getValue();
93
      }
94 2
      return $data;
95
    }
96
97
98
99
    /**
100
     * @return string
101
     */
102 27
    public function getMethod() {
103 27
      if (!empty($this->attributes['method'])) {
104 27
        return strtolower($this->attributes['method']);
105
      }
106
107 1
      return null;
108
    }
109
110
111
    /**
112
     * @param string $method
113
     * @return $this
114
     */
115 3
    public function setMethod($method) {
116 3
      $this->attributes['method'] = $method;
117
118 3
      return $this;
119
    }
120
121
122
    /**
123
     *
124
     */
125 33
    protected function cleanValidationFlag() {
126 33
      $this->errorList = [];
127 33
      $this->validationResult = null;
128 33
    }
129
130
131
    /**
132
     * Check if form is submitted and all elements are valid
133
     *
134
     * @return boolean
135
     */
136 13
    public function isValid() {
137 13
      if ($this->validationResult !== null) {
138 1
        return $this->validationResult;
139
      }
140
141 13
      if (!$this->isSubmitted()) {
142 2
        return false;
143
      }
144
145 12
      $this->validationResult = true;
146
147 12
      foreach ($this->getElements() as $element) {
148 11
        if ($element->isValid()) {
149 11
          continue;
150
        }
151
152 6
        foreach ($element->getValidatorsErrors() as $errorMessage) {
153 6
          $this->addError($errorMessage);
154
        }
155
      }
156
157 12
      return $this->validationResult;
158
    }
159
160
161
    /**
162
     * @return array
163
     */
164 2
    public function getErrors() {
165 2
      return $this->errorList;
166
    }
167
168
169
    /**
170
     * @param string $error
171
     * @return $this
172
     */
173 7
    protected function addError($error) {
174 7
      if (!is_string($error)) {
175
        throw new \InvalidArgumentException('Error should be a string, ' . gettype($error) . ' given.');
176
      }
177 7
      $this->validationResult = false;
178 7
      $this->errorList[] = $error;
179 7
      return $this;
180
    }
181
182
183
    /**
184
     * Check if form is submitted
185
     *
186
     * @return bool
187
     */
188 16
    public function isSubmitted() {
189 16
      return $this->isSubmitted;
190
    }
191
192
193
    /**
194
     * Return unique id of form
195
     *
196
     * @return string
197
     */
198 27
    public function getUid() {
199 27
      if (empty($this->uid)) {
200 17
        $this->uid = md5(get_called_class());
201
      }
202
203 27
      return $this->uid;
204
    }
205
206
207
    /**
208
     * @return ElementInterface[]
209
     */
210 28
    public function getElements() {
211 28
      return $this->elements;
212
    }
213
214
215
    /**
216
     * @param string $name
217
     * @return ElementInterface
218
     * @throws \InvalidArgumentException
219
     */
220 4
    public function getElement($name) {
221 4
      if (empty($this->elements[$name])) {
222 1
        throw new \InvalidArgumentException('Element with name "' . $name . '" not found');
223
      }
224 3
      return $this->elements[$name];
225
    }
226
227
228
    /**
229
     * Attach element to this form. Overwrite element with same name
230
     *
231
     * @param ElementInterface $element
232
     * @return $this
233
     */
234 2
    public function setElement(ElementInterface $element) {
235 2
      $this->cleanValidationFlag();
236 2
      $this->elements[$element->getName()] = $element;
237 2
      return $this;
238
    }
239
240
241
    /**
242
     * @param ElementInterface $element
243
     * @return $this
244
     * @throws \Exception
245
     */
246 29
    public function addElement(ElementInterface $element) {
247 29
      if (isset($this->elements[$element->getName()])) {
248 1
        throw new \Exception('Element with name ' . $element->getName() . ' is already added. Use setElement to overwrite it or change name');
249
      }
250
251 29
      $this->cleanValidationFlag();
252 29
      $this->elements[$element->getName()] = $element;
253 29
      return $this;
254
    }
255
256
257
    /**
258
     * @param string $name
259
     * @param string|null $text
260
     * @return \Fiv\Form\Element\Input
261
     */
262 13
    public function input($name, $text = null) {
263 13
      $input = new Element\Input();
264 13
      $input->setName($name);
265 13
      $input->setText($text);
266 13
      $this->addElement($input);
267 13
      return $input;
268
    }
269
270
271
    /**
272
     * @param string $name
273
     * @param string|null $text
274
     * @return \Fiv\Form\Element\Input
275
     */
276
    public function password($name, $text = null) {
277
      $input = new Element\Password();
278
      $input->setName($name);
279
      $input->setText($text);
280
      $this->addElement($input);
281
      return $input;
282
    }
283
284
285
    /**
286
     * @param string $name
287
     * @param null $text
288
     * @return Select
289
     */
290
    public function select($name, $text = null) {
291
      $select = new Select();
292
      $select->setName($name);
293
      $select->setText($text);
294
      $this->addElement($select);
295
      return $select;
296
    }
297
298
299
    /**
300
     * @param string $name
301
     * @param string $text
302
     * @return RadioList
303
     */
304
    public function radioList($name, $text = null) {
305
      $radio = new RadioList();
306
      $radio->setName($name);
307
      $radio->setText($text);
308
      $this->addElement($radio);
309
      return $radio;
310
    }
311
312
313
    /**
314
     * @param string $name
315
     * @param null $text
316
     * @return TextArea
317
     */
318 5
    public function textarea($name, $text = null) {
319 5
      $input = new TextArea();
320 5
      $input->setName($name);
321 5
      $input->setText($text);
322 5
      $this->addElement($input);
323 5
      return $input;
324
    }
325
326
327
    /**
328
     * ```
329
     * $form->hidden('key', md5($this-user->id . HASH_A);
330
     * ```
331
     * @param string $name
332
     * @param null $value
333
     * @return \Fiv\Form\Element\Input
334
     */
335 3
    public function hidden($name, $value = null) {
336 3
      $hidden = new  \Fiv\Form\Element\Input();
337 3
      $hidden->setType('hidden');
338 3
      $hidden->setName($name);
339 3
      $hidden->setValue($value);
340 3
      $this->addElement($hidden);
341 3
      return $hidden;
342
    }
343
344
345
    /**
346
     * ```
347
     * $form->submit('register', 'зареєструватись');
348
     * ```
349
     * @param string $name
350
     * @param null $value
351
     * @return Submit
352
     */
353 1
    public function submit($name, $value = null) {
354 1
      $input = new Submit();
355 1
      $input->setName($name);
356 1
      $input->setValue($value);
357 1
      $this->addElement($input);
358 1
      return $input;
359
    }
360
361
362
    /**
363
     * ```
364
     * $form->checkbox('subscribe', 'Підписка на новини');
365
     * ```
366
     * @param string $name
367
     * @param string|null $label
368
     * @return Checkbox
369
     */
370 6
    public function checkbox($name, $label = null) {
371 6
      $checkbox = new Checkbox();
372 6
      $checkbox->setName($name);
373 6
      $checkbox->setLabel($label);
374 6
      $this->addElement($checkbox);
375 6
      return $checkbox;
376
    }
377
378
379
    /**
380
     * @param string $name
381
     * @param null $text
382
     * @return CheckboxList
383
     */
384
    public function checkboxList($name, $text = null) {
385
      $checkbox = new CheckboxList();
386
      $checkbox->setName($name);
387
      $checkbox->setText($text);
388
      $this->addElement($checkbox);
389
      return $checkbox;
390
    }
391
392
393
    /**
394
     * Render full form
395
     *
396
     * @return string
397
     */
398 2
    public function render() {
399 2
      return $this->renderStart() . $this->renderElements() . $this->renderEnd();
400
    }
401
402
403
    /**
404
     * You can easy rewrite this method for custom design of your forms
405
     *
406
     * @return string
407
     */
408 2
    protected function renderElements() {
409 2
      $formHtml = '<dl>';
410
411 2
      foreach ($this->getElements() as $element) {
412
        # skip hidden element
413 1
        if ($element instanceof Element\Input and $element->getType() === 'hidden') {
414
          continue;
415
        }
416
417
        $formHtml .=
418 1
          '<dt>' . $element->getText() . '</dt>' .
419 1
          '<dd>' . $element->render() . '</dd>';
420
      }
421
422 2
      $formHtml .= '</dl>';
423 2
      return $formHtml;
424
    }
425
426
427
    /**
428
     * @return string
429
     */
430 3
    public function renderStart() {
431 3
      $hidden = new Element\Input();
432 3
      $hidden->setType('hidden');
433 3
      $hidden->addAttributes([
434 3
        'name' => $this->getUid(),
435
      ]);
436 3
      $hidden->setValue(1);
437
438
439
      # get default attribute
440 3
      $method = $this->getMethod();
441 3
      $this->setAttribute('method', $method);
442
443 3
      $html = '<form ' . Element\Html::renderAttributes($this->getAttributes()) . '>';
444 3
      $html .= $hidden->render();
445
446
      # render hidden element
447 3
      foreach ($this->getElements() as $element) {
448 2
        if ($element instanceof Element\Input and $element->getType() === 'hidden') {
449 2
          $html .= $element->render();
450
        }
451
      }
452
453
454 3
      return $html;
455
    }
456
457
458
    /**
459
     * @return string
460
     */
461 3
    public function renderEnd() {
462 3
      return '</form>';
463
    }
464
  }