Passed
Push — master ( 3c96ed...518a68 )
by Mikael
02:02
created

Form::getHTMLForElements()   C

Complexity

Conditions 8
Paths 10

Size

Total Lines 41
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 21.8238

Importance

Changes 0
Metric Value
cc 8
eloc 26
nc 10
nop 1
dl 0
loc 41
ccs 8
cts 20
cp 0.4
crap 21.8238
rs 5.3846
c 0
b 0
f 0
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 6
    public function __construct(DIInterface $di)
41
    {
42 6
        $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 6
    }
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 6
    public function create($form = [], $elements = [])
87
    {
88
        $defaults = [
89
            // Always have an id
90 6
            "id" => "anax/htmlform",
91
92
            // Use a default class on <form> to ease styling
93
            "class" => "htmlform",
94
95
            // Wrap fields within <fieldset>
96
            "use_fieldset"  => true,
97
98
            // Use legend for fieldset, set it to string value
99
            "legend"        => null,
100
101
            // Default wrapper element around form elements
102
            "wrapper-element" => "p",
103
104
            // Use a <br> after the label, where suitable
105
            "br-after-label" => true,
106
107
            // Default is to always encode values
108
            "escape-values" => true,
109
        ];
110 6
        $this->form = array_merge($defaults, $form);
111
112 6
        $this->elements = [];
113 6
        if (!empty($elements)) {
114 4
            foreach ($elements as $key => $element) {
115 4
                $this->elements[$key] = FormElementFactory::create($key, $element);
116 4
                $this->elements[$key]->setDefault([
117 4
                    "wrapper-element" => $this->form["wrapper-element"],
118 4
                    "br-after-label"  => $this->form["br-after-label"],
119 4
                    "escape-values"   => $this->form["escape-values"],
120
                ]);
121
            }
122
        }
123
124
        // Default values for <output>
125 6
        $this->output = [];
126
127
        // Setting keys used in the session
128 6
        $generalKey = "anax/htmlform-" . $this->form["id"] . "#";
129 6
        $this->sessionKey = [
130 6
            "save"      => $generalKey . "save",
131 6
            "output"    => $generalKey . "output",
132 6
            "failed"    => $generalKey . "failed",
133 6
            "remember"  => $generalKey . "remember",
134
        ];
135
136 6
        return $this;
137
    }
138
139
140
141
    /**
142
     * Add a form element
143
     *
144
     * @param FormElement $element the formelement to add.
145
     *
146
     * @return $this
147
     */
148
    public function addElement($element)
149
    {
150
        $name = $element;
151
        if (isset($this->elements[$name])) {
152
            throw new Exception("Form element '$name' already exists, do not add it twice.");
153
        }
154
        $this[$element['name']] = $name;
155
        return $this;
156
    }
157
158
159
160
    /**
161
     * Get a form element
162
     *
163
     * @param string $name the name of the element.
164
     *
165
     * @return \Anax\HTMLForm\FormElement
166
     */
167 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...
168
    {
169
        if (!isset($this->elements[$name])) {
170
            throw new Exception("Form element '$name' is not found.");
171
        }
172
        return $this->elements[$name];
173
    }
174
175
176
177
    /**
178
     * Remove an form element
179
     *
180
     * @param string $name the name of the element.
181
     *
182
     * @return $this
183
     */
184 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...
185
    {
186
        if (!isset($this->elements[$name])) {
187
            throw new Exception("Form element '$name' is not found.");
188
        }
189
        unset($this->elements[$name]);
190
        return $this;
191
    }
192
193
194
195
    /**
196
     * Set validation to a form element
197
     *
198
     * @param string $element the name of the formelement to add validation rules to.
199
     * @param array  $rules   array of validation rules.
200
     *
201
     * @return $this
202
     */
203
    public function setValidation($element, $rules)
204
    {
205
        $this[$element]['validation'] = $rules;
206
        return $this;
207
    }
208
209
210
211
    /**
212
     * Add output to display to the user for what happened whith the form and
213
     * optionally add a CSS class attribute.
214
     *
215
     * @param string $str   the string to add as output.
216
     * @param string $class a class attribute to set.
217
     *
218
     * @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...
219
     */
220
    public function addOutput($str, $class = null)
221
    {
222
        $key     = $this->sessionKey["output"];
223
        $session = $this->di->get("session");
224
        $output  = $session->get($key);
225
226
        $output["message"] = isset($output["message"])
227
            ? $output["message"] . " $str"
228
            : $str;
229
230
        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...
231
            $output["class"] = $class;
232
        }
233
        $session->set($key, $output);
234
235
        return $this;
236
    }
237
238
239
240
    /**
241
     * Set a CSS class attribute for the <output> element.
242
     *
243
     * @param string $class a class attribute to set.
244
     *
245
     * @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...
246
     */
247
    public function setOutputClass($class)
248
    {
249
        $key     = $this->sessionKey["output"];
250
        $session = $this->di->get("session");
251
        $output  = $session->get($key);
252
        $output["class"] = $class;
253
        $session->set($key, $output);
254
        return $this;
255
    }
256
257
258
259
    /**
260
     * Remember current values in session, useful for storing values of
261
     * current form when submitting it.
262
     *
263
     * @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...
264
     */
265
    public function rememberValues()
266
    {
267
        $this->rememberValues = true;
268
        return $this;
269
    }
270
271
272
273
274
    /**
275
     * Get value of a form element and respect settings of escaped or
276
     * raw value.
277
     *
278
     * @param string $name the name of the formelement.
279
     *
280
     * @return mixed the value of the element.
281
     */
282
    public function value($name)
283
    {
284
        return isset($this->elements[$name])
285
            ? $this->elements[$name]->value()
286
            : null;
287
    }
288
289
290
291
    /**
292
     * Get escaped value of a form element.
293
     *
294
     * @param string $name the name of the formelement.
295
     *
296
     * @return mixed the value of the element.
297
     */
298 4
    public function escValue($name)
299
    {
300 4
        return isset($this->elements[$name])
301 4
            ? $this->elements[$name]->getEscapedValue()
302 4
            : null;
303
    }
304
305
306
307
    /**
308
     * Get raw value of a form element.
309
     *
310
     * @param string $name the name of the formelement.
311
     *
312
     * @return mixed the value of the element.
313
     */
314 4
    public function rawValue($name)
315
    {
316 4
        return isset($this->elements[$name])
317 4
            ? $this->elements[$name]->getRawValue()
318 4
            : null;
319
    }
320
321
322
323
    /**
324
     * Check if a element is checked
325
     *
326
     * @param string $name the name of the formelement.
327
     *
328
     * @return mixed the value of the element.
329
     */
330
    public function checked($name)
331
    {
332
        return isset($this->elements[$name])
333
            ? $this->elements[$name]->checked()
334
            : null;
335
    }
336
337
338
339
    /**
340
     * Return HTML for the form.
341
     *
342
     * @param array $options with options affecting the form output.
343
     *
344
     * @return string with HTML for the form.
345
     */
346 2
    public function getHTML($options = [])
347
    {
348
        $defaults = [
349
            // Only return the start of the form element
350 2
            'start'         => false,
351
352
            // Layout all elements in one column
353
            'columns'       => 1,
354
355
            // Layout consequtive buttons as one element wrapped in <p>
356
            'use_buttonbar' => true,
357
        ];
358 2
        $options = array_merge($defaults, $options);
359
360 2
        $form = array_merge($this->form, $options);
361 2
        $id      = isset($form['id'])      ? " id='{$form['id']}'" : null;
362 2
        $class   = isset($form['class'])   ? " class='{$form['class']}'" : null;
363 2
        $name    = isset($form['name'])    ? " name='{$form['name']}'" : null;
364 2
        $action  = isset($form['action'])  ? " action='{$form['action']}'" : null;
365 2
        $method  = isset($form['method'])  ? " method='{$form['method']}'" : " method='post'";
366 2
        $enctype = isset($form['enctype']) ? " enctype='{$form['enctype']}'" : null;
367 2
        $cformId = isset($form['id'])      ? "{$form['id']}" : null;
368
369 2
        if ($options['start']) {
370
            return "<form{$id}{$class}{$name}{$action}{$method}>\n";
371
        }
372
373 2
        $fieldsetStart  = '<fieldset>';
374 2
        $legend         = null;
375 2
        $fieldsetEnd    = '</fieldset>';
376 2
        if (!$form['use_fieldset']) {
377
            $fieldsetStart = $fieldsetEnd = null;
378
        }
379
380 2
        if ($form['use_fieldset'] && $form['legend']) {
381
            $legend = "<legend>{$form['legend']}</legend>";
382
        }
383
384 2
        $elementsArray  = $this->getHTMLForElements($options);
385 2
        $elements       = $this->getHTMLLayoutForElements($elementsArray, $options);
386 2
        $output         = $this->getOutput();
387
388
        $html = <<< EOD
389 2
\n<form{$id}{$class}{$name}{$action}{$method}{$enctype}>
390 2
<input type="hidden" name="anax/htmlform-id" value="$cformId" />
391 2
{$fieldsetStart}
392 2
{$legend}
393 2
{$elements}
394 2
{$output}
395 2
{$fieldsetEnd}
396
</form>\n
397
EOD;
398
399 2
        return $html;
400
    }
401
402
403
404
    /**
405
     * Return HTML for the elements
406
     *
407
     * @param array $options with options affecting the form output.
408
     *
409
     * @return array with HTML for the formelements.
410
     */
411 2
    public function getHTMLForElements($options = [])
412
    {
413
        $defaults = [
414 2
            "use_buttonbar" => true,
415
        ];
416 2
        $options = array_merge($defaults, $options);
417
418 2
        $elements = [];
419 2
        $buttonbarStarted = false;
420 2
        foreach ($this->elements as $element) {
421
            if ($options["use_buttonbar"]) {
422
                if ($element->isButton() && !$buttonbarStarted) {
423
                    $buttonbarStarted = true;
424
                    $elements[] = [
425
                        "name" => "buttonbar start",
426
                        "html" => "\n<p class=\"buttonbar\">\n"
427
                    ];
428
                } elseif ($buttonbarStarted && !$element->isButton()) {
429
                    $buttonbarStarted = false;
430
                    $elements[] = [
431
                        "name" => "buttonbar end",
432
                        "html" => "\n</p>\n"
433
                    ];
434
                }
435
            }
436
437
            $elements[] = [
438
                "name" => $element["name"],
439
                "html" => $element->getHTML()
440
            ];
441
        }
442
443 2
        if ($buttonbarStarted) {
444
            $elements[] = [
445
                "name" => "buttonbar end",
446
                "html" => "\n</p>\n"
447
            ];
448
        }
449
450 2
        return $elements;
451
    }
452
453
454
455
456
    /**
457
     * Place the elements according to a layout and return the HTML
458
     *
459
     * @param array $elements as returned from GetHTMLForElements().
460
     * @param array $options  with options affecting the layout.
461
     *
462
     * @return array with HTML for the formelements.
463
     */
464 2
    public function getHTMLLayoutForElements($elements, $options = [])
465
    {
466
        $defaults = [
467 2
            'columns' => 1,
468
            'wrap_at_element' => false,  // Wraps column in equal size or at the set number of elements
469
        ];
470 2
        $options = array_merge($defaults, $options);
471
472 2
        $html = null;
473 2
        if ($options['columns'] === 1) {
474 2
            foreach ($elements as $element) {
475 2
                $html .= $element['html'];
476
            }
477
        } elseif ($options['columns'] === 2) {
478
            $buttonbar = null;
479
            $col1 = null;
480
            $col2 = null;
481
482
            $end = end($elements);
483
            if ($end['name'] == 'buttonbar') {
484
                $end = array_pop($elements);
485
                $buttonbar = "<div class='cform-buttonbar'>\n{$end['html']}</div>\n";
486
            }
487
488
            $size = count($elements);
489
            $wrapAt = $options['wrap_at_element'] ? $options['wrap_at_element'] : round($size/2);
490
            for ($i=0; $i<$size; $i++) {
491
                if ($i < $wrapAt) {
492
                    $col1 .= $elements[$i]['html'];
493
                } else {
494
                    $col2 .= $elements[$i]['html'];
495
                }
496
            }
497
498
            $html = <<<EOD
499
<div class='cform-columns-2'>
500
<div class='cform-column-1'>
501
{$col1}
502
</div>
503
<div class='cform-column-2'>
504
{$col2}
505
</div>
506
{$buttonbar}</div>
507
EOD;
508
        }
509
510 2
        return $html;
511
    }
512
513
514
515
    /**
516
     * Get an array with all elements that failed validation together with their id and validation message.
517
     *
518
     * @return array with elements that failed validation.
519
     */
520
    public function getValidationErrors()
521
    {
522
        $errors = [];
523
        foreach ($this->elements as $name => $element) {
524
            if ($element['validation-pass'] === false) {
525
                $errors[$name] = [
526
                    'id' => $element->GetElementId(),
527
                    'label' => $element['label'],
528
                    'message' => implode(' ', $element['validation-messages'])
529
                ];
530
            }
531
        }
532
        return $errors;
533
    }
534
535
536
537
    /**
538
     * Get output messages as <output>.
539
     *
540
     * @return string|null with the complete <output> element or null if no output.
541
     */
542 2
    public function getOutput()
543
    {
544 2
        $output = $this->output;
545 2
        $message = isset($output["message"]) && !empty($output["message"])
546
            ? $output["message"]
547 2
            : null;
548
549 2
        $class = isset($output["class"]) && !empty($output["class"])
550
            ? " class=\"{$output["class"]}\""
551 2
            : null;
552
553 2
        return $message
554
            ? "<output{$class}>{$message}</output>"
555 2
            : null;
556
    }
557
558
559
560
    /**
561
     * Init all element with values from session, clear all and fill in with values from the session.
562
     *
563
     * @param array $values retrieved from session
564
     *
565
     * @return void
566
     */
567
    protected function initElements($values)
568
    {
569
        // First clear all
570
        foreach ($this->elements as $key => $val) {
571
            // Do not reset value for buttons
572
            if (in_array($this[$key]['type'], array('submit', 'reset', 'button'))) {
573
                continue;
574
            }
575
576
            // Reset the value
577
            $this[$key]['value'] = null;
578
579
            // Checkboxes must be cleared
580
            if (isset($this[$key]['checked'])) {
581
                $this[$key]['checked'] = false;
582
            }
583
        }
584
585
        // Now build up all values from $values (session)
586
        foreach ($values as $key => $val) {
587
            // Take care of arrays as values (multiple-checkbox)
588
            if (isset($val['values'])) {
589
                $this[$key]['checked'] = $val['values'];
590
                //$this[$key]['values']  = $val['values'];
591
            } elseif (isset($val['value'])) {
592
                $this[$key]['value'] = $val['value'];
593
            }
594
595
            if ($this[$key]['type'] === 'checkbox') {
596
                $this[$key]['checked'] = true;
597
            } elseif ($this[$key]['type'] === 'radio') {
598
                $this[$key]['checked'] = $val['value'];
599
            }
600
601
            // Keep track on validation messages if set
602
            if (isset($val['validation-messages'])) {
603
                $this[$key]['validation-messages'] = $val['validation-messages'];
604
                $this[$key]['validation-pass'] = false;
605
            }
606
        }
607
    }
608
609
610
611
    /**
612
     * Check if a form was submitted and perform validation and call callbacks.
613
     * The form is stored in the session if validation or callback fails. The
614
     * page should then be redirected to the original form page, the form
615
     * will populate from the session and should be rendered again.
616
     * Form elements may remember their value if 'remember' is set and true.
617
     *
618
     * @param callable $callIfSuccess handler to call if function returns true.
619
     * @param callable $callIfFail    handler to call if function returns true.
620
     *
621
     * @throws \Anax\HTMLForm\Exception
622
     *
623
     * @return boolean|null $callbackStatus if submitted&validates, false if
624
     *                                      not validate, null if not submitted.
625
     *                                      If submitted the callback function
626
     *                                      will return the actual value which
627
     *                                      should be true or false.
628
     */
629
    public function check($callIfSuccess = null, $callIfFail = null)
630
    {
631
        $remember = null;
632
        $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...
633
        $callbackStatus = null;
634
        $values = [];
635
636
        // Remember flash output messages in session
637
        $output = $this->sessionKey["output"];
638
        $session = $this->di->get("session");
639
        $this->output = $session->getOnce($output, []);
640
641
        // Check if this was a post request
642
        $requestMethod = $this->di->get("request")->getServer("REQUEST_METHOD");
643
        if ($requestMethod !== "POST") {
644
            // Its not posted, but check if values should be used from session
645
            $failed   = $this->sessionKey["failed"];
646
            $remember = $this->sessionKey["remember"];
647
            $save     = $this->sessionKey["save"];
648
649
            if ($session->has($failed)) {
650
                // Read form data from session if the previous post failed
651
                // during validation.
652
                $this->InitElements($session->getOnce($failed));
653
            } elseif ($session->has($remember)) {
654
                // Read form data from session if some form elements should
655
                // be remembered
656
                foreach ($session->getOnce($remember) as $key => $val) {
657
                    $this[$key]['value'] = $val['value'];
658
                }
659
            } elseif ($session->has($save)) {
660
                // Read form data from session,
661
                // useful during test where the original form is displayed
662
                // with its posted values
663
                $this->InitElements($session->getOnce($save));
664
            }
665
666
            return null;
667
        }
668
669
        $request = $this->di->get("request");
670
        $formid = $request->getPost("anax/htmlform-id");
671
        // Check if its a form we are dealing with
672
        if (!$formid) {
673
            return null;
674
        }
675
676
        // Check if its this form that was posted
677
        if ($this->form["id"] !== $formid) {
678
            return null;
679
        }
680
681
        // This form was posted, process it
682
        $session->delete($this->sessionKey["failed"]);
683
        $validates = true;
684
        foreach ($this->elements as $element) {
685
            $elementName = $element['name'];
686
            $elementType = $element['type'];
687
688
            $postElement = $request->getPost($elementName);
689
            if ($postElement) {
690
                // The form element has a value set
691
                // Multiple choices comes in the form of an array
692
                if (is_array($postElement)) {
693
                    $values[$elementName]['values'] = $element['checked'] = $postElement;
694
                } else {
695
                    $values[$elementName]['value'] = $element['value'] = $postElement;
696
                }
697
698
                // If the element is a password, do not remember.
699
                if ($elementType === 'password') {
700
                    $values[$elementName]['value'] = null;
701
                }
702
703
                // If the element is a checkbox, set its value of checked.
704
                if ($elementType === 'checkbox') {
705
                    $element['checked'] = true;
706
                }
707
708
                // If the element is a radio, set the value to checked.
709
                if ($elementType === 'radio') {
710
                    $element['checked'] = $element['value'];
711
                }
712
713
                // Do validation of form element
714 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...
715
                    $element['validation-pass'] = $element->Validate($element['validation'], $this);
716
717
                    if ($element['validation-pass'] === false) {
718
                        $values[$elementName] = [
719
                            'value' => $element['value'],
720
                            'validation-messages' => $element['validation-messages']
721
                        ];
722
                        $validates = false;
723
                    }
724
                }
725
726
                // Hmmm.... Why did I need this remember thing?
727
                if (isset($element['remember'])
728
                    && $element['remember']
729
                ) {
730
                    $values[$elementName] = ['value' => $element['value']];
731
                    $remember = true;
732
                }
733
734
                // Carry out the callback if the form element validates
735
                // Hmmm, what if the element with the callback is not the last element?
736
                if (isset($element['callback'])
737
                    && $validates
738
                ) {
739
                    if (isset($element['callback-args'])) {
740
                        $callbackStatus = call_user_func_array(
741
                            $element['callback'],
742
                            array_merge([$this]),
743
                            $element['callback-args']
744
                        );
745
                    } else {
746
                        $callbackStatus = call_user_func($element['callback'], $this);
747
                    }
748
                }
749
            } else {
750
                // The form element has no value set
751
752
                // Set element to null, then we know it was not set.
753
                //$element['value'] = null;
754
                //echo $element['type'] . ':' . $elementName . ':' . $element['value'] . '<br>';
755
756
                // If the element is a checkbox, clear its value of checked.
757
                if ($element['type'] === 'checkbox'
758
                    || $element['type'] === 'checkbox-multiple'
759
                ) {
760
                    $element['checked'] = false;
761
                }
762
763
                // Do validation even when the form element is not set?
764
                // Duplicate code, revise this section and move outside
765
                // this if-statement?
766 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...
767
                    $element['validation-pass'] = $element->Validate($element['validation'], $this);
768
769
                    if ($element['validation-pass'] === false) {
770
                        $values[$elementName] = [
771
                            'value' => $element['value'], 'validation-messages' => $element['validation-messages']
772
                        ];
773
                        $validates = false;
774
                    }
775
                }
776
            }
777
        }
778
779
        // Prepare if data should be stored in the session during redirects
780
        // Did form validation or the callback fail?
781
        if ($validates === false
782
            || $callbackStatus === false
783
        ) {
784
            $session->set($this->sessionKey["failed"], $values);
785
        } elseif ($remember) {
786
            // Hmmm, why do I want to use this
787
            $session->set($this->sessionKey["remember"], $values);
788
        }
789
790
        if ($this->rememberValues) {
791
            // Remember all posted values
792
            $session->set($this->sessionKey["save"], $values);
793
        }
794
795
        // Lets se what the return value should be
796
        $ret = $validates
797
            ? $callbackStatus
798
            : $validates;
799
800
801
        if ($ret === true && isset($callIfSuccess)) {
802
            // Use callback for success, if defined
803
            if (!is_callable($callIfSuccess)) {
804
                throw new Exception("Form, success-method is not callable.");
805
            }
806
            call_user_func_array($callIfSuccess, [$this]);
807
        } elseif ($ret === false && isset($callIfFail)) {
808
            // Use callback for fail, if defined
809
            if (!is_callable($callIfFail)) {
810
                throw new Exception("Form, success-method is not callable.");
811
            }
812
            call_user_func_array($callIfFail, [$this]);
813
        }
814
815
        return $ret;
816
    }
817
}
818