Issues (49)

src/Builder/Engine/Engine.php (2 issues)

Labels
Severity
1
<?php
2
3
namespace Lagdo\UiBuilder\Builder\Engine;
4
5
use Lagdo\UiBuilder\Builder;
6
use Lagdo\UiBuilder\Component\HtmlComponent;
7
use Lagdo\UiBuilder\Component\HtmlElement;
8
use Lagdo\UiBuilder\Component\Html\Element;
9
use Closure;
10
use LogicException;
11
12
use function preg_replace;
13
use function stripos;
14
use function strlen;
15
use function strtolower;
16
use function substr;
17
18
class Engine
19
{
20
    /**
21
     * @var int
22
     */
23
    private int $formLevel = 0;
24
25
    /**
26
     * @var array<array<string, Closure>>
27
     */
28
    protected $helpers = [
29
        /*Builder::TARGET_BUILDER =>*/ [],
30
        /*Builder::TARGET_COMPONENT =>*/ [],
31
        /*Builder::TARGET_ELEMENT =>*/ [],
32
    ];
33
34
    /**
35
     * The constructor
36
     *
37
     * @param Builder $builder
38
     */
39
    public function __construct(private Builder $builder)
40
    {
41
        $this->registerHelper('set', Builder::TARGET_COMPONENT,
42
            function(HtmlComponent $component, string $tagName,
43
                string $method, array $arguments): HtmlComponent {
44
                $component->setAttribute($tagName, $arguments[0] ?? null, $arguments[1] ?? true);
0 ignored issues
show
It seems like $arguments[0] ?? null can also be of type null; however, parameter $value of Lagdo\UiBuilder\Componen...mponent::setAttribute() does only seem to accept boolean|string, 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

44
                $component->setAttribute($tagName, /** @scrutinizer ignore-type */ $arguments[0] ?? null, $arguments[1] ?? true);
Loading history...
45
                return $component;
46
            });
47
        $this->registerHelper('set', Builder::TARGET_ELEMENT,
48
            function(HtmlElement $element, string $tagName,
49
                string $method, array $arguments): HtmlElement {
50
                $element->setAttribute($tagName, $arguments[0] ?? null, $arguments[1] ?? true);
0 ignored issues
show
It seems like $arguments[0] ?? null can also be of type null; however, parameter $value of Lagdo\UiBuilder\Componen...Element::setAttribute() does only seem to accept boolean|string, 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

50
                $element->setAttribute($tagName, /** @scrutinizer ignore-type */ $arguments[0] ?? null, $arguments[1] ?? true);
Loading history...
51
                return $element;
52
            });
53
    }
54
55
    /**
56
     * @param string $tagPrefix
57
     * @param string $tagTarget
58
     * @param Closure $tagHelper
59
     *
60
     * @return void
61
     */
62
    public function registerHelper(string $tagPrefix, string $tagTarget, Closure $tagHelper): void
63
    {
64
        // Do not overwrite existing helpers.
65
        if(isset($this->helpers[$tagTarget]) && !isset($this->helpers[$tagTarget][$tagPrefix])) {
66
            $this->helpers[$tagTarget][$tagPrefix] = $tagHelper;
67
        }
68
    }
69
70
    /**
71
     * @param string $method
72
     *
73
     * @return string
74
     */
75
    private function getTagName(string $method): string
76
    {
77
        return strtolower(preg_replace('/(?<!^)([A-Z])/', '-$1', $method));
78
    }
79
80
    /**
81
     * @param string $method
82
     * @param array $arguments
83
     *
84
     * @return HtmlComponent|Element
85
     */
86
    public function callBuilderHelper(string $method, array $arguments): HtmlComponent|Element
87
    {
88
        $tagName = $this->getTagName($method);
89
        foreach($this->helpers[Builder::TARGET_BUILDER] as $tagPrefix => $helper) {
90
            if (stripos($tagName, "$tagPrefix-") === 0) {
91
                $tagName = substr($tagName, strlen($tagPrefix) + 1);
92
                return $helper($tagName, $method, $arguments);
93
            }
94
        }
95
96
        return $this->builder->createComponent($tagName, $arguments);
97
    }
98
99
    /**
100
     * @param HtmlComponent $component
101
     * @param string $method
102
     * @param array $arguments
103
     *
104
     * @return HtmlComponent
105
     * @throws LogicException When component is not initialized yet
106
     */
107
    public function callComponentHelper(HtmlComponent $component, string $method, array $arguments): HtmlComponent
108
    {
109
        $tagName = $this->getTagName($method);
110
        foreach($this->helpers[Builder::TARGET_COMPONENT] as $tagPrefix => $helper) {
111
            if (stripos($tagName, "$tagPrefix-") === 0) {
112
                $tagName = substr($tagName, strlen($tagPrefix) + 1);
113
                return $helper($component, $tagName, $method, $arguments);
114
            }
115
        }
116
117
        throw new LogicException("Call to undefined method \"{$method}()\" in the HTML component.");
118
    }
119
120
    /**
121
     * @param HtmlElement $element
122
     * @param string $method
123
     * @param array $arguments
124
     *
125
     * @return HtmlElement
126
     * @throws LogicException When component is not initialized yet
127
     */
128
    public function callElementHelper(HtmlElement $element, string $method, array $arguments): HtmlElement
129
    {
130
        $tagName = $this->getTagName($method);
131
        foreach($this->helpers[Builder::TARGET_ELEMENT] as $tagPrefix => $helper) {
132
            if (stripos($tagName, "$tagPrefix-") === 0) {
133
                $tagName = substr($tagName, strlen($tagPrefix) + 1);
134
                return $helper($element, $tagName, $method, $arguments);
135
            }
136
        }
137
138
        throw new LogicException("Call to undefined method \"{$method}()\" in the HTML element.");
139
    }
140
141
    /**
142
     * @return void
143
     */
144
    public function formStarted(): void
145
    {
146
        $this->formLevel++;
147
    }
148
149
    /**
150
     * @return void
151
     */
152
    public function formEnded(): void
153
    {
154
        $this->formLevel--;
155
    }
156
157
    /**
158
     * @return bool
159
     */
160
    public function inForm(): bool
161
    {
162
        return $this->formLevel > 0;
163
    }
164
165
    /**
166
     * @param array $arguments
167
     *
168
     * @return string
169
     */
170
    public function build(array $arguments): string
171
    {
172
        $this->formLevel = 0;
173
        // The "root" component below will not be printed.
174
        $scope = new Scope($this->builder->createComponent('root'));
175
        $scope->build($this, $arguments);
176
177
        return $scope->html();
178
    }
179
}
180