Test Failed
Push — features/47-laravelmethods ( 02a3bd...c84f20 )
by Luke
02:28
created

functions.php ➔ get_count()   C

Complexity

Conditions 11
Paths 13

Size

Total Lines 37
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 12.8905

Importance

Changes 0
Metric Value
cc 11
eloc 22
nc 13
nop 1
dl 0
loc 37
ccs 18
cts 24
cp 0.75
crap 12.8905
rs 5.2653
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*
3
 * Nozavroni/Collections
4
 * Just another collections library for PHP5.6+.
5
 *
6
 * @copyright Copyright (c) 2016 Luke Visinoni <[email protected]>
7
 * @author    Luke Visinoni <[email protected]>
8
 * @license   https://github.com/nozavroni/collections/blob/master/LICENSE The MIT License (MIT)
9
 */
10
namespace Noz;
11
12
use Closure;
13
use Illuminate\Support\Str;
14
use InvalidArgumentException;
15
use Iterator;
16
use Noz\Collection\Collection;
17
use Noz\Collection\Sequence;
18
use Noz\Contracts\CollectionInterface;
19
use RuntimeException;
20
use Traversable;
21
22
/**
23
 * Collection factory.
24
 *
25
 * Simply an alias to (new Collection($in)). Allows for a little more concise and
26
 * simpler instantiation of a collection. Also I plan to eventually support
27
 * additional input types that will make this function more flexible and forgiving
28
 * than simply instantiating a Collection object, but for now the two are identical.
29
 *
30
 * @param array|Iterator $data Either an array or an iterator of data
31
 *
32
 * @return CollectionInterface
0 ignored issues
show
Documentation introduced by
Should the return type not be Illuminate\Support\Collection?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
33
 */
34
function collect($data = null)
35
{
36 44
    return Collection::factory($data);
37
}
38
39
/**
40
 * Invoke a callable and return result.
41
 *
42
 * Pass in a callable followed by whatever arguments you want passed to
43
 * it and this function will invoke it with your arguments and return
44
 * the result.
45
 *
46
 * @param callable $callback The callback function to invoke
47
 * @param array ...$args     The args to pass to your callable
48
 *
49
 * @return mixed The result of your invoked callable
50
 */
51
function invoke(callable $callback, ...$args)
52
{
53 7
    return call_user_func($callback, ...$args);
54
}
55
56
/**
57
 * Underscore function.
58
59
 * This function is meant to work sort of like jQuery's "$()". It is a contextual catch-all type function. It works
60
 * as a short-hand alias for invoke, collect, and with.
61
62
 * @param callable|mixed    $in
63
 * @param mixed ...         $_
64
 *
65
 * @return mixed|CollectionInterface
66
 */
67
function _($in, ...$args)
68
{
69 5
    if (is_callable($in)) {
70 3
        return invoke($in, ...$args);
71
    }
72 2
    if (is_traversable($in)) {
73 1
        return collect($in);
74
    }
75 1
    return $in;
76
}
77
78
/**
79
 * Determine if data is traversable.
80
 *
81
 * Pass in any variable and this function will tell you whether or not it
82
 * is traversable. Basically this just means that it is either an array or an iterator.
83
 * This function was written simply because I was tired of if statements that checked
84
 * whether a variable was an array or a descendant of \Iterator. So I wrote this guy.
85
 *
86
 * @param mixed $data The variable to determine traversability
87
 *
88
 * @return bool True if $input is an array or an Iterator
89
 */
90
function is_traversable($data)
91
{
92 98
    return is_array($data) || $data instanceof Traversable;
93
}
94
95
/**
96
 * Can data be converted to an array?
97
 *
98
 * @param mixed $data The data to check
99
 *
100
 * @return bool
101
 */
102
function is_arrayable($data)
103
{
104 71
    if (!is_array($data)) {
105 48
        if (is_object($data)) {
106
            return (
107 5
                method_exists($data, 'toArray') ||
108
                $data instanceof Traversable
109 5
            );
110
        }
111 46
        return false;
112
    }
113 40
    return true;
114
}
115
116
/**
117
 * Convert any traversable to an array.
118
 *
119
 * @todo I'm not sure if this function is necessary or not. Does iterator_to_array do everything this can do?
120
 *
121
 * @param Traversable $data Traversable data
122
 *
123
 * @return array
124
 */
125
function traversable_to_array(Traversable $data)
126
{
127 3
    $arr = [];
128 3
    foreach ($data as $key => $val) {
129 3
        $arr[$key] = $val;
130 3
    }
131 3
    return $arr;
132
}
133
134
/**
135
 * Convert data to an array.
136
 *
137
 * Accepts any kind of data and converts it to an array. If strict mode is on, only data that returns true from
138
 * is_arrayable() will be converted to an array. Anything else will cause an InvalidArgumentException to be thrown.
139
140
 * @param mixed $data   Data to convert to array
141
 * @param bool  $strict Whether to use strict mode
142
143
 * @return array
144
 *
145
 * @throws InvalidArgumentException
146
 */
147
function to_array($data, $strict = true)
148
{
149 41
    if (is_arrayable($data)) {
150 40
        if (!is_array($data)) {
151
            // this is what makes toArray() work recursively
152
            // it must stay right where it is do not move it
153 3
            if (method_exists($data, 'toArray')) {
154 3
                $data = $data->toArray();
155 3
            }
156 3
            if ($data instanceof Traversable) {
157 2
                $data = traversable_to_array($data);
158 2
            }
159 3
        }
160 40
        return $data;
161
    }
162 2
    if ($strict) {
163 1
        throw new InvalidArgumentException(sprintf(
164 1
            'Invalid argument for "%s". Cannot convert "%s" to an array.',
165 1
            __FUNCTION__,
166 1
            typeof($data)
167 1
        ));
168
    }
169 1
    if (is_object($data)) {
170 1
        $values = [];
171 1
        foreach ($data as $key => $val) {
172 1
            $values[$key] = $val;
173 1
        }
174 1
        return $values;
175
    }
176 1
    if (is_null($data)) {
177 1
        return [];
178
    }
179 1
    return [$data];
180
}
181
182
/**
183
 * Get object count.
184
 *
185
 * This function will accept any data and attempt to return its count.
186
 *
187
 * @param mixed $data The data to count
188
 *
189
 * @return int
190
 */
191
function get_count($data)
192
{
193 13
    if (is_null($data)) {
194 5
        return $data;
195
    }
196
197 10
    if (is_array($data)) {
198 1
        return count($data);
199
    }
200
201 10
    if (is_numeric($data)) {
202 8
        return (int) $data;
203
    }
204
205 5
    if ($data === '') {
206 1
        return 0;
207
    }
208
209 5
    if (is_object($data)) {
210 4
        if (method_exists($data, 'count')) {
211 2
            $count = $data->count();
212 4
        } elseif (method_exists($data, '__toString')) {
213 3
            $count = (string) $data;
214 3
            $count = (int) $count;
215 3
        } elseif (is_traversable($data)) {
216
            $count = 0;
217
            foreach ($data as $item) {
218
                $count++;
219
            }
220
        }
221 4
        if (isset($count)) {
222 4
            return (int) $count;
223
        }
224
    }
225
226 1
    throw new RuntimeException('Cannot convert to int.');
227
}
228
229
/**
230
 * Normalize offset to positive integer.
231
 *
232
 * Provided with the requested offset, whether it be a string, an integer (positive or negative), or some type of
233
 * object, this function will normalize it to a positive integer offset or, failing that, it will throw an exception.
234
 * A negative offset will require either the traversable that is being indexed or its total count in order to normalize
235
236
 * @param int|mixed $offset The offset to normalize
237
 * @param int|array|traversable $count  Either the traversable count, or the traversable itself.
238
239
 * @return int
240
241
 * @throws RuntimeException If offset cannot be normalized
242
 * @throws InvalidArgumentException If offset is negative and count is not provided
243
 */
244
function normalize_offset($offset, $count = null)
245
{
246 11
    if (is_object($offset) && method_exists($offset, '__toString')) {
247 1
        $offset = (string) $offset;
248 1
    }
249
250 11
    if (!is_numeric($offset)) {
251 3
        throw new RuntimeException('Invalid offset.');
252
    }
253
254 8
    $count = get_count($count);
255
256 8
    if ($offset < 0) {
257 6
        if (is_null($count)) {
258 1
            throw new InvalidArgumentException('Cannot normalize negative offset without a total count.');
259
        }
260 5
        $offset += $count;
261 5
    }
262 7
    return (int) $offset;
263
}
264
265
/**
266
 * Get range start and end from string.
267
 *
268
 * Provided a string in the format of "start:end" and the total items in a collection, this function will return an
269
 * array in the form of [start, length].
270
 *
271
 * @param string $range The range to get (in the format of "start:end"
272
 * @param int|array|traversable $count  Either the traversable count, or the traversable itself.
273
 *
274
 * @return array [start, length]
275
 */
276
function get_range_start_end($range, $count = null)
277
{
278 6
    $count = get_count($count);
279 6
    if (Str::contains($range, Sequence::SLICE_DELIM)) {
280
        // return slice as a new sequence
281 5
        list($start, $end) = explode(Sequence::SLICE_DELIM, $range, 2);
282 5
        if ($start == '') {
283 4
            $start = 0;
284 4
        }
285 5
        if ($end == '') {
286 4
            $end = $count - 1;
287 4
        }
288 5
        $start = normalize_offset($start, $count);
289 4
        $end = normalize_offset($end, $count) + 1;
290 4
        if ($end > $start) {
291 4
            $length = $end - $start;
292 4
            return [$start, $length];
293
        }
294
    }
295 1
    throw new RuntimeException('Invalid index range/offset.');
296
}
297
298
/**
299
 * Get data type.
300
 *
301
 * Inspects data to determine its type.
302
 *
303
 * @param mixed  $data       The data to check
304
 * @param bool   $meta       Whether to include meta data such as length/size
305
// * @param string $returnType What type of value to return (array or string)
0 ignored issues
show
Bug introduced by
There is no parameter named $returnType. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
306
 *
307
 * @return string
308
 */
309
function typeof($data, $meta = true/*, $returnType = 'string'*/)
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
310
{
311 4
    $type = gettype($data);
312 4
    if ($meta) {
313
        switch($type) {
314 4
            case 'object':
315 2
                $class = get_class($data);
316 2
                return "{$type} <{$class}>";
317 3
            case 'resource':
318 1
                $restype = get_resource_type($data);
319 1
                return "{$type} <{$restype}>";
320
        }
321 3
    } else {
322
        switch($type) {
323 1
            case 'object':
324 1
                return get_class($data);
325 1
            case 'resource':
326 1
                return get_resource_type($data);
327
        }
328
    }
329 3
    return $type;
330
}
331
332
// BEGIN debug/testing functions
333
334
/**
335
 * Dump and die.
336
 *
337
 * @param mixed $input Data to dump
338
 * @param bool  $exit  Should we exit after dump?
339
 * @param bool  $label Should we print a label?
340
 * @codeCoverageIgnore
341
 */
342
function dd($input, $exit = true, $label = null)
343
{
344
    if (is_null($label)) {
345
        $trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1);
346
        $label = 'File: ';
347
        $label .= pathinfo($trace[0]['file'], PATHINFO_FILENAME);
348
        $label .= ':' . $trace[0]['line'];
349
        echo $label . "\n";
350
    } else {
351
        echo $label . "\n" . implode(
352
                array_map(
353
                    function () {
354
                        return '-';
355
                    },
356
                    str_split($label)
357
                )
358
            ) . "\n";
359
    }
360
    var_dump($input);
361
    echo "\n";
362
    if ($exit) {
363
        exit;
364
    }
365
}
366
367
/**
368
 * Exactly the same as var_dump, except that it returns its output rather than dumping it.
369
 */
370
function sdump($var)
371
{
372 27
    ob_start();
373 27
    var_dump($var);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($var); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
374 27
    return ob_get_clean();
375
}
376
377
/**
378
 * Get object hash/checksum.
379
 * Using a var_dump of an object, this will return a hash that tells you if anything in your object has changed. Just
380
 * create a hash of an object, do some stuff with it, then create another hash of it and compare the two. If they are
381
 * different, teh object has changed in some way.
382
 *
383
 * @param object $obj The object to hash
384
 * @param string $alg The hash algorithm (supports md5 or sha1)
385
 *
386
 * @return string
387
 *
388
 * @throws InvalidArgumentException
389
 */
390
function object_hash($obj, $alg = 'md5')
391
{
392 27
    $algorithms = ['md5', 'sha1'];
393 27
    if (!in_array($alg, $algorithms)) {
394 1
        throw new InvalidArgumentException(sprintf(
395 1
            '"%s" is not a valid hash algorithm (%s).',
396 1
            $alg,
397 1
            implode(', ', $algorithms)
398 1
        ));
399
    }
400 26
    return call_user_func($alg, sdump($obj));
401
}
402