Subversion-Projekte lars-tiefland.laravel_shop

Revision

Revision 148 | Details | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\View;
4
 
5
use ArrayAccess;
6
use ArrayIterator;
7
use Illuminate\Contracts\Support\Htmlable;
8
use Illuminate\Support\Arr;
9
use Illuminate\Support\HtmlString;
10
use Illuminate\Support\Str;
11
use Illuminate\Support\Traits\Conditionable;
12
use Illuminate\Support\Traits\Macroable;
13
use IteratorAggregate;
14
use Traversable;
15
 
16
class ComponentAttributeBag implements ArrayAccess, Htmlable, IteratorAggregate
17
{
18
    use Conditionable, Macroable;
19
 
20
    /**
21
     * The raw array of attributes.
22
     *
23
     * @var array
24
     */
25
    protected $attributes = [];
26
 
27
    /**
28
     * Create a new component attribute bag instance.
29
     *
30
     * @param  array  $attributes
31
     * @return void
32
     */
33
    public function __construct(array $attributes = [])
34
    {
35
        $this->attributes = $attributes;
36
    }
37
 
38
    /**
39
     * Get the first attribute's value.
40
     *
41
     * @param  mixed  $default
42
     * @return mixed
43
     */
44
    public function first($default = null)
45
    {
46
        return $this->getIterator()->current() ?? value($default);
47
    }
48
 
49
    /**
50
     * Get a given attribute from the attribute array.
51
     *
52
     * @param  string  $key
53
     * @param  mixed  $default
54
     * @return mixed
55
     */
56
    public function get($key, $default = null)
57
    {
58
        return $this->attributes[$key] ?? value($default);
59
    }
60
 
61
    /**
62
     * Determine if a given attribute exists in the attribute array.
63
     *
64
     * @param  string  $key
65
     * @return bool
66
     */
67
    public function has($key)
68
    {
69
        return array_key_exists($key, $this->attributes);
70
    }
71
 
72
    /**
73
     * Determine if a given attribute is missing from the attribute array.
74
     *
75
     * @param  string  $key
76
     * @return bool
77
     */
78
    public function missing($key)
79
    {
80
        return ! $this->has($key, $this->attributes);
81
    }
82
 
83
    /**
84
     * Only include the given attribute from the attribute array.
85
     *
86
     * @param  mixed  $keys
87
     * @return static
88
     */
89
    public function only($keys)
90
    {
91
        if (is_null($keys)) {
92
            $values = $this->attributes;
93
        } else {
94
            $keys = Arr::wrap($keys);
95
 
96
            $values = Arr::only($this->attributes, $keys);
97
        }
98
 
99
        return new static($values);
100
    }
101
 
102
    /**
103
     * Exclude the given attribute from the attribute array.
104
     *
105
     * @param  mixed|array  $keys
106
     * @return static
107
     */
108
    public function except($keys)
109
    {
110
        if (is_null($keys)) {
111
            $values = $this->attributes;
112
        } else {
113
            $keys = Arr::wrap($keys);
114
 
115
            $values = Arr::except($this->attributes, $keys);
116
        }
117
 
118
        return new static($values);
119
    }
120
 
121
    /**
122
     * Filter the attributes, returning a bag of attributes that pass the filter.
123
     *
124
     * @param  callable  $callback
125
     * @return static
126
     */
127
    public function filter($callback)
128
    {
129
        return new static(collect($this->attributes)->filter($callback)->all());
130
    }
131
 
132
    /**
133
     * Return a bag of attributes that have keys starting with the given value / pattern.
134
     *
135
     * @param  string|string[]  $needles
136
     * @return static
137
     */
138
    public function whereStartsWith($needles)
139
    {
140
        return $this->filter(function ($value, $key) use ($needles) {
141
            return Str::startsWith($key, $needles);
142
        });
143
    }
144
 
145
    /**
146
     * Return a bag of attributes with keys that do not start with the given value / pattern.
147
     *
148
     * @param  string|string[]  $needles
149
     * @return static
150
     */
151
    public function whereDoesntStartWith($needles)
152
    {
153
        return $this->filter(function ($value, $key) use ($needles) {
154
            return ! Str::startsWith($key, $needles);
155
        });
156
    }
157
 
158
    /**
159
     * Return a bag of attributes that have keys starting with the given value / pattern.
160
     *
161
     * @param  string|string[]  $needles
162
     * @return static
163
     */
164
    public function thatStartWith($needles)
165
    {
166
        return $this->whereStartsWith($needles);
167
    }
168
 
169
    /**
170
     * Only include the given attribute from the attribute array.
171
     *
172
     * @param  mixed|array  $keys
173
     * @return static
174
     */
175
    public function onlyProps($keys)
176
    {
177
        return $this->only($this->extractPropNames($keys));
178
    }
179
 
180
    /**
181
     * Exclude the given attribute from the attribute array.
182
     *
183
     * @param  mixed|array  $keys
184
     * @return static
185
     */
186
    public function exceptProps($keys)
187
    {
188
        return $this->except($this->extractPropNames($keys));
189
    }
190
 
191
    /**
192
     * Extract prop names from given keys.
193
     *
194
     * @param  mixed|array  $keys
195
     * @return array
196
     */
197
    protected function extractPropNames($keys)
198
    {
199
        $props = [];
200
 
201
        foreach ($keys as $key => $defaultValue) {
202
            $key = is_numeric($key) ? $defaultValue : $key;
203
 
204
            $props[] = $key;
205
            $props[] = Str::kebab($key);
206
        }
207
 
208
        return $props;
209
    }
210
 
211
    /**
212
     * Conditionally merge classes into the attribute bag.
213
     *
214
     * @param  mixed|array  $classList
215
     * @return static
216
     */
217
    public function class($classList)
218
    {
219
        $classList = Arr::wrap($classList);
220
 
221
        return $this->merge(['class' => Arr::toCssClasses($classList)]);
222
    }
223
 
224
    /**
399 lars 225
     * Conditionally merge styles into the attribute bag.
226
     *
227
     * @param  mixed|array  $styleList
228
     * @return static
229
     */
230
    public function style($styleList)
231
    {
232
        $styleList = Arr::wrap($styleList);
233
 
234
        return $this->merge(['style' => Arr::toCssStyles($styleList)]);
235
    }
236
 
237
    /**
148 lars 238
     * Merge additional attributes / values into the attribute bag.
239
     *
240
     * @param  array  $attributeDefaults
241
     * @param  bool  $escape
242
     * @return static
243
     */
244
    public function merge(array $attributeDefaults = [], $escape = true)
245
    {
246
        $attributeDefaults = array_map(function ($value) use ($escape) {
247
            return $this->shouldEscapeAttributeValue($escape, $value)
248
                        ? e($value)
249
                        : $value;
250
        }, $attributeDefaults);
251
 
252
        [$appendableAttributes, $nonAppendableAttributes] = collect($this->attributes)
253
                    ->partition(function ($value, $key) use ($attributeDefaults) {
399 lars 254
                        return $key === 'class' || $key === 'style' || (
255
                            isset($attributeDefaults[$key]) &&
256
                            $attributeDefaults[$key] instanceof AppendableAttributeValue
257
                        );
148 lars 258
                    });
259
 
260
        $attributes = $appendableAttributes->mapWithKeys(function ($value, $key) use ($attributeDefaults, $escape) {
261
            $defaultsValue = isset($attributeDefaults[$key]) && $attributeDefaults[$key] instanceof AppendableAttributeValue
262
                        ? $this->resolveAppendableAttributeDefault($attributeDefaults, $key, $escape)
263
                        : ($attributeDefaults[$key] ?? '');
264
 
399 lars 265
            if ($key === 'style') {
266
                $value = Str::finish($value, ';');
267
            }
268
 
148 lars 269
            return [$key => implode(' ', array_unique(array_filter([$defaultsValue, $value])))];
270
        })->merge($nonAppendableAttributes)->all();
271
 
272
        return new static(array_merge($attributeDefaults, $attributes));
273
    }
274
 
275
    /**
276
     * Determine if the specific attribute value should be escaped.
277
     *
278
     * @param  bool  $escape
279
     * @param  mixed  $value
280
     * @return bool
281
     */
282
    protected function shouldEscapeAttributeValue($escape, $value)
283
    {
284
        if (! $escape) {
285
            return false;
286
        }
287
 
288
        return ! is_object($value) &&
289
               ! is_null($value) &&
290
               ! is_bool($value);
291
    }
292
 
293
    /**
294
     * Create a new appendable attribute value.
295
     *
296
     * @param  mixed  $value
297
     * @return \Illuminate\View\AppendableAttributeValue
298
     */
299
    public function prepends($value)
300
    {
301
        return new AppendableAttributeValue($value);
302
    }
303
 
304
    /**
305
     * Resolve an appendable attribute value default value.
306
     *
307
     * @param  array  $attributeDefaults
308
     * @param  string  $key
309
     * @param  bool  $escape
310
     * @return mixed
311
     */
312
    protected function resolveAppendableAttributeDefault($attributeDefaults, $key, $escape)
313
    {
314
        if ($this->shouldEscapeAttributeValue($escape, $value = $attributeDefaults[$key]->value)) {
315
            $value = e($value);
316
        }
317
 
318
        return $value;
319
    }
320
 
321
    /**
322
     * Get all of the raw attributes.
323
     *
324
     * @return array
325
     */
326
    public function getAttributes()
327
    {
328
        return $this->attributes;
329
    }
330
 
331
    /**
332
     * Set the underlying attributes.
333
     *
334
     * @param  array  $attributes
335
     * @return void
336
     */
337
    public function setAttributes(array $attributes)
338
    {
339
        if (isset($attributes['attributes']) &&
340
            $attributes['attributes'] instanceof self) {
341
            $parentBag = $attributes['attributes'];
342
 
343
            unset($attributes['attributes']);
344
 
345
            $attributes = $parentBag->merge($attributes, $escape = false)->getAttributes();
346
        }
347
 
348
        $this->attributes = $attributes;
349
    }
350
 
351
    /**
352
     * Get content as a string of HTML.
353
     *
354
     * @return string
355
     */
356
    public function toHtml()
357
    {
358
        return (string) $this;
359
    }
360
 
361
    /**
362
     * Merge additional attributes / values into the attribute bag.
363
     *
364
     * @param  array  $attributeDefaults
365
     * @return \Illuminate\Support\HtmlString
366
     */
367
    public function __invoke(array $attributeDefaults = [])
368
    {
369
        return new HtmlString((string) $this->merge($attributeDefaults));
370
    }
371
 
372
    /**
373
     * Determine if the given offset exists.
374
     *
375
     * @param  string  $offset
376
     * @return bool
377
     */
378
    public function offsetExists($offset): bool
379
    {
380
        return isset($this->attributes[$offset]);
381
    }
382
 
383
    /**
384
     * Get the value at the given offset.
385
     *
386
     * @param  string  $offset
387
     * @return mixed
388
     */
389
    public function offsetGet($offset): mixed
390
    {
391
        return $this->get($offset);
392
    }
393
 
394
    /**
395
     * Set the value at a given offset.
396
     *
397
     * @param  string  $offset
398
     * @param  mixed  $value
399
     * @return void
400
     */
401
    public function offsetSet($offset, $value): void
402
    {
403
        $this->attributes[$offset] = $value;
404
    }
405
 
406
    /**
407
     * Remove the value at the given offset.
408
     *
409
     * @param  string  $offset
410
     * @return void
411
     */
412
    public function offsetUnset($offset): void
413
    {
414
        unset($this->attributes[$offset]);
415
    }
416
 
417
    /**
418
     * Get an iterator for the items.
419
     *
420
     * @return \ArrayIterator
421
     */
422
    public function getIterator(): Traversable
423
    {
424
        return new ArrayIterator($this->attributes);
425
    }
426
 
427
    /**
428
     * Implode the attributes into a single HTML ready string.
429
     *
430
     * @return string
431
     */
432
    public function __toString()
433
    {
434
        $string = '';
435
 
436
        foreach ($this->attributes as $key => $value) {
437
            if ($value === false || is_null($value)) {
438
                continue;
439
            }
440
 
441
            if ($value === true) {
442
                $value = $key;
443
            }
444
 
445
            $string .= ' '.$key.'="'.str_replace('"', '\\"', trim($value)).'"';
446
        }
447
 
448
        return trim($string);
449
    }
450
}