Completed
Pull Request — master (#14)
by Martin
02:45
created

Form   F

Complexity

Total Complexity 113

Size/Duplication

Total Lines 809
Duplicated Lines 0 %

Test Coverage

Coverage 28.33%

Importance

Changes 0
Metric Value
eloc 308
dl 0
loc 809
ccs 85
cts 300
cp 0.2833
rs 2
c 0
b 0
f 0
wmc 113

24 Methods

Rating   Name   Duplication   Size   Complexity  
A offsetExists() 0 3 1
A __construct() 0 3 1
A offsetSet() 0 6 2
A offsetUnset() 0 3 1
A offsetGet() 0 5 2
A rawValue() 0 5 2
F getHTML() 0 54 12
A getOutput() 0 14 6
B initElements() 0 38 10
A removeElement() 0 7 2
A checked() 0 5 2
A addOutput() 0 16 3
A getValidationErrors() 0 13 3
B getHTMLLayoutForElements() 0 47 8
A addElement() 0 8 2
A getElement() 0 6 2
A setOutputClass() 0 8 1
B getHTMLForElements() 0 40 8
A create() 0 54 3
F check() 0 187 36
A value() 0 5 2
A setValidation() 0 4 1
A escValue() 0 5 2
A rememberValues() 0 4 1

How to fix   Complexity   

Complex Class

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.

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 Psr\Container\ContainerInterface;
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.
0 ignored issues
show
Bug introduced by
The type Anax\HTMLForm\Anax\DI\DIInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

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

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

746
                        $callbackStatus = /** @scrutinizer ignore-call */ call_user_func_array(

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
747
                        );
748
                    } else {
749
                        $callbackStatus = call_user_func($element['callback'], $this);
750
                    }
751
                }
752
            } else {
753
                // The form element has no value set
754
755
                // Set element to null, then we know it was not set.
756
                //$element['value'] = null;
757
                //echo $element['type'] . ':' . $elementName . ':' . $element['value'] . '<br>';
758
759
                // If the element is a checkbox, clear its value of checked.
760
                if ($element['type'] === 'checkbox'
761
                    || $element['type'] === 'checkbox-multiple'
762
                ) {
763
                    $element['checked'] = false;
764
                }
765
766
                // Do validation even when the form element is not set?
767
                // Duplicate code, revise this section and move outside
768
                // this if-statement?
769
                if (isset($element['validation'])) {
770
                    $element['validation-pass'] = $element->Validate($element['validation'], $this);
771
772
                    if ($element['validation-pass'] === false) {
773
                        $values[$elementName] = [
774
                            'value' => $element['value'], 'validation-messages' => $element['validation-messages']
775
                        ];
776
                        $validates = false;
777
                    }
778
                }
779
            }
780
        }
781
782
        // Prepare if data should be stored in the session during redirects
783
        // Did form validation or the callback fail?
784
        if ($validates === false
785
            || $callbackStatus === false
786
        ) {
787
            $session->set($this->sessionKey["failed"], $values);
788
        } elseif ($remember) {
789
            // Hmmm, why do I want to use this
790
            $session->set($this->sessionKey["remember"], $values);
791
        }
792
793
        if ($this->rememberValues) {
794
            // Remember all posted values
795
            $session->set($this->sessionKey["save"], $values);
796
        }
797
798
        // Lets se what the return value should be
799
        $ret = $validates
800
            ? $callbackStatus
801
            : $validates;
802
803
804
        if ($ret === true && isset($callIfSuccess)) {
805
            // Use callback for success, if defined
806
            if (!is_callable($callIfSuccess)) {
807
                throw new Exception("Form, success-method is not callable.");
808
            }
809
            call_user_func_array($callIfSuccess, [$this]);
810
        } elseif ($ret === false && isset($callIfFail)) {
811
            // Use callback for fail, if defined
812
            if (!is_callable($callIfFail)) {
813
                throw new Exception("Form, success-method is not callable.");
814
            }
815
            call_user_func_array($callIfFail, [$this]);
816
        }
817
818
        return $ret;
819
    }
820
}
821