Completed
Push — master ( 31ff58...427b27 )
by Mark van den
04:54
created

Collection   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 357
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 45
lcom 1
cbo 0
dl 0
loc 357
ccs 90
cts 90
cp 1
rs 8.3673
c 0
b 0
f 0

25 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A make() 0 4 1
A count() 0 4 1
A offsetExists() 0 4 1
A offsetGet() 0 4 1
A offsetSet() 0 8 2
A offsetUnset() 0 4 1
A all() 0 4 1
A changeKeyCase() 0 4 1
A contains() 0 9 2
A each() 0 10 3
A filter() 0 8 2
B first() 0 19 6
A get() 0 8 2
A has() 0 12 4
A implode() 0 4 1
A last() 0 4 2
A map() 0 8 1
A mapWithKeys() 0 13 3
A reject() 0 12 2
A slice() 0 4 1
A take() 0 8 2
A toArray() 0 4 1
A useAsCallable() 0 4 2
A values() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like Collection 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 Collection, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Mvdnbrk\Postmark\Support;
4
5
use stdClass;
6
use Countable;
7
use ArrayAccess;
8
9
class Collection implements ArrayAccess, Countable
10
{
11
    /**
12
     * The items contained in the collection.
13
     *
14
     * @var array
15
     */
16
    protected $items = [];
17
18
    /**
19
     * Create a new collection.
20
     *
21
     * @param  array  $items
22
     */
23 198
    public function __construct($items = [])
24
    {
25 198
        $this->items = $items;
26 198
    }
27
28
    /**
29
     * Create a new collection instance if the value isn't one already.
30
     *
31
     * @param  mixed  $items
32
     * @return static
33
     */
34 33
    public static function make($items = [])
35
    {
36 33
        return new static($items);
37
    }
38
39
    /**
40
     * Count the number of items in the collection.
41
     *
42
     * @return int
43
     */
44 21
    public function count()
45
    {
46 21
        return count($this->items);
47
    }
48
49
    /**
50
     * Determine if an item exists at an offset.
51
     *
52
     * @param  mixed  $key
53
     * @return bool
54
     */
55 99
    public function offsetExists($key)
56
    {
57 99
        return array_key_exists($key, $this->items);
58
    }
59
60
    /**
61
     * Get an item at a given offset.
62
     *
63
     * @param  mixed  $key
64
     * @return mixed
65
     */
66 9
    public function offsetGet($key)
67
    {
68 9
        return $this->items[$key];
69
    }
70
71
    /**
72
     * Set the item at a given offset.
73
     *
74
     * @param  mixed  $key
75
     * @param  mixed  $value
76
     * @return void
77
     */
78 6
    public function offsetSet($key, $value)
79
    {
80 6
        if (is_null($key)) {
81 6
            $this->items[] = $value;
82
        } else {
83 6
            $this->items[$key] = $value;
84
        }
85 6
    }
86
87
    /**
88
     * Unset the item at a given offset.
89
     *
90
     * @param  string  $key
91
     * @return void
92
     */
93 6
    public function offsetUnset($key)
94
    {
95 6
        unset($this->items[$key]);
96 6
    }
97
98
    /**
99
     * Get all of the items in the collection.
100
     *
101
     * @return array
102
     */
103 24
    public function all()
104
    {
105 24
        return $this->items;
106
    }
107
108
    /**
109
     * Change key of the collection to
110
     * upper or lowecase.
111
     *
112
     * @param int $case
113
     * @return static
114
     */
115 6
    public function changeKeyCase($case = CASE_LOWER)
116
    {
117 6
        return new static(array_change_key_case($this->items, $case));
118
    }
119
120
    /**
121
     * Determine if an item exists in the collection.
122
     *
123
     * @param  mixed  $key
124
     * @return bool
125
     */
126 99
    public function contains($key)
127
    {
128 99
        if ($this->useAsCallable($key)) {
129 3
            $placeholder = new stdClass;
130 3
            return $this->first($key, $placeholder) !== $placeholder;
131
        }
132
133 99
        return in_array($key, $this->items);
134
    }
135
136
    /**
137
     * Execute a callback over each item.
138
     *
139
     * @param  callable  $callback
140
     * @return $this
141
     */
142 3
    public function each(callable $callback)
143
    {
144 3
        foreach ($this->items as $key => $item) {
145 3
            if ($callback($item, $key) === false) {
146 3
                break;
147
            }
148
        }
149
150 3
        return $this;
151
    }
152
153
    /**
154
     * Run a filter over each of the items.
155
     *
156
     * @param  callable|null  $callback
157
     * @return static
158
     */
159 105
    public function filter(callable $callback = null)
160
    {
161 105
        if ($callback) {
162 105
            return new static(array_filter($this->items, $callback, ARRAY_FILTER_USE_BOTH));
163
        }
164
165 3
        return new static(array_filter($this->items));
166
    }
167
168
    /**
169
     * Get the first item from the collection.
170
     *
171
     * @param  callable|null  $callback
172
     * @param  mixed  $default
173
     * @return mixed
174
     */
175 30
    public function first(callable $callback = null, $default = null)
176
    {
177 30
        if (is_null($callback)) {
178 21
            if (empty($this->items)) {
179 3
                return $default;
180
            }
181 18
            foreach ($this->items as $item) {
182 18
                return $item;
183
            }
184
        }
185
186 9
        foreach ($this->items as $key => $value) {
187 9
            if (call_user_func($callback, $value, $key)) {
188 9
                return $value;
189
            }
190
        }
191
192 6
        return $default;
193
    }
194
195
    /**
196
     * Get an item from the collection by key.
197
     *
198
     * @param  mixed  $key
199
     * @param  mixed  $default
200
     * @return mixed
201
     */
202 87
    public function get($key, $default = null)
203
    {
204 87
        if ($this->offsetExists($key)) {
205 84
            return $this->items[$key];
206
        }
207
208 21
        return $default;
209
    }
210
211
    /**
212
     * Determine if an item exists in the collection by key.
213
     *
214
     * @param  mixed  $key
215
     * @return bool
216
     */
217 30
    public function has($key)
218
    {
219 30
        $keys = is_array($key) ? $key : func_get_args();
220
221 30
        foreach ($keys as $value) {
222 30
            if (! $this->offsetExists($value)) {
223 30
                return false;
224
            }
225
        }
226
227 27
        return true;
228
    }
229
230
    /**
231
     * Concatenate values of a given key as a string.
232
     *
233
     * @param  string  $seperator
234
     * @return string
235
     */
236 99
    public function implode($seperator)
237
    {
238 99
        return implode($seperator, $this->items);
239
    }
240
241
    /**
242
     * Get the last item from the collection.
243
     *
244
     * @param  mixed  $default
245
     * @return mixed
246
     */
247 12
    public function last($default = null)
248
    {
249 12
        return empty($this->items) ? $default : end($this->items);
250
    }
251
252
    /**
253
     * Run a map over each of the items.
254
     *
255
     * @param  callable  $callback
256
     * @return static
257
     */
258 21
    public function map(callable $callback)
259
    {
260 21
        $keys = array_keys($this->items);
261
262 21
        $items = array_map($callback, $this->items, $keys);
263
264 21
        return new static(array_combine($keys, $items));
265
    }
266
267
    /**
268
     * Run an associative map over each of the items.
269
     *
270
     * The callback should return an associative array with a single key/value pair.
271
     *
272
     * @param  callable  $callback
273
     * @return static
274
     */
275 21
    public function mapWithKeys(callable $callback)
276
    {
277 21
        $result = [];
278
279 21
        foreach ($this->items as $key => $value) {
280 18
            $assoc = $callback($value, $key);
281 18
            foreach ($assoc as $mapKey => $mapValue) {
282 18
                $result[$mapKey] = $mapValue;
283
            }
284
        }
285
286 21
        return new static($result);
287
    }
288
289
    /**
290
     * Create a collection of all elements that do not pass a given truth test.
291
     *
292
     * @param  callable|mixed  $callback
293
     * @return static
294
     */
295 99
    public function reject($callback)
296
    {
297 99
        if ($this->useAsCallable($callback)) {
298
            return $this->filter(function ($value, $key) use ($callback) {
299 99
                return ! $callback($value, $key);
300 99
            });
301
        }
302
303
        return $this->filter(function ($item) use ($callback) {
304 3
            return $item != $callback;
305 3
        });
306
    }
307
308
    /**
309
     * Slice the underlying collection array.
310
     *
311
     * @param  int  $offset
312
     * @param  int  $length
313
     * @return static
314
     */
315 120
    public function slice($offset, $length = null)
316
    {
317 120
        return new static(array_slice($this->items, $offset, $length, true));
318
    }
319
320
    /**
321
     * Take the first or last {$limit} items.
322
     *
323
     * @param  int  $limit
324
     * @return static
325
     */
326 102
    public function take($limit)
327
    {
328 102
        if ($limit < 0) {
329 3
            return $this->slice($limit, abs($limit));
330
        }
331
332 99
        return $this->slice(0, $limit);
333
    }
334
335
    /**
336
     * Get the collection of items as a plain array.
337
     *
338
     * @return array
339
     */
340 33
    public function toArray()
341
    {
342 33
        return $this->items;
343
    }
344
345
    /**
346
     * Determine if the given value is callable, but not a string.
347
     *
348
     * @param  mixed  $value
349
     * @return bool
350
     */
351 102
    protected function useAsCallable($value)
352
    {
353 102
        return ! is_string($value) && is_callable($value);
354
    }
355
356
    /**
357
     * Reset the keys on the underlying array.
358
     *
359
     * @return static
360
     */
361 30
    public function values()
362
    {
363 30
        return new static(array_values($this->items));
364
    }
365
}
366