Completed
Push — master ( 5d4f5b...d70912 )
by Shcherbak
03:51
created

Form::addError()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

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