Completed
Push — 1.x ( bd3256...2ade27 )
by Pol
01:22
created

Attributes::prepareValues()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 5.2331

Importance

Changes 0
Metric Value
dl 0
loc 37
ccs 15
cts 19
cp 0.7895
rs 9.0168
c 0
b 0
f 0
cc 5
nc 5
nop 0
crap 5.2331
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 7
    public function __construct(array $attributes = array())
21
    {
22 7
        $this->setAttributes($attributes);
23 7
    }
24
25
    /**
26
     * Normalize a value.
27
     *
28
     * @param mixed $value
29
     *  The value to normalize.
30
     *
31
     * @return array
32
     *   The value normalized.
33
     */
34 3
    private function normalizeValue($value)
35
    {
36 3
        return $this->ensureFlatArray($value);
37
    }
38
39
    /**
40
     * Todo.
41
     *
42
     * @param mixed $value
43
     *   Todo.
44
     *
45
     * @return array
46
     *   The array, flattened.
47
     */
48 3
    private function ensureFlatArray($value)
49
    {
50 3
        $type = gettype($value);
51
52 3
        $return = array();
53
54
        switch ($type) {
55 3
            case 'string':
56 2
                $return = explode(
57 2
                    ' ',
58 2
                    $this->ensureString($value)
59
                );
60 2
                break;
61
62 2
            case 'array':
63
                $return = iterator_to_array(
64
                    new \RecursiveIteratorIterator(
65
                        new \RecursiveArrayIterator(
66
                            $value
67
                        )
68
                    ),
69
                    false
70
                );
71
                break;
72
73 2
            case 'double':
74 2
            case 'integer':
75
                $return = array($value);
76
                break;
77 2
            case 'object':
78 2
            case 'boolean':
79 2
            case 'resource':
80 2
            case 'NULL':
81
        }
82
83 3
        return $return;
84
    }
85
86
    /**
87
     * Todo.
88
     *
89
     * @param mixed $value
90
     *   Todo.
91
     *
92
     * @return string
93
     *   A string.
94
     */
95 3
    private function ensureString($value)
96
    {
97 3
        $type = gettype($value);
98
99 3
        $return = '';
100
101
        switch ($type) {
102 3
            case 'string':
103 2
                $return = $value;
104 2
                break;
105
106 2
            case 'array':
107
                $return = implode(
108
                    ' ',
109
                    $this->ensureFlatArray($value)
110
                );
111
                break;
112
113 2
            case 'double':
114 2
            case 'integer':
115
                 $return = (string) $value;
116
                break;
117 2
            case 'object':
118 2
            case 'boolean':
119 2
            case 'resource':
120 2
            case 'NULL':
121
        }
122
123 3
        return $return;
124
    }
125
126
    /**
127
     * Set attributes.
128
     *
129
     * @param array|Attributes $attributes
130
     *   The attributes.
131
     *
132
     * @return $this
133
     */
134 7
    public function setAttributes($attributes = array())
135
    {
136 7
        foreach ($attributes as $name => $value) {
137
            $this->storage[$name] = new Attribute(
138
                $name,
139
                $this->ensureString($value)
140
            );
141
        }
142
143 7
        return $this;
144
    }
145
146
    /**
147
     * {@inheritdoc}
148
     */
149 1
    public function &offsetGet($name)
150
    {
151 1
        if (!isset($this->storage[$name])) {
152 1
            $attribute = new Attribute(
153 1
                $name
154
            );
155 1
            $this->storage[$attribute->getName()] = $attribute;
156
        }
157
158 1
        return $this->storage[$name];
159
    }
160
161
    /**
162
     * {@inheritdoc}
163
     */
164
    public function offsetSet($name, $value = null)
165
    {
166
        $this->storage[$name] = new Attribute(
167
            $name,
168
            $this->ensureString($value)
169
        );
170
    }
171
172
    /**
173
     * {@inheritdoc}
174
     */
175
    public function offsetUnset($name)
176
    {
177
        unset($this->storage[$name]);
178
    }
179
180
    /**
181
     * {@inheritdoc}
182
     */
183
    public function offsetExists($name)
184
    {
185
        return isset($this->storage[$name]);
186
    }
187
188
    /**
189
     * Sets values for an attribute key.
190
     *
191
     * @param string $attribute
192
     *   Name of the attribute.
193
     * @param string|array|bool $value
194
     *   Value(s) to set for the given attribute key.
195
     *
196
     * @return $this
197
     */
198
    public function setAttribute($attribute, $value = false)
199
    {
200
        $this->offsetSet($attribute, $value);
201
202
        return $this;
203
    }
204
205
    /**
206
     * Append a value into an attribute.
207
     *
208
     * @param string $key
209
     *   The attribute's name.
210
     * @param string|array|bool $value
211
     *   The attribute's value.
212
     *
213
     * @return $this
214
     */
215 3 View Code Duplication
    public function append($key, $value = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
216
    {
217
        $this->storage += array(
218 3
            $key => new Attribute(
219 3
                $key,
220 3
                $this->ensureString($value)
221
            )
222
        );
223
224 3
        $value = $this->normalizeValue($value);
225
226 3
        foreach ($value as $value_item) {
227 2
            $this->storage[$key]->append($value_item);
228
        }
229
230 3
        return $this;
231
    }
232
233
    /**
234
     * Remove a value from a specific attribute.
235
     *
236
     * @param string $key
237
     *   The attribute's name.
238
     * @param string|array|bool $value
239
     *   The attribute's value.
240
     *
241
     * @return $this
242
     */
243 2
    public function remove($key, $value = false)
244
    {
245 2
        if (!isset($this->storage[$key])) {
246 1
            return $this;
247
        }
248
249 1
        $value = $this->normalizeValue($value);
250
251 1
        foreach ($value as $value_item) {
252 1
            $this->storage[$key]->remove($value_item);
253
        }
254
255 1
        return $this;
256
    }
257
258
    /**
259
     * Delete an attribute.
260
     *
261
     * @param string|array $name
262
     *   The name of the attribute key to delete.
263
     *
264
     * @return $this
265
     */
266 1
    public function delete($name = array())
267
    {
268 1
        $name = $this->normalizeValue($name);
269
270 1
        foreach ($name as $attribute_name) {
271 1
            unset($this->storage[$attribute_name]);
272
        }
273
274 1
        return $this;
275
    }
276
277
    /**
278
     * Return the attributes.
279
     *
280
     * @param string $key
281
     *   The attributes's name.
282
     * @param array|string $value
283
     *   The attribute's value.
284
     *
285
     * @return \drupol\htmltag\Attributes
286
     */
287
    public function without($key, $value)
288
    {
289
        $attributes = clone $this;
290
291
        return $attributes->remove($key, $value);
292
    }
293
294
    /**
295
     * Replace a value with another.
296
     *
297
     * @param string $key
298
     *   The attributes's name.
299
     * @param string $value
300
     *   The attribute's value.
301
     * @param array|string $replacement
302
     *   The replacement value.
303
     *
304
     * @return $this
305
     */
306 View Code Duplication
    public function replace($key, $value, $replacement)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
307
    {
308
        $this->storage += array(
309
            $key => new Attribute(
310
                $key,
311
                $this->ensureString($value)
312
            )
313
        );
314
315
        $replacement = $this->normalizeValue($replacement);
316
317
        foreach ($replacement as $replacement_value) {
318
            $this->storage[$key]->replace($value, $replacement_value);
319
        }
320
321
        return $this;
322
    }
323
324
    /**
325
     * Merge attributes.
326
     *
327
     * @param array $data
328
     *   The data to merge.
329
     *
330
     * @return $this
331
     */
332 View Code Duplication
    public function merge(array $data = array())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
333
    {
334
        foreach ($data as $key => $value) {
335
            $this->storage += array(
336
                $key => new Attribute(
337
                    $key,
338
                    $this->ensureString($value)
339
                )
340
            );
341
342
            $this->storage[$key]->merge(
343
                $this->normalizeValue($value)
344
            );
345
        }
346
347
        return $this;
348
    }
349
350
    /**
351
     * Check if an attribute exists and if a value if provided check it as well.
352
     *
353
     * @param string $key
354
     *   Attribute name.
355
     * @param string $value
356
     *   Todo.
357
     *
358
     * @return bool
359
     *   Whereas an attribute exists.
360
     */
361
    public function exists($key, $value = null)
362
    {
363
        if (isset($this->storage[$key])) {
364
            $attribute = $this->storage[$key];
365
        } else {
366
            return false;
367
        }
368
369
        if (null !== $value) {
370
            return $attribute->contains($value);
371
        }
372
373
        return true;
374
    }
375
376
    /**
377
     * Check if attribute contains a value.
378
     *
379
     * @param string $key
380
     *   Attribute name.
381
     * @param string $value
382
     *   Attribute value.
383
     *
384
     * @return bool
385
     *   Whereas an attribute contains a value.
386
     */
387
    public function contains($key, $value)
388
    {
389
        if (!isset($this->storage[$key])) {
390
            return false;
391
        }
392
393
        return $this->storage[$key]->contains($value);
394
    }
395
396
    /**
397
     * {@inheritdoc}
398
     */
399 4
    public function __toString()
400
    {
401
        // If empty, just return an empty string.
402 4
        if ([] === $this->storage) {
403 2
            return '';
404
        }
405
406 4
        $attributes = implode(' ', $this->prepareValues());
407
408 4
        return $attributes ? ' ' . $attributes : '';
409
    }
410
411
    /**
412
     * Returns all storage elements as an array.
413
     *
414
     * @return \drupol\htmltag\Attribute[]
415
     *   An associative array of attributes.
416
     */
417 4
    private function prepareValues()
418
    {
419 4
        $attributes = $this->storage;
420
421
        // If empty, just return an empty array.
422 4
        if (empty($attributes)) {
423
            return array();
424
        }
425
426
        // Sort the attributes.
427 4
        ksort($attributes);
428
429 4
        $result = [];
430
431 4
        foreach ($attributes as $attribute_name => $attribute) {
432
            switch ($attribute_name) {
433 4
                case 'class':
434 3
                    $classes = $attribute->getValueAsArray();
435 3
                    asort($classes);
436 3
                    $result[$attribute->getName()] = $attribute->set(
437 3
                        implode(' ', $classes)
438
                    );
439 3
                    break;
440
441 2
                case 'placeholder':
442
                    $result[$attribute->getName()] = $attribute->set(
443
                        strip_tags($attribute->getValueAsString())
444
                    );
445
                    break;
446
447
                default:
448 4
                    $result[$attribute->getName()] = $attribute;
449
            }
450
        }
451
452 4
        return $result;
453
    }
454
455
    /**
456
     * Returns all storage elements as an array.
457
     *
458
     * @return array
459
     *   An associative array of attributes.
460
     */
461
    public function toArray()
462
    {
463
        $attributes = $this->storage;
464
465
        // If empty, just return an empty array.
466
        if (empty($attributes)) {
467
            return array();
468
        }
469
470
        $result = [];
471
472
        foreach ($this->prepareValues() as $attribute) {
473
            $result[$attribute->getName()] = $attribute->getValueAsArray();
474
        }
475
476
        return $result;
477
    }
478
479
    /**
480
     * Get storage.
481
     *
482
     * @return \drupol\htmltag\Attribute[]
483
     *   Todo.
484
     */
485
    public function getStorage()
486
    {
487
        return $this->storage;
488
    }
489
490
    /**
491
     * {@inheritdoc}
492
     */
493
    public function getIterator()
494
    {
495
        return new \ArrayIterator($this->toArray());
496
    }
497
}
498