Passed
Push — master ( a680c8...bf773c )
by Marcio
03:21
created

IteratorDot   F

Complexity

Total Complexity 71

Size/Duplication

Total Lines 426
Duplicated Lines 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 71
eloc 124
c 4
b 0
f 0
dl 0
loc 426
rs 2.7199

24 Methods

Rating   Name   Duplication   Size   Complexity  
A isEmpty() 0 12 4
A setReference() 0 3 1
A count() 0 3 1
A push() 0 10 4
A delete() 0 18 6
A getArrayItems() 0 8 3
A flatten() 0 17 5
A all() 0 3 1
B has() 0 19 8
B get() 0 19 7
A clear() 0 9 3
A set() 0 16 6
A merge() 0 10 4
A setArray() 0 3 1
A add() 0 8 4
A pull() 0 10 2
A getIterator() 0 3 1
A __construct() 0 3 1
A exists() 0 3 1
A toJson() 0 7 3
A offsetUnset() 0 3 1
A offsetSet() 0 7 2
A offsetGet() 0 3 1
A offsetExists() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like IteratorDot often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use IteratorDot, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * Dot - PHP dot notation access to arrays
5
 *
6
 * @author  Riku Särkinen <[email protected]>
7
 * @link    https://github.com/adbario/php-dot-notation
8
 * @license https://github.com/adbario/php-dot-notation/blob/2.x/LICENSE.md (MIT License)
9
 */
10
11
namespace Ballybran\Core\Collections\Collection;
12
13
use Countable;
14
use ArrayAccess;
15
use ArrayIterator;
16
use IteratorAggregate;
17
18
/**
19
 * Dot
20
 *
21
 * This class provides a dot notation access and helper functions for
22
 * working with arrays of data. Inspired by Laravel Collection.
23
 */
24
class IteratorDot implements ArrayAccess, Countable, IteratorAggregate
25
{
26
    /**
27
     * The stored items
28
     *
29
     * @var array
30
     */
31
    protected $items = [];
32
    
33
    /**
34
     *  elements
35
     *
36
     * @var array
37
     */
38
    protected $elements;
39
40
    /**
41
     * Create a new Dot instance
42
     *
43
     * @param mixed $items
44
     */
45
    public function __construct($items = [])
46
    {
47
        $this->elements = $this->getArrayItems($items);
48
    }
49
50
    /**
51
     * Set a given key / value pair or pairs
52
     * if the key doesn't exist already
53
     *
54
     * @param array|int|string $keys
55
     * @param mixed $value
56
     */
57
    public function add($keys, $value = null)
58
    {
59
        if (is_array($keys)) {
60
            foreach ($keys as $key => $value) {
61
                $this->add($key, $value);
62
            }
63
        } elseif (is_null($this->get($keys))) {
64
            $this->set($keys, $value);
65
        }
66
    }
67
68
    /**
69
     * Return all the stored items
70
     *
71
     * @return array
72
     */
73
    public function all()
74
    {
75
        return $this->elements;
76
    }
77
78
    /**
79
     * Delete the contents of a given key or keys
80
     *
81
     * @param array|int|string|null $keys
82
     */
83
    public function clear($keys = null)
84
    {
85
        if (is_null($keys)) {
86
            $this->elements = [];
87
            return;
88
        }
89
        $keys = (array)$keys;
90
        foreach ($keys as $key) {
91
            $this->set($key, []);
92
        }
93
    }
94
95
    /**
96
     * Delete the given key or keys
97
     *
98
     * @param array|int|string $keys
99
     */
100
    public function delete($keys)
101
    {
102
        $keys = (array)$keys;
103
        foreach ($keys as $key) {
104
            if ($this->exists($this->elements, $key)) {
105
                unset($this->elements[$key]);
106
                continue;
107
            }
108
            $items = &$this->elements;
109
            $segments = explode('.', $key);
110
            $lastSegment = array_pop($segments);
111
            foreach ($segments as $segment) {
112
                if (!isset($items[$segment]) || !is_array($items[$segment])) {
113
                    continue 2;
114
                }
115
                $items = &$items[$segment];
116
            }
117
            unset($items[$lastSegment]);
118
        }
119
    }
120
121
    /**
122
     * Checks if the given key exists in the provided array.
123
     *
124
     * @param  array $array Array to validate
125
     * @param  int|string $key The key to look for
126
     *
127
     * @return bool
128
     */
129
    protected function exists($array, $key)
130
    {
131
        return array_key_exists($key, $array);
132
    }
133
134
    /**
135
     * Flatten an array with the given character as a key delimiter
136
     *
137
     * @param  string $delimiter
138
     * @param  array|null $items
139
     * @param  string $prepend
140
     * @return array
141
     */
142
    public function flatten($delimiter = '.', $items = null, $prepend = '')
143
    {
144
        $flatten = [];
145
        if (is_null($items)) {
146
            $items = $this->elements;
147
        }
148
        foreach ($items as $key => $value) {
149
            if (is_array($value) && !empty($value)) {
150
                $flatten = array_merge(
151
                    $flatten,
152
                    $this->flatten($delimiter, $value, $prepend . $key . $delimiter)
153
                );
154
            } else {
155
                $flatten[$prepend . $key] = $value;
156
            }
157
        }
158
        return $flatten;
159
    }
160
161
    /**
162
     * Return the value of a given key
163
     *
164
     * @param  int|string|null $key
165
     * @param  mixed $default
166
     * @return mixed
167
     */
168
    public function get($key = null, $default = null)
169
    {
170
        if (is_null($key)) {
171
            return $this->elements;
172
        }
173
        if ($this->exists($this->elements, $key)) {
174
            return $this->elements[$key];
175
        }
176
        if (false === strpos($key, '.')) {
177
            return $default;
178
        }
179
        $items = $this->elements;
180
        foreach (explode('.', $key) as $segment) {
181
            if (!is_array($items) || !$this->exists($items, $segment)) {
182
                return $default;
183
            }
184
            $items = &$items[$segment];
185
        }
186
        return $items;
187
    }
188
189
    /**
190
     * Return the given items as an array
191
     *
192
     * @param  mixed $items
193
     * @return array
194
     */
195
    protected function getArrayItems($items)
196
    {
197
        if (is_array($items)) {
198
            return $items;
199
        } elseif ($items instanceof self) {
200
            return $items->all();
201
        }
202
        return (array)$items;
203
    }
204
205
    /**
206
     * Check if a given key or keys exists
207
     *
208
     * @param  array|int|string $keys
209
     * @return bool
210
     */
211
    public function has($keys)
212
    {
213
        $keys = (array)$keys;
214
        if ( empty($this->elements) || $keys === []) {
215
            return false;
216
        }
217
        foreach ($keys as $key) {
218
            $items = $this->elements;
219
            if ($this->exists($items, $key)) {
220
                continue;
221
            }
222
            foreach (explode('.', $key) as $segment) {
223
                if (!is_array($items) || !$this->exists($items, $segment)) {
224
                    return false;
225
                }
226
                $items = $items[$segment];
227
            }
228
        }
229
        return true;
230
    }
231
232
    /**
233
     * Check if a given key or keys are empty
234
     *
235
     * @param  array|int|string|null $keys
236
     * @return bool
237
     */
238
    public function isEmpty($keys = null)
239
    {
240
        if (is_null($keys)) {
241
            return empty($this->elements);
242
        }
243
        $keys = (array)$keys;
244
        foreach ($keys as $key) {
245
            if (!empty($this->get($key))) {
246
                return false;
247
            }
248
        }
249
        return true;
250
    }
251
252
    /**
253
     * Merge a given array or a Dot object with the given key
254
     * or with the whole Dot object
255
     *
256
     * @param array|string|self $key
257
     * @param array $value
258
     */
259
    public function merge($key, $value = null)
260
    {
261
        if (is_array($key)) {
262
            $this->elements = array_merge($this->elements, $key);
263
        } elseif (is_string($key)) {
264
            $items = (array)$this->get($key);
265
            $value = array_merge($items, $this->getArrayItems($value));
266
            $this->set($key, $value);
267
        } elseif ($key instanceof self) {
0 ignored issues
show
introduced by
$key is always a sub-type of self.
Loading history...
268
            $this->elements = array_merge($this->elements, $key->all());
269
        }
270
    }
271
272
    /**
273
     * Return the value of a given key and
274
     * delete the key
275
     *
276
     * @param  int|string|null $key
277
     * @param  mixed $default
278
     * @return mixed
279
     */
280
    public function pull($key = null, $default = null)
281
    {
282
        if (is_null($key)) {
283
            $value = $this->all();
284
            $this->clear();
285
            return $value;
286
        }
287
        $value = $this->get($key, $default);
288
        $this->delete($key);
289
        return $value;
290
    }
291
292
    /**
293
     * Push a given value to the end of the array
294
     * in a given key
295
     *
296
     * @param mixed $key
297
     * @param mixed $value
298
     */
299
    public function push($key, $value = null)
300
    {
301
        if (is_null($value)) {
302
            $this->elements[] = $key;
303
            return;
304
        }
305
        $items = $this->get($key);
306
        if (is_array($items) || is_null($items)) {
307
            $items[] = $value;
308
            $this->set($key, $items);
309
        }
310
    }
311
312
    /**
313
     * Set a given key / value pair or pairs
314
     *
315
     * @param array|int|string $keys
316
     * @param mixed $value
317
     */
318
    public function set($keys, $value = null)
319
    {
320
        if (is_array($keys)) {
321
            foreach ($keys as $key => $value) {
322
                $this->set($key, $value);
323
            }
324
            return;
325
        }
326
        $items = &$this->elements;
327
        foreach (explode('.', $keys) as $key) {
328
            if (!isset($items[$key]) || !is_array($items[$key])) {
329
                $items[$key] = [];
330
            }
331
            $items = &$items[$key];
332
        }
333
        $items = $value;
334
    }
335
336
    /**
337
     * Replace all items with a given array
338
     *
339
     * @param mixed $items
340
     */
341
    public function setArray($items)
342
    {
343
        $this->elements = $this->getArrayItems($items);
344
    }
345
346
    /**
347
     * Replace all items with a given array as a reference
348
     *
349
     * @param array $items
350
     */
351
    public function setReference(array &$items)
352
    {
353
        $this->elements = &$items;
354
    }
355
356
    /**
357
     * Return the value of a given key or all the values as JSON
358
     *
359
     * @param  mixed $key
360
     * @param  int $options
361
     * @return string
362
     */
363
    public function toJson($key = null, $options = 0)
364
    {
365
        if (is_string($key)) {
366
            return json_encode($this->get($key), $options);
367
        }
368
        $options = $key === null ? 0 : $key;
369
        return json_encode($this->elements, $options);
370
    }
371
    /*
372
     * --------------------------------------------------------------
373
     * ArrayAccess interface
374
     * --------------------------------------------------------------
375
     */
376
    /**
377
     * Check if a given key exists
378
     *
379
     * @param  int|string $key
380
     * @return bool
381
     */
382
    public function offsetExists($key)
383
    {
384
        return $this->has($key);
385
    }
386
387
    /**
388
     * Return the value of a given key
389
     *
390
     * @param  int|string $key
391
     * @return mixed
392
     */
393
    public function offsetGet($key)
394
    {
395
        return $this->get($key);
396
    }
397
398
    /**
399
     * Set a given value to the given key
400
     *
401
     * @param int|string|null $key
402
     * @param mixed $value
403
     */
404
    public function offsetSet($key, $value)
405
    {
406
        if (is_null($key)) {
407
            $this->elements[] = $value;
408
            return;
409
        }
410
        $this->set($key, $value);
411
    }
412
413
    /**
414
     * Delete the given key
415
     *
416
     * @param int|string $key
417
     */
418
    public function offsetUnset($key)
419
    {
420
        $this->delete($key);
421
    }
422
    /*
423
     * --------------------------------------------------------------
424
     * Countable interface
425
     * --------------------------------------------------------------
426
     */
427
    /**
428
     * Return the number of items in a given key
429
     *
430
     * @param  int|string|null $key
431
     * @return int
432
     */
433
    public function count($key = null)
434
    {
435
        return count($this->get($key));
436
    }
437
    /*
438
     * --------------------------------------------------------------
439
     * IteratorAggregate interface
440
     * --------------------------------------------------------------
441
     */
442
    /**
443
     * Get an iterator for the stored items
444
     *
445
     * @return \ArrayIterator
446
     */
447
    public function getIterator()
448
    {
449
        return new ArrayIterator($this->elements);
450
    }
451
}