Completed
Push — master ( 9a9f3c...33ba23 )
by Denis
01:26
created

AbstractElement::afterToParts()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Ngtfkx\Laradeck\FormBuilder\Elements;
4
5
6
use Illuminate\Support\Collection;
7
8
abstract class AbstractElement
9
{
10
    /**
11
     * @var Collection|iterable $classes Коллекция классом элемента
12
     */
13
    protected $classes;
14
15
    /**
16
     * @var Collection|iterable $attributes Коллекция дополнительных атрибутов элемента
17
     */
18
    protected $attributes;
19
20
    /**
21
     * @var Collection|iterable $styles Коллекция inline-стилей элемента
22
     */
23
    protected $styles;
24
25
    /**
26
     * @var string $value Значение элемента
27
     */
28
    protected $value;
29
30
    /**
31
     * @var string $tag Тег элемента
32
     */
33
    protected $tag;
34
35
    /**
36
     * @var Collection|iterable $parts Набор атрибутов для генерации html-кода элементов
37
     */
38
    protected $parts;
39
40
    /**
41
     * @var bool $needClose Признак, что надо закрывать тег элемента
42
     */
43
    protected $needClose = false;
44
45
    /**
46
     * @return void
47
     */
48
    abstract public function tag();
49
50
    public function __construct()
51
    {
52
        $this->classes = new Collection();
53
54
        $this->attributes = new Collection();
55
56
        $this->styles = new Collection();
57
58
        $this->parts = new Collection();
59
60
        $this->tag();
61
    }
62
63
    /**
64
     * Сеттер значения элемента
65
     *
66
     * @param string|null $value
67
     * @return AbstractElement
68
     */
69
    public function value(?string $value): self
70
    {
71
        $this->value = $value;
72
73
        return $this;
74
    }
75
76
    /**
77
     * Сеттер атрибута id элемента
78
     *
79
     * @param string|null $value
80
     * @return AbstractElement
81
     */
82
    public function id(?string $value): self
83
    {
84
        $this->attr('id', $value);
85
86
        return $this;
87
    }
88
89
    /**
90
     * Сеттер атрибута name элемента
91
     *
92
     * @param string|null $value
93
     * @return AbstractElement
94
     */
95
    public function name(?string $value): self
96
    {
97
        $this->attr('name', $value);
98
99
        return $this;
100
    }
101
102
    /**
103
     * Добавить элементу один или несколько классов
104
     *
105
     * @param array ...$classes
106
     * @return AbstractElement
107
     */
108
    public function class(...$classes): self
0 ignored issues
show
Coding Style introduced by
Possible parse error: non-abstract method defined as abstract
Loading history...
Coding Style introduced by
It is generally advisable to only define one property per statement.

Only declaring a single property per statement allows you to later on add doc comments more easily.

It is also recommended by PSR2, so it is a common style that many people expect.

Loading history...
109
    {
110
        $this->classes($classes);
0 ignored issues
show
Documentation introduced by
$classes is of type array<integer,array>, but the function expects a object<Ngtfkx\Laradeck\F...lder\Elements\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
111
112
        return $this;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $this.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
113
    }
114
115
    /**
116
     *  Добавить элементу один или несколько классов из массива
117
     *
118
     * @param iterable $classes
119
     * @return AbstractElement
120
     */
121
    public function classes(iterable $classes): self
122
    {
123
        foreach ($classes as $class) {
124
            if (!$this->classes->contains($class)) {
125
                $this->classes->push($class);
126
            }
127
        }
128
129
        return $this;
130
    }
131
132
    /**
133
     * Добавить к элементу один или несколько inline-стилей
134
     *
135
     * @param string $key
136
     * @param string|null $value
137
     * @return AbstractElement
138
     */
139
    public function style(string $key, string $value = null): self
140
    {
141
        if (empty($value)) {
142
            $pos = strpos($key, ':', 2);
143
            if ($pos !== false) {
144
                $parts = explode(':', strrev($key));
145
                $key = strrev($parts[1]);
146
                $value = strrev($parts[0]);
147
            }
148
        }
149
150
        if ($key && $value) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $value of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
151
            $this->styles->put($key, $value);
152
        }
153
154
        return $this;
155
    }
156
157
    /**
158
     * Добавить к элементу один или несколько inline-стилей из массива
159
     *
160
     * @param iterable $styles
161
     * @return AbstractElement
162
     */
163
    public function styles(iterable $styles): self
164
    {
165
        foreach ($styles as $key => $value) {
166
            $this->styles->put($key, $value);
167
        }
168
169
        return $this;
170
    }
171
172
    /**
173
     * Добавить аттрибут к элементу
174
     *
175
     * @param string $key
176
     * @param mixed $value
177
     * @return AbstractElement
178
     */
179
    public function attr(string $key, $value = null): self
180
    {
181
        $this->attributes->put($key, $value);
182
183
        return $this;
184
    }
185
186
    /**
187
     * Добавить один или несколько атрибутов из массива к элементу
188
     *
189
     * @param iterable $attributes
190
     * @return AbstractElement
191
     */
192
    public function attrs(iterable $attributes): self
193
    {
194
        foreach ($attributes as $key => $value) {
195
            if ($key === 'class') {
196
                $this->class($value);
197
            } else if ($key === 'style') {
198
                $this->style($value);
199
            } else {
200
                $this->attributes->put($key, $value);
201
            }
202
        }
203
204
        return $this;
205
    }
206
207
    /**
208
     * Очистить классы элемента
209
     *
210
     * @return AbstractElement
211
     */
212
    public function clearClasses(): self
213
    {
214
        $this->classes = new Collection();
215
216
        return $this;
217
    }
218
219
    /**
220
     * Очистить классы стили
221
     *
222
     * @return AbstractElement
223
     */
224
    public function clearStyles(): self
225
    {
226
        $this->styles = new Collection();
227
228
        return $this;
229
    }
230
231
    /**
232
     * Очистить классы атрибуты
233
     *
234
     * @return AbstractElement
235
     */
236
    public function clearAttributes(): self
237
    {
238
        $this->attributes = new Collection();
239
240
        return $this;
241
    }
242
243
    protected function render(): string
244
    {
245
        $attributes = $this->generateAttributes();
246
247
        return '<' . $this->tag . $attributes . '>';
248
    }
249
250
    protected function beforeToParts(): void
251
    {
252
        $this->addAttr('value');
253
    }
254
255
    protected  function afterToParts(): void
256
    {
257
258
    }
259
260
    /**
261
     * Преобразовать в строку для вывода в HTML
262
     *
263
     * @return string
264
     */
265
    public function __toString(): string
266
    {
267
        $this->beforeToParts();
268
269
        $this->classesToParts();
270
271
        $this->stylesToParts();
272
273
        $this->attributesToParts();
274
275
        $this->afterToParts();
276
277
        return $this->render();
278
    }
279
280
    protected function generateAttributes(): string
281
    {
282
        $attributes = '';
283
284
        foreach ($this->parts as $key => $value) {
285
            if (is_null($value) || (is_bool($value) && $value === false)) {
286
                continue;
287
            } else if (is_bool($value)) {
288
                $value = $key;
289
            }
290
            $attributes .= ' ' . $key . '="' . $value . '"';
291
        }
292
293
        return $attributes;
294
    }
295
296
    protected function stylesToParts(): void
297
    {
298
        if ($this->styles->isNotEmpty()) {
299
            $this->parts->put('style', $this->styles->pipe(function ($styles) {
300
                $styleAttr = '';
301
                foreach ($styles as $key => $value) {
302
                    $styleAttr .= $key . ':' . $value . ';';
303
                }
304
305
                return $styleAttr;
306
            }));
307
        }
308
    }
309
310
    protected function classesToParts(): void
311
    {
312
        if ($this->classes->isNotEmpty()) {
313
            $this->parts->put('class', $this->classes->implode(' '));
314
        }
315
    }
316
317
    public function attributesToParts(): void
318
    {
319
        foreach ($this->attributes as $key => $value) {
320
            $this->parts->put($key, $value);
321
        }
322
    }
323
324
    protected function addAttr(...$names): self
325
    {
326
        foreach ($names as $name) {
327
            if (!empty($this->$name)) {
328
                $this->parts[$name] = $this->$name;
329
            }
330
        }
331
332
        return $this;
333
    }
334
335
    protected function addAttrAs(...$names): self
336
    {
337
        foreach ($names as $name) {
338
            if (!empty($this->$name)) {
339
                $this->parts[$name] = $name;
340
            }
341
        }
342
343
        return $this;
344
    }
345
}