Completed
Pull Request — master (#24)
by Vitaliy
03:05
created

Form::submit()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 7
ccs 6
cts 6
cp 1
rs 9.4285
cc 1
eloc 6
nc 1
nop 2
crap 1
1
<?php
2
3
4
  namespace Fiv\Form;
5
6
  use Fiv\Form\Element;
7
  use Fiv\Form\Element\Checkbox;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Fiv\Form\Checkbox.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
8
  use Fiv\Form\Element\CheckboxList;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Fiv\Form\CheckboxList.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
9
  use Fiv\Form\Element\Submit;
10
  use Fiv\Form\Element\TextArea;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Fiv\Form\TextArea.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

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