FormHandler::setModel()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Jidaikobo\Kontiki\Handlers;
4
5
use DOMDocument;
6
use Jidaikobo\Kontiki\Models\ModelInterface;
7
use Jidaikobo\Kontiki\Utils\MessageUtils;
8
use Jidaikobo\Kontiki\Utils\FormUtils;
9
10
class FormHandler
11
{
12
    private DOMDocument $dom;
13
    private FormUtils $formUtils;
14
    private ?ModelInterface $model = null;
15
16
    public function __construct(FormUtils $formUtils)
17
    {
18
        $this->formUtils = $formUtils;
19
    }
20
21
    public function setModel(ModelInterface $model): void
22
    {
23
        $this->model = $model;
24
    }
25
26
    public function setHtml(string $html): void
27
    {
28
        $this->dom = new DOMDocument('1.0', 'UTF-8');
29
        libxml_use_internal_errors(true);
30
        if (!empty($html)) {
31
            $this->loadHTML($html);
32
        }
33
    }
34
35
    public function loadHTML(string $html): void
36
    {
37
        $map = [0x80, 0x10FFFF, 0, 0xFFFF];
38
        $html = mb_encode_numericentity($html, $map, 'UTF-8');
39
        $this->dom->loadHTML(
40
            $html,
41
            LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
42
        );
43
    }
44
45
    /**
46
     * Set an attribute for an element by its ID.
47
     *
48
     * @param  string $id        The ID of the element.
49
     * @param  string $attribute The attribute name.
50
     * @param  string $value     The attribute value.
51
     * @return void
52
     */
53
    public function setAttributeById(
54
        string $id,
55
        string $attribute,
56
        string $value
57
    ): void {
58
        $element = $this->dom->getElementById($id);
59
        if ($element) {
60
            $element->setAttribute($attribute, $value);
61
        }
62
    }
63
64
    /**
65
     * Add a CSS class to an element by its ID.
66
     *
67
     * @param  string $id    The ID of the element.
68
     * @param  string $class The CSS class to add.
69
     * @return void
70
     */
71
    public function addClassById(string $id, string $class): void
72
    {
73
        $element = $this->dom->getElementById($id);
74
        if ($element) {
75
            $currentClass = $element->getAttribute('class') ?: '';
76
            $classes = array_unique(array_filter(array_merge(explode(' ', $currentClass), [$class])));
77
            $element->setAttribute('class', implode(' ', $classes));
78
        }
79
    }
80
81
    public function addErrors(array $errors): void
82
    {
83
        if (empty($errors)) {
84
            return;
85
        }
86
87
        foreach ($errors as $field => $messages) {
88
            $id = $this->formUtils->nameToId($field);
89
90
            // Add ARIA attributes and classes to the element
91
            $this->setAttributeById($id, 'aria-invalid', 'true');
92
            $this->setAttributeById($id, 'aria-errormessage', 'errormessage_' . $id);
93
            $this->addClassById($id, 'is-invalid');
94
        }
95
96
        // Use MessageUtils to generate the error summary
97
        $errorHtml = MessageUtils::errorHtml($errors, $this->model);
0 ignored issues
show
Bug introduced by
It seems like $this->model can also be of type null; however, parameter $model of Jidaikobo\Kontiki\Utils\MessageUtils::errorHtml() does only seem to accept Jidaikobo\Kontiki\Models\ModelInterface, maybe add an additional type check? ( Ignorable by Annotation )

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

97
        $errorHtml = MessageUtils::errorHtml($errors, /** @scrutinizer ignore-type */ $this->model);
Loading history...
98
        $this->injectMessageIntoForm($errorHtml);
99
    }
100
101
    public function addSuccessMessages(array $successMessages): void
102
    {
103
        if (empty($successMessages)) {
104
            return;
105
        }
106
        $successHtml = MessageUtils::alertHtml(join($successMessages));
0 ignored issues
show
Bug introduced by
The call to join() has too few arguments starting with array. ( Ignorable by Annotation )

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

106
        $successHtml = MessageUtils::alertHtml(/** @scrutinizer ignore-call */ join($successMessages));

This check compares calls to functions or methods with their respective definitions. If the call has less 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...
107
        $this->injectMessageIntoForm($successHtml);
108
    }
109
110
    protected function injectMessageIntoForm(string $messageHtml): void
111
    {
112
        $form = $this->dom->getElementsByTagName('form')->item(0);
113
        if ($form) {
114
            $messageNode = $this->dom->createDocumentFragment();
115
            $messageNode->appendXML($messageHtml);
116
            $form->insertBefore($messageNode, $form->firstChild);
117
        }
118
    }
119
120
    /**
121
     * Get the modified HTML as a string.
122
     *
123
     * @return string The HTML content.
124
     */
125
    public function getHtml(): string
126
    {
127
        $html = $this->dom->saveHTML();
128
        return mb_decode_numericentity($html, [0x80, 0x10FFFF, 0, 0xFFFF], 'UTF-8');
0 ignored issues
show
Bug Best Practice introduced by
The expression return mb_decode_numeric...11, 0, 65535), 'UTF-8') could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
129
    }
130
}
131