Passed
Push — main ( ed843a...1402e3 )
by Thierry
02:16
created

UiBuilder::scope()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 1
b 0
f 0
1
<?php
2
3
namespace Lagdo\UiBuilder\Scope;
4
5
use Closure;
6
use Lagdo\UiBuilder\BuilderInterface;
7
use Lagdo\UiBuilder\Html\HtmlBuilder;
8
use Lagdo\UiBuilder\Scope\Scope;
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
use function trim;
17
18
class UiBuilder extends HtmlBuilder
19
{
20
    /**
21
     * @var array<string, Closure>
22
     */
23
    protected $tagBuilders = [];
24
25
    /**
26
     * @var Scope
27
     */
28
    protected $scope;
29
30
    /**
31
     * The constructor
32
     */
33
    public function __construct()
34
    {
35
        $this->addTagBuilder('set', function(BuilderInterface $builder, string $tagName, string $method, array $arguments) {
36
            if ($this->scope === null) {
37
                throw new LogicException('Attributes can be set for elements only');
38
            }
39
            $this->scope->attributes[$tagName] = $arguments[0] ?? null;
40
        });
41
        $this->addTagBuilder('form', function(BuilderInterface $builder, string $tagName, string $method, array $arguments) {
42
            $this->createScope($tagName, $arguments);
43
            // Prepend the UI framework class to the tag.
44
            $this->prependClass($this->_formTagClass($tagName));
0 ignored issues
show
Bug introduced by
$this->_formTagClass($tagName) of type void is incompatible with the type string expected by parameter $class of Lagdo\UiBuilder\Scope\UiBuilder::prependClass(). ( Ignorable by Annotation )

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

44
            $this->prependClass(/** @scrutinizer ignore-type */ $this->_formTagClass($tagName));
Loading history...
Bug introduced by
The method _formTagClass() does not exist on Lagdo\UiBuilder\Scope\UiBuilder. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

44
            $this->prependClass($this->/** @scrutinizer ignore-call */ _formTagClass($tagName));
Loading history...
Bug introduced by
Are you sure the usage of $this->_formTagClass($tagName) targeting Lagdo\UiBuilder\Scope\UiBuilder::__call() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
45
        });
46
    }
47
48
    /**
49
     * @return Scope|null
50
     */
51
    public function scope(): ?Scope
52
    {
53
        return $this->scope;
54
    }
55
56
    /**
57
     * @param string $tagPrefix
58
     * @param Closure $tagBuilder
59
     *
60
     * @return void
61
     */
62
    public function addTagBuilder(string $tagPrefix, Closure $tagBuilder)
63
    {
64
        // Do not overwrite existing builders.
65
        if(!isset($this->tagBuilders[$tagPrefix]))
66
        {
67
            $this->tagBuilders[$tagPrefix] = $tagBuilder;
68
        }
69
    }
70
71
    /**
72
     * @param string $method
73
     * @param array $arguments
74
     *
75
     * @return void
76
     * @throws LogicException When element is not initialized yet
77
     */
78
    public function make(string $method, array $arguments)
79
    {
80
        $tagName = strtolower(preg_replace('/(?<!^)([A-Z])/', '-$1', $method));
81
        foreach($this->tagBuilders as $tagPrefix => $tagBuilder)
82
        {
83
            if (stripos($tagName, $tagPrefix . '-') === 0) {
84
                $tagName = substr($tagName, strlen($tagPrefix) + 1);
85
                $tagBuilder($this, $tagName, $method, $arguments);
86
                return;
87
            }
88
        }
89
        $this->createScope($tagName, $arguments);
90
    }
91
92
    /**
93
     * @param string $name
94
     * @param string $value
95
     *
96
     * @return void
97
     */
98
    public function setAttribute(string $name, string $value)
99
    {
100
        $this->scope->attributes[$name] = $value;
101
    }
102
103
    /**
104
     * @param array $attributes
105
     *
106
     * @return self
107
     */
108
    public function setAttributes(array $attributes): self
109
    {
110
        foreach ($attributes as $name => $value) {
111
            $this->scope->attributes[$name] = $value;
112
        }
113
        return $this;
114
    }
115
116
    /**
117
     * @param string $name
118
     * @param array $arguments
119
     *
120
     * @return void
121
     */
122
    public function createScope(string $name, array $arguments = [])
123
    {
124
        $this->scope = new Scope($name, $arguments, $this->scope);
125
    }
126
127
    /**
128
     * @param string $name
129
     * @param array $arguments
130
     *
131
     * @return void
132
     */
133
    public function createWrapper(string $name, array $arguments = [])
134
    {
135
        $this->createScope($name, [$arguments]);
136
        $this->scope->isWrapper = true;
137
    }
138
139
    /**
140
     * Append a class to the existing one.
141
     *
142
     * @param string $class
143
     *
144
     * @return void
145
     */
146
    public function appendClass(string $class)
147
    {
148
        if ($this->scope === null) {
149
            throw new LogicException('Attributes can be set for elements only');
150
        }
151
        $class = ($this->scope->attributes['class'] ?? '') . ' ' . $class;
152
        $this->scope->attributes['class'] = trim($class);
153
    }
154
155
    /**
156
     * Prepend a class to the existing one.
157
     *
158
     * @param string $class
159
     *
160
     * @return void
161
     */
162
    public function prependClass(string $class)
163
    {
164
        if ($this->scope === null) {
165
            throw new LogicException('Attributes can be set for elements only');
166
        }
167
        $class .= ' ' . ($this->scope->attributes['class'] ?? '');
168
        $this->scope->attributes['class'] = trim($class);
169
    }
170
171
    /**
172
     * @return void
173
     */
174
    public function end()
175
    {
176
        parent::end();
177
        // Wrappers are scopes that were automatically added.
178
        // They also need to be automatically ended.
179
        while ($this->scope !== null && $this->scope->isWrapper) {
180
            parent::end();
181
        }
182
    }
183
184
    /**
185
     * @return void
186
     */
187
    public function endShorted()
188
    {
189
        parent::endShorted();
190
        // Wrappers are scopes that were automatically added.
191
        // They also need to be automatically ended.
192
        while ($this->scope !== null && $this->scope->isWrapper) {
193
            parent::end();
194
        }
195
    }
196
197
    /**
198
     * @return bool
199
     */
200
    public function isInputGroup(): bool
201
    {
202
        return $this->scope !== null && $this->scope->isInputGroup;
203
    }
204
}
205