Passed
Push — main ( 68e606...997043 )
by Thierry
02:29
created

Engine::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 10
nc 1
nop 0
dl 0
loc 13
rs 9.9332
c 1
b 0
f 0
1
<?php
2
3
namespace Lagdo\UiBuilder\Engine;
4
5
use Lagdo\UiBuilder\Component\HtmlComponent;
6
use Lagdo\UiBuilder\Component\HtmlElement;
7
use Lagdo\UiBuilder\Component\Html\Element;
8
use Closure;
9
use LogicException;
10
11
use function preg_replace;
12
use function stripos;
13
use function strlen;
14
use function strtolower;
15
use function substr;
16
17
class Engine
18
{
19
    /**
20
     * @var int
21
     */
22
    public const TARGET_BUILDER = 0;
23
24
    /**
25
     * @var int
26
     */
27
    public const TARGET_COMPONENT = 1;
28
29
    /**
30
     * @var int
31
     */
32
    public const TARGET_ELEMENT = 2;
33
34
    /**
35
     * @var array<string, array<string, Closure>>
36
     */
37
    protected $helpers = [
38
        /*self::TARGET_BUILDER =>*/ [],
39
        /*self::TARGET_COMPONENT =>*/ [],
40
        /*self::TARGET_ELEMENT =>*/ [],
41
    ];
42
43
    /**
44
     * The constructor
45
     */
46
    public function __construct()
47
    {
48
        $this->registerHelper('set', self::TARGET_COMPONENT,
49
            function(HtmlComponent $component, string $tagName,
50
                string $method, array $arguments): HtmlComponent {
51
                $component->setAttribute($tagName, $arguments[0] ?? null, $arguments[1] ?? true);
52
                return $component;
53
            });
54
        $this->registerHelper('set', self::TARGET_ELEMENT,
55
            function(HtmlElement $element, string $tagName,
56
                string $method, array $arguments): HtmlElement {
57
                $element->setAttribute($tagName, $arguments[0] ?? null, $arguments[1] ?? true);
58
                return $element;
59
            });
60
    }
61
62
    /**
63
     * @param string $tagPrefix
64
     * @param string $tagTarget
65
     * @param Closure $tagHelper
66
     *
67
     * @return void
68
     */
69
    public function registerHelper(string $tagPrefix, string $tagTarget, Closure $tagHelper): void
70
    {
71
        // Do not overwrite existing helpers.
72
        if(isset($this->helpers[$tagTarget]) && !isset($this->helpers[$tagTarget][$tagPrefix])) {
73
            $this->helpers[$tagTarget][$tagPrefix] = $tagHelper;
74
        }
75
    }
76
77
    /**
78
     * @param string $method
79
     *
80
     * @return string
81
     */
82
    private function getTagName(string $method): string
83
    {
84
        return strtolower(preg_replace('/(?<!^)([A-Z])/', '-$1', $method));
85
    }
86
87
    /**
88
     * @param string $method
89
     * @param array $arguments
90
     *
91
     * @return HtmlComponent|Element
92
     */
93
    public function callBuilderHelper(string $method, array $arguments): HtmlComponent|Element
94
    {
95
        $tagName = $this->getTagName($method);
96
        foreach($this->helpers[self::TARGET_BUILDER] as $tagPrefix => $helper) {
97
            if (stripos($tagName, "$tagPrefix-") === 0) {
98
                $tagName = substr($tagName, strlen($tagPrefix) + 1);
99
                return $helper($tagName, $method, $arguments);
100
            }
101
        }
102
103
        return $this->createComponent($tagName, $arguments);
104
    }
105
106
    /**
107
     * @param HtmlComponent $component
108
     * @param string $method
109
     * @param array $arguments
110
     *
111
     * @return HtmlComponent
112
     * @throws LogicException When component is not initialized yet
113
     */
114
    public function callComponentHelper(HtmlComponent $component, string $method, array $arguments): HtmlComponent
115
    {
116
        $tagName = $this->getTagName($method);
117
        foreach($this->helpers[self::TARGET_COMPONENT] as $tagPrefix => $helper) {
118
            if (stripos($tagName, "$tagPrefix-") === 0) {
119
                $tagName = substr($tagName, strlen($tagPrefix) + 1);
120
                return $helper($component, $tagName, $method, $arguments);
121
            }
122
        }
123
124
        throw new LogicException("No \"{$method}()\" method defined in the HTML component.");
125
    }
126
127
    /**
128
     * @param HtmlElement $element
129
     * @param string $method
130
     * @param array $arguments
131
     *
132
     * @return HtmlElement
133
     * @throws LogicException When component is not initialized yet
134
     */
135
    public function callElementHelper(HtmlElement $element, string $method, array $arguments): HtmlElement
136
    {
137
        $tagName = $this->getTagName($method);
138
        foreach($this->helpers[self::TARGET_ELEMENT] as $tagPrefix => $helper) {
139
            if (stripos($tagName, "$tagPrefix-") === 0) {
140
                $tagName = substr($tagName, strlen($tagPrefix) + 1);
141
                return $helper($element, $tagName, $method, $arguments);
142
            }
143
        }
144
145
        throw new LogicException("No \"{$method}()\" method defined in the HTML element.");
146
    }
147
148
    /**
149
     * @template T of HtmlComponent
150
     * @param string $name
151
     * @param array $arguments
152
     * @psalm-param class-string<T> $class
153
     *
154
     * @return T
0 ignored issues
show
Bug introduced by
The type Lagdo\UiBuilder\Engine\T 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...
155
     */
156
    public function createComponent(string $name, array $arguments = [],
157
        string $class = HtmlComponent::class): mixed
158
    {
159
        return new $class($this, $name, $arguments);
160
    }
161
162
    /**
163
     * @param array $arguments
164
     *
165
     * @return string
166
     */
167
    public function build(array $arguments): string
168
    {
169
        // The "root" component below will not be printed.
170
        $scope = new Scope($this->createComponent('root'));
171
        $scope->build($arguments);
172
        return $scope->html();
173
    }
174
}
175