Completed
Push — master ( 60ac2f...695cd7 )
by Denis
01:32
created

AbstractElement::beforeCommonPrepareToRender()   B

Complexity

Conditions 7
Paths 8

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 8
nc 8
nop 0
dl 0
loc 16
rs 8.2222
c 0
b 0
f 0
1
<?php
2
3
namespace Ngtfkx\Laradeck\FormBuilder\Elements;
4
5
6
use Illuminate\Support\Collection;
7
use Ngtfkx\Laradeck\FormBuilder\Layouts\AbstractLayout;
8
use Ngtfkx\Laradeck\FormBuilder\Render;
9
10
abstract class AbstractElement
11
{
12
    /**
13
     * @var Collection|iterable $classes Коллекция классом элемента
14
     */
15
    public $classes;
16
17
    /**
18
     * @var Collection|iterable $attributes Коллекция дополнительных атрибутов элемента
19
     */
20
    public $attributes;
21
22
    /**
23
     * @var Collection|iterable $styles Коллекция inline-стилей элемента
24
     */
25
    public $styles;
26
27
    /**
28
     * @var string $value Значение элемента
29
     */
30
    public $value;
31
32
    /**
33
     * @var string $tag Тег элемента
34
     */
35
    protected $tag;
36
37
    /**
38
     * @var Collection|iterable $parts Набор атрибутов для генерации html-кода элементов
39
     */
40
    public $parts;
41
42
    /**
43
     * @var string $label
44
     */
45
    public $label;
46
47
    /**
48
     * @var string $help
49
     */
50
    public $help;
51
52
    /**
53
     * @var AbstractLayout
54
     */
55
    public $layout;
56
57
    public $onlyTagRender = false;
58
59
    /**
60
     * Генерировать значение атрибутом
61
     *
62
     * @var bool
63
     */
64
    protected $valueAsAttribute = true;
65
66
    /**
67
     * @return void
68
     */
69
    abstract public function tag();
70
71
    public function __construct()
72
    {
73
        $this->classes = new Collection();
74
75
        $this->attributes = new Collection();
76
77
        $this->styles = new Collection();
78
79
        $this->parts = new Collection();
80
81
        $this->tag();
82
    }
83
84
    public function layout(?AbstractLayout $layout): self
85
    {
86
        $this->layout = $layout;
87
88
        return $this;
89
    }
90
91
    /**
92
     * Сеттер значения лейбла для элемента
93
     *
94
     * @param string|null $value
95
     * @return AbstractElement
96
     */
97
    public function label(?string $value): self
98
    {
99
        $this->label = $value;
100
101
        return $this;
102
    }
103
104
    /**
105
     * Сеттер значения подсказки для элемента
106
     *
107
     * @param string|null $value
108
     * @return AbstractElement
109
     */
110
    public function help(?string $value): self
111
    {
112
        $this->help = $value;
113
114
        return $this;
115
    }
116
117
    /**
118
     * Сеттер значения элемента
119
     *
120
     * @param string|null $value
121
     * @return AbstractElement
122
     */
123
    public function value(?string $value): self
124
    {
125
        $this->value = $value;
126
127
        return $this;
128
    }
129
130
    /**
131
     * Сеттер атрибута id элемента
132
     *
133
     * @param string|null $value
134
     * @return AbstractElement
135
     */
136
    public function id(?string $value): self
137
    {
138
        $this->attr('id', $value);
139
140
        return $this;
141
    }
142
143
    /**
144
     * Сеттер атрибута name элемента
145
     *
146
     * @param string|null $value
147
     * @return AbstractElement
148
     */
149
    public function name(?string $value): self
150
    {
151
        $this->attr('name', $value);
152
153
        return $this;
154
    }
155
156
    /**
157
     * Добавить элементу один или несколько классов
158
     *
159
     * @param array ...$classes
160
     * @return AbstractElement
161
     */
162
    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...
163
    {
164
        $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...
165
166
        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...
167
    }
168
169
    /**
170
     *  Добавить элементу один или несколько классов из массива
171
     *
172
     * @param iterable $classes
173
     * @return AbstractElement
174
     */
175
    public function classes(iterable $classes): self
176
    {
177
        foreach ($classes as $class) {
178
            if (!$this->classes->contains($class)) {
179
                $this->classes->push($class);
180
            }
181
        }
182
183
        return $this;
184
    }
185
186
    /**
187
     * Добавить к элементу один или несколько inline-стилей
188
     *
189
     * @param string $key
190
     * @param string|null $value
191
     * @return AbstractElement
192
     */
193
    public function style(string $key, string $value = null): self
194
    {
195
        if (empty($value)) {
196
            $pos = strpos($key, ':', 2);
197
            if ($pos !== false) {
198
                $parts = explode(':', strrev($key));
199
                $key = strrev($parts[1]);
200
                $value = strrev($parts[0]);
201
            }
202
        }
203
204
        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...
205
            $this->styles->put($key, $value);
206
        }
207
208
        return $this;
209
    }
210
211
    /**
212
     * Добавить к элементу один или несколько inline-стилей из массива
213
     *
214
     * @param iterable $styles
215
     * @return AbstractElement
216
     */
217
    public function styles(iterable $styles): self
218
    {
219
        foreach ($styles as $key => $value) {
220
            $this->styles->put($key, $value);
221
        }
222
223
        return $this;
224
    }
225
226
    /**
227
     * Добавить аттрибут к элементу
228
     *
229
     * @param string $key
230
     * @param string|null $value
231
     * @return AbstractElement
232
     */
233
    public function attr(string $key, $value = null): self
234
    {
235
        $this->attributes->put($key, $value);
236
237
        return $this;
238
    }
239
240
    /**
241
     * Добавить один или несколько атрибутов из массива к элементу
242
     *
243
     * @param iterable $attributes
244
     * @return AbstractElement
245
     */
246
    public function attrs(iterable $attributes): self
247
    {
248
        foreach ($attributes as $key => $value) {
249
            if ($key === 'class') {
250
                $this->class($value);
251
            } else if ($key === 'style') {
252
                $this->style($value);
253
            } else {
254
                $this->attributes->put($key, $value);
255
            }
256
        }
257
258
        return $this;
259
    }
260
261
    /**
262
     * Очистить классы элемента
263
     *
264
     * @return AbstractElement
265
     */
266
    public function clearClasses(): self
267
    {
268
        $this->classes = new Collection();
269
270
        return $this;
271
    }
272
273
    /**
274
     * Очистить классы стили
275
     *
276
     * @return AbstractElement
277
     */
278
    public function clearStyles(): self
279
    {
280
        $this->styles = new Collection();
281
282
        return $this;
283
    }
284
285
    /**
286
     * Очистить классы атрибуты
287
     *
288
     * @return AbstractElement
289
     */
290
    public function clearAttributes(): self
291
    {
292
        $this->attributes = new Collection();
293
294
        return $this;
295
    }
296
297
    public function getTagHtml()
298
    {
299
        return '<' . $this->tag . '**attributes**>';
300
    }
301
302
    public function beforeCommonPrepareToRender(): void
303
    {
304
        if ($this->valueAsAttribute) {
305
            $this->parts['value'] = $this->value;
306
        }
307
308
        $elementName = $this->getLowerClassName();
309
310
        if (is_null($this->layout) === false && $elementName && !in_array($elementName, $this->layout->skipCommonClassesForElements)) {
311
            $this->class($this->layout->getCommonClasses());
312
        }
313
314
        if (is_null($this->layout) === false && $this->layout->getElementClasses($elementName)) {
315
            $this->class($this->layout->getElementClasses($elementName));
316
        }
317
    }
318
319
    public function beforeElementPrepareToRender(): void
320
    {
321
322
    }
323
324
    public function afterCommonPrepareToRender(): void
325
    {
326
        /**
327
         * Если не задан id, то сгенерируем случайный
328
         */
329
        if ($this->parts->has('id') === false) {
330
            $this->parts->put('id', str_random(20));
331
        }
332
    }
333
334
    public function afterElementPrepareToRender(): void
335
    {
336
337
    }
338
339
    public function getLowerClassName(): string
340
    {
341
        return strtolower($this->getClassName());
342
    }
343
344
    public function getClassName(): string
345
    {
346
        return class_basename($this);
347
    }
348
349
    /**
350
     * Преобразовать в строку для вывода в HTML
351
     *
352
     * @return string
353
     */
354
    public function __toString(): string
355
    {
356
        return new Render($this);
357
    }
358
359
    protected function addAttrAs(...$names): self
360
    {
361
        foreach ($names as $name) {
362
            if (!empty($this->$name)) {
363
                $this->parts[$name] = $name;
364
            }
365
        }
366
367
        return $this;
368
    }
369
}