HtmlAttributes::wrapArray()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 3
c 1
b 0
f 0
nc 3
nop 1
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 3
rs 10
1
<?php
2
3
namespace Oddvalue\LinkBuilder;
4
5
use ArrayAccess;
6
use Illuminate\Contracts\Support\Htmlable;
7
8
class HtmlAttributes implements ArrayAccess, Htmlable
9
{
10
    protected $attributes = [];
11
    protected $classes = [];
12
13
    /**
14
     * Construct with attribute array
15
     *
16
     * @param array $attributes
17
     */
18 51
    public function __construct($attributes = [])
19
    {
20 51
        $this->set($attributes);
21 51
    }
22
23
    /**
24
     * Static singleton generator
25
     *
26
     * @param array $attributes
27
     * @return self
28
     */
29 36
    public static function make($attributes = [])
30
    {
31 36
        return new static($attributes);
32
    }
33
34
    /**
35
     * Get one or all of the attributes as an array
36
     *
37
     * @param string $attribute
38
     * @return array|string
39
     */
40 9
    public function get(string $attribute = null)
41
    {
42 9
        if (is_null($attribute)) {
43 3
            return $this->toArray();
44
        }
45 9
        if ($attribute === 'class') {
46 3
            return $this->getClass();
47
        }
48 9
        return $this->attributes[$attribute];
49
    }
50
51
    /**
52
     * Set one or more attributes
53
     *
54
     * @param mixed $attributes
55
     * @param string $value
56
     * @return self
57
     */
58 51
    public function set($attributes, string $value = null)
59
    {
60 51
        if (! is_array($attributes) || $attributes instanceof ArrayAccess) {
61 9
            $attributes = [$attributes => $value];
62
        }
63
64 51
        foreach ($attributes as $name => $value) {
65 30
            if ($name === 'class') {
66 15
                $this->setClass($value);
67 15
                continue;
68
            }
69
70 24
            if (is_int($name)) {
71 3
                $name = $value;
72 3
                $value = null;
73
            }
74
75 24
            $this->attributes[$name] = $value;
76
        }
77
78 51
        return $this;
79
    }
80
81
    /**
82
     * Remove one or more attributes
83
     *
84
     * @param string|array $attributes
85
     * @return self
86
     */
87 3
    public function remove($attributes)
88
    {
89 3
        foreach ($this->wrapArray($attributes) as $name) {
90 3
            if ($name === 'class') {
91 3
                $this->clearClass();
92 3
                continue;
93
            }
94 3
            unset($this->attributes[$name]);
95
        }
96 3
        return $this;
97
    }
98
99
    /**
100
     * Test if the attribute exists
101
     *
102
     * @param string $attribute
103
     * @return boolean
104
     */
105 6
    public function has(string $attribute) : bool
106
    {
107 6
        if ($attribute === 'class') {
108 3
            return $this->hasClass();
109
        }
110
111 3
        return array_key_exists($attribute, $this->attributes);
112
    }
113
114
    /**
115
     * Append an html class to the class attribute
116
     *
117
     * @param array|string $class
118
     * @return self
119
     */
120 6
    public function addClass($class)
121
    {
122 6
        $this->classes = array_unique(array_merge($this->classes, $this->splitClass($class)));
123 6
        return $this;
124
    }
125
126
    /**
127
     * Override the class attribute
128
     *
129
     * @param array|string $class
130
     * @return void
131
     */
132 18
    public function setClass($class)
133
    {
134 18
        $this->classes = $this->splitClass($class);
135 18
        return $this;
136
    }
137
138
    /**
139
     * Get the class attribute value
140
     *
141
     * @return string
142
     */
143 18
    public function getClass() : string
144
    {
145 18
        return implode(' ', $this->classes);
146
    }
147
148
    /**
149
     * Test that a certain class exists or that the class attribute exists
150
     *
151
     * @param string $class
152
     * @return boolean
153
     */
154 27
    public function hasClass(string $class = null)
155
    {
156 27
        if (! $class) {
157 27
            return count($this->classes) > 0;
158
        }
159 3
        return in_array($class, $this->classes);
160
    }
161
162
    /**
163
     * Take a string of class names and split them to an array
164
     *
165
     * @param array|string $classString
166
     * @return array
167
     */
168 24
    private function splitClass($classString) : array
169
    {
170 24
        return call_user_func_array('array_merge', array_map(function ($class) {
171 24
            return explode(' ', $class);
172 24
        }, $this->wrapArray($classString)));
173
    }
174
175
    /**
176
     * Remove all classes
177
     *
178
     * @return self
179
     */
180 3
    public function clearClass()
181
    {
182 3
        $this->classes = [];
183 3
        return $this;
184
    }
185
186
    /**
187
     * Remove a class
188
     *
189
     * @param string $class
190
     * @return self
191
     */
192 3
    public function removeClass(string $class)
193
    {
194 3
        if (($key = array_search($class, $this->classes)) !== false) {
195 3
            unset($this->classes[$key]);
196
        }
197 3
        return $this;
198
    }
199
200
    /**
201
     * Assure that the value is wrapped in an array if not already
202
     *
203
     * @param mixed $value
204
     * @return array
205
     */
206 24
    private function wrapArray($value) : array
207
    {
208 24
        if (is_null($value)) {
209 3
            return [];
210
        }
211
212 24
        return is_array($value) ? $value : [$value];
213
    }
214
215
    /**
216
     * Test if no attributes are set
217
     *
218
     * @return boolean
219
     */
220 33
    public function isEmpty() : bool
221
    {
222 33
        return empty($this->attributes) && empty($this->classes);
223
    }
224
225
    /**
226
     * ArrayAccess method to check an attribute exists
227
     *
228
     * @param mixed $offset
229
     * @return boolean
230
     */
231 3
    public function offsetExists($offset) : bool
232
    {
233 3
        return $this->has($offset);
234
    }
235
236
    /**
237
     * ArrayAccess method to fetch an attribute
238
     *
239
     * @param mixed $offset
240
     * @return mixed
241
     */
242 6
    public function offsetGet($offset)
243
    {
244 6
        return $this->get($offset);
245
    }
246
247
    /**
248
     * ArrayAccess method to set an attribute
249
     *
250
     * @param mixed $offset
251
     * @param mixed $value
252
     * @return void
253
     */
254 3
    public function offsetSet($offset, $value) : void
255
    {
256 3
        $this->set($offset, $value);
257 3
    }
258
259
    /**
260
     * ArrayAccess method for unsetting an attribute
261
     *
262
     * @param mixed $offset
263
     * @return void
264
     */
265 3
    public function offsetUnset($offset) : void
266
    {
267 3
        $this->remove($offset);
268 3
    }
269
270
    /**
271
     * Cast the object to an array
272
     *
273
     * @return array
274
     */
275 24
    public function toArray() : array
276
    {
277 24
        return array_merge($this->attributes, $this->hasClass() ? ['class' => $this->getClass()] : []);
278
    }
279
280
    /**
281
     * Format the object as a string of HTML tag attributes
282
     *
283
     * @return string
284
     */
285 33
    public function toHtml() : string
286
    {
287 33
        if ($this->isEmpty()) {
288 15
            return '';
289
        }
290
291 21
        return ' ' . implode(' ', array_map(function ($attribute, $value) {
292 21
            if (is_null($value) || $value === '') {
293 9
                return $attribute;
294
            }
295
296 18
            return "{$attribute}=\"{$value}\"";
297 21
        }, array_keys($this->toArray()), $this->toArray()));
298
    }
299
300
    /**
301
     * Cast the object to a string
302
     *
303
     * @return string
304
     */
305 30
    public function __toString()
306
    {
307 30
        return $this->toHtml();
308
    }
309
}
310