Completed
Push — 1.x ( 5c883c...dbb510 )
by Pol
05:33 queued 04:22
created

Attributes::contains()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 2
1
<?php
2
3
namespace drupol\htmltag;
4
5
/**
6
 * Class Attributes.
7
 */
8
class Attributes implements \ArrayAccess, \IteratorAggregate
9
{
10
    /**
11
     * Stores the attribute data.
12
     *
13
     * @var \drupol\htmltag\Attribute[]
14
     */
15
    private $storage = array();
16
17
    /**
18
     * {@inheritdoc}
19
     */
20 13
    public function __construct(array $attributes = array())
21
    {
22 13
        foreach ($attributes as $name => $value) {
23
            $this->storage[$name] = new Attribute(
24
                $name,
25
                $this->ensureString($value)
26
            );
27
        }
28 13
    }
29
30
    /**
31
     * {@inheritdoc}
32
     */
33 2
    public function &offsetGet($name)
34
    {
35 2
        if (!isset($this->storage[$name])) {
36 2
            $this->storage[$name] = new Attribute(
37 2
                $name
38
            );
39
        }
40
41 2
        return $this->storage[$name];
42
    }
43
44
    /**
45
     * {@inheritdoc}
46
     */
47
    public function offsetSet($name, $value = null)
48
    {
49
        $this->storage[$name] = new Attribute(
50
            $name,
51
            $this->ensureString($value)
52
        );
53
    }
54
55
    /**
56
     * {@inheritdoc}
57
     */
58
    public function offsetUnset($name)
59
    {
60
        unset($this->storage[$name]);
61
    }
62
63
    /**
64
     * {@inheritdoc}
65
     */
66
    public function offsetExists($name)
67
    {
68
        return isset($this->storage[$name]);
69
    }
70
71
    /**
72
     * Append a value into an attribute.
73
     *
74
     * @param string $key
75
     *   The attribute's name.
76
     * @param string|array|bool $value
77
     *   The attribute's value.
78
     *
79
     * @return $this
80
     */
81 7
    public function append($key, $value = null)
82
    {
83
        $this->storage += array(
84 7
            $key => new Attribute(
85 7
                $key,
86 7
                $this->ensureString($value)
87
            )
88
        );
89
90 7
        foreach ($this->normalizeValue($value) as $value_item) {
91 6
            $this->storage[$key]->append($value_item);
92
        }
93
94 7
        return $this;
95
    }
96
97
    /**
98
     * Remove a value from a specific attribute.
99
     *
100
     * @param string $key
101
     *   The attribute's name.
102
     * @param string|array|bool $value
103
     *   The attribute's value.
104
     *
105
     * @return $this
106
     */
107 2
    public function remove($key, $value = false)
108
    {
109 2
        if (!isset($this->storage[$key])) {
110 1
            return $this;
111
        }
112
113 1
        foreach ($this->normalizeValue($value) as $value_item) {
114 1
            $this->storage[$key]->remove($value_item);
115
        }
116
117 1
        return $this;
118
    }
119
120
    /**
121
     * Delete an attribute.
122
     *
123
     * @param string|array $name
124
     *   The name of the attribute key to delete.
125
     *
126
     * @return $this
127
     */
128 1
    public function delete($name = array())
129
    {
130 1
        foreach ($this->normalizeValue($name) as $attribute_name) {
131 1
            unset($this->storage[$attribute_name]);
132
        }
133
134 1
        return $this;
135
    }
136
137
    /**
138
     * Return the attributes.
139
     *
140
     * @param string $key
141
     *   The attributes's name.
142
     * @param array|string $value
143
     *   The attribute's value.
144
     *
145
     * @return \drupol\htmltag\Attributes
146
     */
147
    public function without($key, $value)
148
    {
149
        $attributes = clone $this;
150
151
        return $attributes->remove($key, $value);
152
    }
153
154
    /**
155
     * Replace a value with another.
156
     *
157
     * @param string $key
158
     *   The attributes's name.
159
     * @param string $value
160
     *   The attribute's value.
161
     * @param array|string $replacement
162
     *   The replacement value.
163
     *
164
     * @return $this
165
     */
166 1
    public function replace($key, $value, $replacement)
167
    {
168
        $this->storage += array(
169 1
            $key => new Attribute(
170 1
                $key,
171 1
                $this->ensureString($value)
172
            )
173
        );
174
175 1
        $this->storage[$key]->remove($value);
176 1
        foreach ($this->normalizeValue($replacement) as $replacement_value) {
177 1
            $this->storage[$key]->append($replacement_value);
178
        }
179
180 1
        return $this;
181
    }
182
183
    /**
184
     * Merge attributes.
185
     *
186
     * @param array $data
187
     *   The data to merge.
188
     *
189
     * @return $this
190
     */
191 1
    public function merge(array $data = array())
192
    {
193 1
        foreach ($data as $key => $value) {
194
            $this->storage += array(
195 1
                $key => new Attribute(
196 1
                    $key
197
                )
198
            );
199
200 1
            $this->storage[$key]->merge(
201 1
                $this->normalizeValue($value)
202
            );
203
        }
204
205 1
        return $this;
206
    }
207
208
    /**
209
     * Check if an attribute exists and if a value if provided check it as well.
210
     *
211
     * @param string $key
212
     *   Attribute name.
213
     * @param string $value
214
     *   Todo.
215
     *
216
     * @return bool
217
     *   Whereas an attribute exists.
218
     */
219 1
    public function exists($key, $value = null)
220
    {
221 1
        if (!isset($this->storage[$key])) {
222 1
            return false;
223
        }
224
225 1
        if (null !== $value) {
226 1
            return $this->contains($key, $value);
227
        }
228
229 1
        return true;
230
    }
231
232
    /**
233
     * Check if attribute contains a value.
234
     *
235
     * @param string $key
236
     *   Attribute name.
237
     * @param string $value
238
     *   Attribute value.
239
     *
240
     * @return bool
241
     *   Whereas an attribute contains a value.
242
     */
243 2
    public function contains($key, $value)
244
    {
245 2
        if (!isset($this->storage[$key])) {
246 1
            return false;
247
        }
248
249 2
        return $this->storage[$key]->contains($value);
250
    }
251
252
    /**
253
     * {@inheritdoc}
254
     */
255 8
    public function __toString()
256
    {
257 8
        return $this->render();
258
    }
259
260
    /**
261
     * Render the attributes.
262
     */
263 8
    public function render()
264
    {
265
        // If empty, just return an empty string.
266 8
        if ([] === $this->storage) {
267 3
            return '';
268
        }
269
270 7
        $attributes = implode(' ', $this->prepareValues());
271
272 7
        return $attributes ? ' ' . $attributes : '';
273
    }
274
275
    /**
276
     * Returns all storage elements as an array.
277
     *
278
     * @return array
279
     *   An associative array of attributes.
280
     */
281
    public function toArray()
282
    {
283
        $attributes = $this->storage;
284
285
        // If empty, just return an empty array.
286
        if (empty($attributes)) {
287
            return array();
288
        }
289
290
        $result = [];
291
292
        foreach ($this->prepareValues() as $attribute) {
293
            $result[$attribute->getName()] = $attribute->getValueAsArray();
294
        }
295
296
        return $result;
297
    }
298
299
    /**
300
     * Get storage.
301
     *
302
     * @return \drupol\htmltag\Attribute[]
303
     *   Todo.
304
     */
305
    public function getStorage()
306
    {
307
        return $this->storage;
308
    }
309
310
    /**
311
     * {@inheritdoc}
312
     */
313
    public function getIterator()
314
    {
315
        return new \ArrayIterator($this->toArray());
316
    }
317
318
    /**
319
     * Returns all storage elements as an array.
320
     *
321
     * @return \drupol\htmltag\Attribute[]
322
     *   An associative array of attributes.
323
     */
324 7
    private function prepareValues()
325
    {
326 7
        $attributes = $this->storage;
327
328
        // If empty, just return an empty array.
329 7
        if (empty($attributes)) {
330
            return array();
331
        }
332
333
        // Sort the attributes.
334 7
        ksort($attributes);
335
336 7
        $result = [];
337
338 7
        foreach ($attributes as $attribute_name => $attribute) {
339 7
            switch ($attribute_name) {
340 7
                case 'class':
341 6
                    $classes = $attribute->getValueAsArray();
342 6
                    asort($classes);
343 6
                    $result[$attribute->getName()] = $attribute->set(
344 6
                        implode(' ', $classes)
345
                    );
346 6
                    break;
347
348
                default:
349 7
                    $result[$attribute->getName()] = $attribute;
350
            }
351
        }
352
353 7
        return $result;
354
    }
355
356
    /**
357
     * Normalize a value.
358
     *
359
     * @param mixed $value
360
     *  The value to normalize.
361
     *
362
     * @return array
363
     *   The value normalized.
364
     */
365 7
    private function normalizeValue($value)
366
    {
367 7
        return $this->ensureFlatArray($value);
368
    }
369
370
    /**
371
     * Todo.
372
     *
373
     * @param mixed $value
374
     *   Todo.
375
     *
376
     * @return array
377
     *   The array, flattened.
378
     */
379 7
    private function ensureFlatArray($value)
380
    {
381 7
        $type = gettype($value);
382
383 7
        $return = array();
384
385 7
        switch ($type) {
386 7
            case 'string':
387 6
                $return = explode(
388 6
                    ' ',
389 6
                    $this->ensureString($value)
390
                );
391 6
                break;
392
393 6
            case 'array':
394 1
                $flat_array = iterator_to_array(
395 1
                    new \RecursiveIteratorIterator(
396 1
                        new \RecursiveArrayIterator(
397 1
                            $value
398
                        )
399
                    ),
400 1
                    false
401
                );
402
403 1
                $return = [];
404 1
                foreach ($flat_array as $item) {
405 1
                    $return = array_merge(
406 1
                        $return,
407 1
                        $this->normalizeValue($item)
408
                    );
409
                }
410 1
                break;
411
412 6
            case 'double':
413 6
            case 'integer':
414
                $return = array($value);
415
                break;
416 6
            case 'object':
417 6
            case 'boolean':
418 6
            case 'resource':
419 6
            case 'NULL':
420
        }
421
422 7
        return $return;
423
    }
424
425
    /**
426
     * Todo.
427
     *
428
     * @param mixed $value
429
     *   Todo.
430
     *
431
     * @return string
432
     *   A string.
433
     */
434 7
    private function ensureString($value)
435
    {
436 7
        $type = gettype($value);
437
438 7
        $return = '';
439
440 7
        switch ($type) {
441 7
            case 'string':
442 6
                $return = $value;
443 6
                break;
444
445 6
            case 'array':
446
                $return = implode(
447
                    ' ',
448
                    $this->ensureFlatArray($value)
449
                );
450
                break;
451
452 6
            case 'double':
453 6
            case 'integer':
454
                $return = (string) $value;
455
                break;
456 6
            case 'object':
457 6
            case 'boolean':
458 6
            case 'resource':
459 6
            case 'NULL':
460
        }
461
462 7
        return $return;
463
    }
464
}
465