Passed
Push — master ( 68d467...3da7f9 )
by Mikael
02:33
created

Form   D

Complexity

Total Complexity 107

Size/Duplication

Total Lines 768
Duplicated Lines 5.99 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 23.86%

Importance

Changes 0
Metric Value
dl 46
loc 768
ccs 84
cts 352
cp 0.2386
rs 4.4444
c 0
b 0
f 0
wmc 107
lcom 1
cbo 2

22 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A offsetSet() 5 8 2
A offsetExists() 0 4 1
A offsetUnset() 0 4 1
A offsetGet() 0 6 2
A create() 0 48 3
A addElement() 0 9 2
A getElement() 7 7 2
A removeElement() 8 8 2
A setValidation() 0 5 1
A addOutput() 0 17 3
A setOutputClass() 0 9 1
A rememberValues() 0 5 1
A value() 0 6 2
A checked() 0 6 2
F getHTML() 0 55 12
B getHTMLForElements() 0 38 6
C getHTMLLayoutForElements() 0 48 8
A getValidationErrors() 0 14 3
B getOutput() 0 15 6
D initElements() 0 41 10
F check() 26 188 36

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Form often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Form, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Anax\HTMLForm;
4
5
use \Anax\DI\DIInterface;
6
7
/**
8
 * A utility class to easy creating and handling of forms
9
 */
10
class Form implements \ArrayAccess
11
{
12
    /**
13
     * @var array $form       settings for the form
14
     * @var array $elements   all form elements
15
     * @var array $output     messages to display together with the form
16
     * @var array $sessionKey key values for the session
17
     */
18
    protected $form;
19
    protected $elements;
20
    protected $output;
21
    protected $sessionKey;
22
23
    /**
24
     * @var boolean $rememberValues remember values in the session.
25
     */
26
    protected $rememberValues;
27
28
    /**
29
     * @var Anax\DI\DIInterface $di the DI service container.
30
     */
31
    protected $di;
32
33
34
35
    /**
36
     * Constructor injects with DI container.
37
     *
38
     * @param Anax\DI\DIInterface $di a service container
39
     */
40 2
    public function __construct(DIInterface $di)
41
    {
42 2
        $this->di = $di;
0 ignored issues
show
Documentation Bug introduced by
It seems like $di of type object<Anax\DI\DIInterface> is incompatible with the declared type object<Anax\HTMLForm\Anax\DI\DIInterface> of property $di.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
43 2
    }
44
45
46
47
    /**
48
     * Implementing ArrayAccess for this->elements
49
     */
50
    public function offsetSet($offset, $value)
51
    {
52 View Code Duplication
        if (is_null($offset)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
53
            $this->elements[] = $value;
54
        } else {
55
            $this->elements[$offset] = $value;
56
        }
57
    }
58
    
59
    public function offsetExists($offset)
60
    {
61
        return isset($this->elements[$offset]);
62
    }
63
    
64
    public function offsetUnset($offset)
65
    {
66
        unset($this->elements[$offset]);
67
    }
68
    
69
    public function offsetGet($offset)
70
    {
71
        return isset($this->elements[$offset])
72
            ? $this->elements[$offset]
73
            : null;
74
    }
75
76
77
78
    /**
79
     * Add a form element
80
     *
81
     * @param array $form     details for the form
82
     * @param array $elements all the elements
83
     *
84
     * @return $this
85
     */
86 2
    public function create($form = [], $elements = [])
87
    {
88
        $defaults = [
89
            // Always have an id
90 2
            "id" => "anax/htmlform",
91
92
            // Use a default class on <form> to ease styling
93 2
            "class" => "htmlform",
94
95
            // Wrap fields within <fieldset>
96 2
            "use_fieldset"  => true,
97
98
            // Use legend for fieldset, set it to string value
99 2
            "legend"        => null,
100
101
            // Default wrapper element around form elements
102 2
            "wrapper-element" => "p",
103
104
            // Use a <br> after the label, where suitable
105 2
            "br-after-label" => true,
106 2
        ];
107 2
        $this->form = array_merge($defaults, $form);
108
109 2
        $this->elements = [];
110 2
        if (!empty($elements)) {
111
            foreach ($elements as $key => $element) {
112
                $this->elements[$key] = FormElementFactory::create($key, $element);
113
                $this->elements[$key]->setDefault([
114
                    "wrapper-element" => $this->form["wrapper-element"],
115
                    "br-after-label"  => $this->form["br-after-label"],
116
                ]);
117
            }
118
        }
119
120
        // Default values for <output>
121 2
        $this->output = [];
122
123
        // Setting keys used in the session
124 2
        $generalKey = "anax/htmlform-" . $this->form["id"] . "#";
125 2
        $this->sessionKey = [
126 2
            "save"      => $generalKey . "save",
127 2
            "output"    => $generalKey . "output",
128 2
            "failed"    => $generalKey . "failed",
129 2
            "remember"  => $generalKey . "remember",
130
        ];
131
132 2
        return $this;
133
    }
134
135
136
137
    /**
138
     * Add a form element
139
     *
140
     * @param FormElement $element the formelement to add.
141
     *
142
     * @return $this
143
     */
144
    public function addElement($element)
145
    {
146
        $name = $element;
147
        if (isset($this->elements[$name])) {
148
            throw new Exception("Form element '$name' already exists, do not add it twice.");
149
        }
150
        $this[$element['name']] = $name;
151
        return $this;
152
    }
153
154
155
156
    /**
157
     * Get a form element
158
     *
159
     * @param string $name the name of the element.
160
     *
161
     * @return \Anax\HTMLForm\FormElement
162
     */
163 View Code Duplication
    public function getElement($name)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
164
    {
165
        if (!isset($this->elements[$name])) {
166
            throw new Exception("Form element '$name' is not found.");
167
        }
168
        return $this->elements[$name];
169
    }
170
171
172
173
    /**
174
     * Remove an form element
175
     *
176
     * @param string $name the name of the element.
177
     *
178
     * @return $this
179
     */
180 View Code Duplication
    public function removeElement($name)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
181
    {
182
        if (!isset($this->elements[$name])) {
183
            throw new Exception("Form element '$name' is not found.");
184
        }
185
        unset($this->elements[$name]);
186
        return $this;
187
    }
188
189
190
191
    /**
192
     * Set validation to a form element
193
     *
194
     * @param string $element the name of the formelement to add validation rules to.
195
     * @param array  $rules   array of validation rules.
196
     *
197
     * @return $this
198
     */
199
    public function setValidation($element, $rules)
200
    {
201
        $this[$element]['validation'] = $rules;
202
        return $this;
203
    }
204
205
206
207
    /**
208
     * Add output to display to the user for what happened whith the form and
209
     * optionally add a CSS class attribute.
210
     *
211
     * @param string $str   the string to add as output.
212
     * @param string $class a class attribute to set.
213
     *
214
     * @return $this.
0 ignored issues
show
Documentation introduced by
The doc-type $this. could not be parsed: Unknown type name "$this." at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
215
     */
216
    public function addOutput($str, $class = null)
217
    {
218
        $key     = $this->sessionKey["output"];
219
        $session = $this->di->get("session");
220
        $output  = $session->get($key);
221
222
        $output["message"] = isset($output["message"])
223
            ? $output["message"] . " $str"
224
            : $str;
225
226
        if ($class) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $class of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
227
            $output["class"] = $class;
228
        }
229
        $session->set($key, $output);
230
231
        return $this;
232
    }
233
234
235
236
    /**
237
     * Set a CSS class attribute for the <output> element.
238
     *
239
     * @param string $class a class attribute to set.
240
     *
241
     * @return $this.
0 ignored issues
show
Documentation introduced by
The doc-type $this. could not be parsed: Unknown type name "$this." at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
242
     */
243
    public function setOutputClass($class)
244
    {
245
        $key     = $this->sessionKey["output"];
246
        $session = $this->di->get("session");
247
        $output  = $session->get($key);
248
        $output["class"] = $class;
249
        $session->set($key, $output);
250
        return $this;
251
    }
252
253
254
255
    /**
256
     * Remember current values in session, useful for storing values of
257
     * current form when submitting it.
258
     *
259
     * @return $this.
0 ignored issues
show
Documentation introduced by
The doc-type $this. could not be parsed: Unknown type name "$this." at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
260
     */
261
    public function rememberValues()
262
    {
263
        $this->rememberValues = true;
264
        return $this;
265
    }
266
267
268
269
270
    /**
271
     * Get value of a form element
272
     *
273
     * @param string $name the name of the formelement.
274
     *
275
     * @return mixed the value of the element.
276
     */
277
    public function value($name)
278
    {
279
        return isset($this->elements[$name])
280
            ? $this->elements[$name]->value()
281
            : null;
282
    }
283
284
285
286
    /**
287
     * Check if a element is checked
288
     *
289
     * @param string $name the name of the formelement.
290
     *
291
     * @return mixed the value of the element.
292
     */
293
    public function checked($name)
294
    {
295
        return isset($this->elements[$name])
296
            ? $this->elements[$name]->checked()
297
            : null;
298
    }
299
300
301
302
    /**
303
     * Return HTML for the form.
304
     *
305
     * @param array $options with options affecting the form output.
306
     *
307
     * @return string with HTML for the form.
308
     */
309 2
    public function getHTML($options = [])
310
    {
311
        $defaults = [
312
            // Only return the start of the form element
313 2
            'start'         => false,
314
            
315
            // Layout all elements in one column
316 2
            'columns'       => 1,
317
            
318
            // Layout consequtive buttons as one element wrapped in <p>
319 2
            'use_buttonbar' => true,
320 2
        ];
321 2
        $options = array_merge($defaults, $options);
322
323 2
        $form = array_merge($this->form, $options);
324 2
        $id      = isset($form['id'])      ? " id='{$form['id']}'" : null;
325 2
        $class   = isset($form['class'])   ? " class='{$form['class']}'" : null;
326 2
        $name    = isset($form['name'])    ? " name='{$form['name']}'" : null;
327 2
        $action  = isset($form['action'])  ? " action='{$form['action']}'" : null;
328 2
        $method  = isset($form['method'])  ? " method='{$form['method']}'" : " method='post'";
329 2
        $enctype = isset($form['enctype']) ? " enctype='{$form['enctype']}'" : null;
330 2
        $cformId = isset($form['id'])      ? "{$form['id']}" : null;
331
332 2
        if ($options['start']) {
333
            return "<form{$id}{$class}{$name}{$action}{$method}>\n";
334
        }
335
336 2
        $fieldsetStart  = '<fieldset>';
337 2
        $legend         = null;
338 2
        $fieldsetEnd    = '</fieldset>';
339 2
        if (!$form['use_fieldset']) {
340
            $fieldsetStart = $fieldsetEnd = null;
341
        }
342
343 2
        if ($form['use_fieldset'] && $form['legend']) {
344
            $legend = "<legend>{$form['legend']}</legend>";
345
        }
346
347 2
        $elementsArray  = $this->getHTMLForElements($options);
348 2
        $elements       = $this->getHTMLLayoutForElements($elementsArray, $options);
349 2
        $output         = $this->getOutput();
350
351
        $html = <<< EOD
352 2
\n<form{$id}{$class}{$name}{$action}{$method}{$enctype}>
353 2
<input type="hidden" name="anax/htmlform-id" value="$cformId" />
354 2
{$fieldsetStart}
355 2
{$legend}
356 2
{$elements}
357 2
{$output}
358 2
{$fieldsetEnd}
359 2
</form>\n
360 2
EOD;
361
362 2
        return $html;
363
    }
364
365
366
367
    /**
368
     * Return HTML for the elements
369
     *
370
     * @param array $options with options affecting the form output.
371
     *
372
     * @return array with HTML for the formelements.
373
     */
374 2
    public function getHTMLForElements($options = [])
375
    {
376
        $defaults = [
377 2
            'use_buttonbar' => true,
378 2
        ];
379 2
        $options = array_merge($defaults, $options);
380
381 2
        $elements = array();
382 2
        reset($this->elements);
383 2
        while (list($key, $element) = each($this->elements)) {
0 ignored issues
show
Unused Code introduced by
The assignment to $key is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
384
            if (in_array($element['type'], array('submit', 'reset', 'button'))
385
                && $options['use_buttonbar']
386
            ) {
387
                // Create a buttonbar
388
                $name = 'buttonbar';
389
                $html = "<p class='buttonbar'>\n" . $element->GetHTML() . '&nbsp;';
390
391
                // Get all following submits (and buttons)
392
                while (list($key, $element) = each($this->elements)) {
0 ignored issues
show
Unused Code introduced by
The assignment to $key is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
393
                    if (in_array($element['type'], array('submit', 'reset', 'button'))) {
394
                        $html .= $element->GetHTML();
395
                    } else {
396
                        prev($this->elements);
397
                        break;
398
                    }
399
                }
400
                $html .= "\n</p>";
401
            } else {
402
                // Just add the element
403
                $name = $element['name'];
404
                $html = $element->GetHTML();
405
            }
406
407
            $elements[] = array('name'=>$name, 'html'=> $html);
408
        }
409
410 2
        return $elements;
411
    }
412
413
414
415
416
    /**
417
     * Place the elements according to a layout and return the HTML
418
     *
419
     * @param array $elements as returned from GetHTMLForElements().
420
     * @param array $options  with options affecting the layout.
421
     *
422
     * @return array with HTML for the formelements.
423
     */
424 2
    public function getHTMLLayoutForElements($elements, $options = [])
425
    {
426
        $defaults = [
427 2
            'columns' => 1,
428 2
            'wrap_at_element' => false,  // Wraps column in equal size or at the set number of elements
429 2
        ];
430 2
        $options = array_merge($defaults, $options);
431
432 2
        $html = null;
433 2
        if ($options['columns'] === 1) {
434 2
            foreach ($elements as $element) {
435
                $html .= $element['html'];
436 2
            }
437 2
        } elseif ($options['columns'] === 2) {
438
            $buttonbar = null;
439
            $col1 = null;
440
            $col2 = null;
441
442
            $end = end($elements);
443
            if ($end['name'] == 'buttonbar') {
444
                $end = array_pop($elements);
445
                $buttonbar = "<div class='cform-buttonbar'>\n{$end['html']}</div>\n";
446
            }
447
448
            $size = count($elements);
449
            $wrapAt = $options['wrap_at_element'] ? $options['wrap_at_element'] : round($size/2);
450
            for ($i=0; $i<$size; $i++) {
451
                if ($i < $wrapAt) {
452
                    $col1 .= $elements[$i]['html'];
453
                } else {
454
                    $col2 .= $elements[$i]['html'];
455
                }
456
            }
457
458
            $html = <<<EOD
459
<div class='cform-columns-2'>
460
<div class='cform-column-1'>
461
{$col1}
462
</div>
463
<div class='cform-column-2'>
464
{$col2}
465
</div>
466
{$buttonbar}</div>
467
EOD;
468
        }
469
470 2
        return $html;
471
    }
472
473
474
475
    /**
476
     * Get an array with all elements that failed validation together with their id and validation message.
477
     *
478
     * @return array with elements that failed validation.
479
     */
480
    public function getValidationErrors()
481
    {
482
        $errors = [];
483
        foreach ($this->elements as $name => $element) {
484
            if ($element['validation-pass'] === false) {
485
                $errors[$name] = [
486
                    'id' => $element->GetElementId(),
487
                    'label' => $element['label'],
488
                    'message' => implode(' ', $element['validation-messages'])
489
                ];
490
            }
491
        }
492
        return $errors;
493
    }
494
495
496
497
    /**
498
     * Get output messages as <output>.
499
     *
500
     * @return string|null with the complete <output> element or null if no output.
501
     */
502 2
    public function getOutput()
503
    {
504 2
        $output = $this->output;
505 2
        $message = isset($output["message"]) && !empty($output["message"])
506 2
            ? $output["message"]
507 2
            : null;
508
509 2
        $class = isset($output["class"]) && !empty($output["class"])
510 2
            ? " class=\"{$output["class"]}\""
511 2
            : null;
512
513
        return $message
514 2
            ? "<output{$class}>{$message}</output>"
515 2
            : null;
516
    }
517
518
519
520
    /**
521
     * Init all element with values from session, clear all and fill in with values from the session.
522
     *
523
     * @param array $values retrieved from session
524
     *
525
     * @return void
526
     */
527
    protected function initElements($values)
528
    {
529
        // First clear all
530
        foreach ($this->elements as $key => $val) {
531
            // Do not reset value for buttons
532
            if (in_array($this[$key]['type'], array('submit', 'reset', 'button'))) {
533
                continue;
534
            }
535
536
            // Reset the value
537
            $this[$key]['value'] = null;
538
539
            // Checkboxes must be cleared
540
            if (isset($this[$key]['checked'])) {
541
                $this[$key]['checked'] = false;
542
            }
543
        }
544
545
        // Now build up all values from $values (session)
546
        foreach ($values as $key => $val) {
547
            // Take care of arrays as values (multiple-checkbox)
548
            if (isset($val['values'])) {
549
                $this[$key]['checked'] = $val['values'];
550
                //$this[$key]['values']  = $val['values'];
551
            } elseif (isset($val['value'])) {
552
                $this[$key]['value'] = $val['value'];
553
            }
554
555
            if ($this[$key]['type'] === 'checkbox') {
556
                $this[$key]['checked'] = true;
557
            } elseif ($this[$key]['type'] === 'radio') {
558
                $this[$key]['checked'] = $val['value'];
559
            }
560
561
            // Keep track on validation messages if set
562
            if (isset($val['validation-messages'])) {
563
                $this[$key]['validation-messages'] = $val['validation-messages'];
564
                $this[$key]['validation-pass'] = false;
565
            }
566
        }
567
    }
568
569
570
571
    /**
572
     * Check if a form was submitted and perform validation and call callbacks.
573
     * The form is stored in the session if validation or callback fails. The
574
     * page should then be redirected to the original form page, the form
575
     * will populate from the session and should be rendered again.
576
     * Form elements may remember their value if 'remember' is set and true.
577
     *
578
     * @param callable $callIfSuccess handler to call if function returns true.
579
     * @param callable $callIfFail    handler to call if function returns true.
580
     *
581
     * @throws \Anax\HTMLForm\Exception
582
     *
583
     * @return boolean|null $callbackStatus if submitted&validates, false if
584
     *                                      not validate, null if not submitted.
585
     *                                      If submitted the callback function
586
     *                                      will return the actual value which
587
     *                                      should be true or false.
588
     */
589
    public function check($callIfSuccess = null, $callIfFail = null)
590
    {
591
        $remember = null;
592
        $validates = null;
0 ignored issues
show
Unused Code introduced by
$validates is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
593
        $callbackStatus = null;
594
        $values = [];
595
596
        // Remember flash output messages in session
597
        $output = $this->sessionKey["output"];
598
        $session = $this->di->get("session");
599
        $this->output = $session->getOnce($output, []);
600
601
        // Check if this was a post request
602
        $requestMethod = $this->di->get("request")->getServer("REQUEST_METHOD");
603
        if ($requestMethod !== "POST") {
604
            // Its not posted, but check if values should be used from session
605
            $failed   = $this->sessionKey["failed"];
606
            $remember = $this->sessionKey["remember"];
607
            $save     = $this->sessionKey["save"];
608
            
609
            if ($session->has($failed)) {
610
                // Read form data from session if the previous post failed
611
                // during validation.
612
                $this->InitElements($session->getOnce($failed));
613
            } elseif ($session->has($remember)) {
614
                // Read form data from session if some form elements should
615
                // be remembered
616
                foreach ($session->getOnce($remember) as $key => $val) {
617
                    $this[$key]['value'] = $val['value'];
618
                }
619
            } elseif ($session->has($save)) {
620
                // Read form data from session,
621
                // useful during test where the original form is displayed
622
                // with its posted values
623
                $this->InitElements($session->getOnce($save));
624
            }
625
626
            return null;
627
        }
628
629
        $request = $this->di->get("request");
630
        $formid = $request->getPost("anax/htmlform-id");
631
        // Check if its a form we are dealing with
632
        if (!$formid) {
633
            return null;
634
        }
635
636
        // Check if its this form that was posted
637
        if ($this->form["id"] !== $formid) {
638
            return null;
639
        }
640
641
        // This form was posted, process it
642
        $session->delete($this->sessionKey["failed"]);
643
        $validates = true;
644
        foreach ($this->elements as $element) {
645
            $elementName = $element['name'];
646
            $elementType = $element['type'];
647
648
            $postElement = $request->getPost($elementName);
649
            if ($postElement) {
650
                // The form element has a value set
651
                // Multiple choices comes in the form of an array
652
                if (is_array($postElement)) {
653
                    $values[$elementName]['values'] = $element['checked'] = $postElement;
654
                } else {
655
                    $values[$elementName]['value'] = $element['value'] = $postElement;
656
                }
657
658
                // If the element is a password, do not remember.
659
                if ($elementType === 'password') {
660
                    $values[$elementName]['value'] = null;
661
                }
662
663
                // If the element is a checkbox, set its value of checked.
664
                if ($elementType === 'checkbox') {
665
                    $element['checked'] = true;
666
                }
667
668
                // If the element is a radio, set the value to checked.
669
                if ($elementType === 'radio') {
670
                    $element['checked'] = $element['value'];
671
                }
672
673
                // Do validation of form element
674 View Code Duplication
                if (isset($element['validation'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
675
                    $element['validation-pass'] = $element->Validate($element['validation'], $this);
676
677
                    if ($element['validation-pass'] === false) {
678
                        $values[$elementName] = [
679
                            'value' => $element['value'],
680
                            'validation-messages' => $element['validation-messages']
681
                        ];
682
                        $validates = false;
683
                    }
684
                }
685
686
                // Hmmm.... Why did I need this remember thing?
687
                if (isset($element['remember'])
688
                    && $element['remember']
689
                ) {
690
                    $values[$elementName] = ['value' => $element['value']];
691
                    $remember = true;
692
                }
693
694
                // Carry out the callback if the form element validates
695
                // Hmmm, what if the element with the callback is not the last element?
696
                if (isset($element['callback'])
697
                    && $validates
698
                ) {
699
                    if (isset($element['callback-args'])) {
700
                        $callbackStatus = call_user_func_array(
701
                            $element['callback'],
702
                            array_merge([$this]),
703
                            $element['callback-args']
704
                        );
705
                    } else {
706
                        $callbackStatus = call_user_func($element['callback'], $this);
707
                    }
708
                }
709
            } else {
710
                // The form element has no value set
711
712
                // Set element to null, then we know it was not set.
713
                //$element['value'] = null;
714
                //echo $element['type'] . ':' . $elementName . ':' . $element['value'] . '<br>';
715
716
                // If the element is a checkbox, clear its value of checked.
717
                if ($element['type'] === 'checkbox'
718
                    || $element['type'] === 'checkbox-multiple'
719
                ) {
720
                    $element['checked'] = false;
721
                }
722
723
                // Do validation even when the form element is not set?
724
                // Duplicate code, revise this section and move outside
725
                // this if-statement?
726 View Code Duplication
                if (isset($element['validation'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
727
                    $element['validation-pass'] = $element->Validate($element['validation'], $this);
728
729
                    if ($element['validation-pass'] === false) {
730
                        $values[$elementName] = [
731
                            'value' => $element['value'], 'validation-messages' => $element['validation-messages']
732
                        ];
733
                        $validates = false;
734
                    }
735
                }
736
            }
737
        }
738
739
        // Prepare if data should be stored in the session during redirects
740
        // Did form validation or the callback fail?
741
        if ($validates === false
742
            || $callbackStatus === false
743
        ) {
744
            $session->set($this->sessionKey["failed"], $values);
745
        } elseif ($remember) {
746
            // Hmmm, why do I want to use this
747
            $session->set($this->sessionKey["remember"], $values);
748
        }
749
750
        if ($this->rememberValues) {
751
            // Remember all posted values
752
            $session->set($this->sessionKey["save"], $values);
753
        }
754
755
        // Lets se what the return value should be
756
        $ret = $validates
757
            ? $callbackStatus
758
            : $validates;
759
760
761
        if ($ret === true && isset($callIfSuccess)) {
762
            // Use callback for success, if defined
763
            if (!is_callable($callIfSuccess)) {
764
                throw new Exception("Form, success-method is not callable.");
765
            }
766
            call_user_func_array($callIfSuccess, [$this]);
767
        } elseif ($ret === false && isset($callIfFail)) {
768
            // Use callback for fail, if defined
769
            if (!is_callable($callIfFail)) {
770
                throw new Exception("Form, success-method is not callable.");
771
            }
772
            call_user_func_array($callIfFail, [$this]);
773
        }
774
775
        return $ret;
776
    }
777
}
778