Completed
Push — master ( 603fa9...c5e232 )
by Daniel
03:00
created

Enumerator::last()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 3
1
<?php
2
namespace Narrowspark\Arr;
3
4
use ArrayAccess;
5
use Narrowspark\Arr\Traits\SplitPathTrait;
6
use Narrowspark\Arr\Traits\ValueTrait;
7
8
class Enumerator
9
{
10
    use SplitPathTrait;
11
    use ValueTrait;
12
13
    /**
14
     * Return the first element in an array passing a given truth test.
15
     *
16
     * @param array    $array
17
     * @param callable $callback
18
     * @param mixed    $default
19
     *
20
     * @return mixed
21
     */
22
    public function first($array, callable $callback, $default = null)
23
    {
24
        foreach ($array as $key => $value) {
25
            if (call_user_func($callback, $key, $value)) {
26
                return $value;
27
            }
28
        }
29
30
        return $this->value($default);
31
    }
32
33
    /**
34
     * Return the last element in an array passing a given truth test.
35
     *
36
     * @param array    $array
37
     * @param callable $callback
38
     * @param mixed    $default
39
     *
40
     * @return mixed
41
     */
42
    public function last($array, callable $callback, $default = null)
43
    {
44
        return $this->first(array_reverse($array), $callback, $default);
45
    }
46
47
    /**
48
     * Get a subset of the items from the given array.
49
     *
50
     * @param string[] $array
51
     * @param string[] $keys
52
     *
53
     * @return string[]
54
     */
55
    public function only($array, $keys)
56
    {
57
        return array_intersect_key($array, array_flip((array) $keys));
58
    }
59
60
    /**
61
     * Get a value from the array, and remove it.
62
     *
63
     * @param array       $array
64
     * @param string      $key
65
     * @param string|null $default
66
     *
67
     * @return mixed
68
     */
69
    public function pull(array &$array, $key, $default = null)
70
    {
71
        $value = $this->get($array, $key, $default);
0 ignored issues
show
Bug introduced by
The method get() does not seem to exist on object<Narrowspark\Arr\Enumerator>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
72
73
        $this->forget($array, $key);
0 ignored issues
show
Bug introduced by
The method forget() does not seem to exist on object<Narrowspark\Arr\Enumerator>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
74
75
        return $value;
76
    }
77
78
    /**
79
     * Pluck an array of values from an array.
80
     *
81
     * @param array|\ArrayAccess $array
82
     * @param string             $value
83
     * @param string|null        $key
84
     *
85
     * @return array
86
     */
87
    public function pluck(array $array, $value, $key = null)
88
    {
89
        $results = [];
90
91
        list($value, $key) = $this->explodePluckParameters($value, $key);
92
93
        // If the key is "null", we will just append the value to the array and keep
94
        // looping. Otherwise we will key the array using the value of the key we
95
        // received from the developer. Then we'll return the final array form.
96
        if (is_null($key)) {
97
            foreach ($array as $item) {
98
                $results[] = $this->dataGet($item, $value);
99
            }
100
        } else {
101
            foreach ($array as $item) {
102
                $results[$this->dataGet($item, $key)] = $this->dataGet($item, $value);
103
            }
104
        }
105
106
        return $results;
107
    }
108
109
    /**
110
     * Filter the array using the given Closure.
111
     *
112
     * @param array    $array
113
     * @param callable $callback
114
     *
115
     * @return array
116
     */
117
    public function where(array $array, callable $callback)
118
    {
119
        $filtered = [];
120
121
        foreach ($array as $key => $value) {
122
            if (call_user_func($callback, $key, $value)) {
123
                $filtered[$key] = $value;
124
            }
125
        }
126
127
        return $filtered;
128
    }
129
130
    /**
131
     * Get an item from an array or object using "dot" notation.
132
     *
133
     * @param mixed        $target
134
     * @param string|array $key
135
     * @param string       $default
0 ignored issues
show
Documentation introduced by
Should the type for parameter $default not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
136
     *
137
     * @return mixed
138
     */
139
    public function dataGet($target, $key, $default = null)
140
    {
141
        if (is_null($key)) {
142
            return $target;
143
        }
144
145
        $key = is_array($key) ? $key : $this->splitPath($key);
146
147
        while (($segment = array_shift($key)) !== null) {
148
            if ($segment === '*') {
149
                if (!is_array($target) && !$target instanceof ArrayAccess) {
150
                    return $this->value($default);
151
                }
152
153
                $result = $this->pluck($target, $key);
0 ignored issues
show
Bug introduced by
It seems like $target defined by parameter $target on line 139 can also be of type object<ArrayAccess>; however, Narrowspark\Arr\Enumerator::pluck() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
Documentation introduced by
$key is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
154
155
                return in_array('*', $key, true) ? $this->collapse($result) : $result;
156
            }
157
158
            if (is_array($target)) {
159
                if (!array_key_exists($segment, $target)) {
160
                    return $this->value($default);
161
                }
162
163
                $target = $target[$segment];
164
            } elseif ($target instanceof ArrayAccess) {
165
                if (!isset($target[$segment])) {
166
                    return $this->value($default);
167
                }
168
169
                $target = $target[$segment];
170
            } elseif (is_object($target)) {
171
                if (!isset($target->{$segment})) {
172
                    return $this->value($default);
173
                }
174
175
                $target = $target->{$segment};
176
            } else {
177
                return $this->value($default);
178
            }
179
        }
180
181
        return $target;
182
    }
183
184
    /**
185
     * Push an item onto the beginning of an array.
186
     *
187
     * @param array $array
188
     * @param mixed $value
189
     * @param mixed $key
190
     *
191
     * @return array
192
     */
193
    public function prepend(array $array, $value, $key = null)
194
    {
195
        if (is_null($key)) {
196
            array_unshift($array, $value);
197
        } else {
198
            $array = [$key => $value] + $array;
199
        }
200
201
        return $array;
202
    }
203
204
    /**
205
     * Collapse an array of arrays into a single array.
206
     *
207
     * @param array $array
208
     *
209
     * @return array
210
     */
211
    public function collapse(array $array)
212
    {
213
        $results = [];
214
215
        foreach ($array as $values) {
216
            if (!is_array($values)) {
217
                continue;
218
            }
219
220
            $results = array_merge($results, $values);
221
        }
222
223
        return $results;
224
    }
225
226
    /**
227
     * Replace a given pattern with each value in the array in sequentially.
228
     *
229
     * @param string $pattern
230
     * @param array  $replacements
231
     * @param string $subject
232
     *
233
     * @return string
234
     */
235
    public function pregReplaceSub($pattern, &$replacements, $subject)
236
    {
237
        return preg_replace_callback($pattern, function ($match) use (&$replacements) {
1 ignored issue
show
Unused Code introduced by
The parameter $match is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
238
            return array_shift($replacements);
239
        }, $subject);
240
    }
241
242
    /**
243
     * A shorter way to run a match on the array's keys rather than the values.
244
     *
245
     * @param string $pattern
246
     * @param array  $input
247
     * @param int    $flags
248
     *
249
     * @return array
250
     */
251
    public function pregGrepKeys($pattern, array $input, $flags = 0)
252
    {
253
        return array_intersect_key($input, array_flip(preg_grep($pattern, array_keys($input), $flags)));
254
    }
255
256
    /**
257
     * Index the array by array of keys.
258
     *
259
     * @param array     $data
260
     * @param array     $keys
261
     * @param bool|true $unique
262
     *
263
     * @return array
264
     */
265
    public function getIndexedByKeys(array $data, array $keys, $unique = true)
266
    {
267
        $result = [];
268
269
        foreach ($data as $value) {
270
            $this->indexByKeys($result, $value, $keys, $unique);
271
        }
272
273
        return $result;
274
    }
275
276
    /**
277
     * Converts array of arrays to one-dimensional array, where key is $keyName and value is $valueName.
278
     *
279
     * @param array        $array
280
     * @param string       $keyName
281
     * @param string|array $valueName
282
     *
283
     * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

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.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
284
     */
285
    public function getIndexedValues(array $array, $keyName, $valueName)
286
    {
287
        array_flip($this->pluck($array, $keyName, $valueName));
0 ignored issues
show
Bug introduced by
It seems like $valueName defined by parameter $valueName on line 285 can also be of type array; however, Narrowspark\Arr\Enumerator::pluck() does only seem to accept string|null, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
288
    }
289
290
    /**
291
     * @param array     $result
292
     * @param array     $toSave
293
     * @param array     $keys
294
     * @param bool|true $unique
295
     */
296
    protected function indexByKeys(array &$result, array $toSave, array $keys, $unique = true)
297
    {
298
        foreach ($keys as $key) {
299
            if (!isset($result[$toSave[$key]])) {
300
                $result[$toSave[$key]] = [];
301
            }
302
303
            $result = &$result[$toSave[$key]];
304
        }
305
306
        if ($unique) {
307
            $result = $toSave;
308
        } else {
309
            $result[] = $toSave;
310
        }
311
    }
312
313
    /**
314
     * Explode the "value" and "key" arguments passed to "pluck".
315
     *
316
     * @param string      $value
317
     * @param string|null $key
318
     *
319
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
320
     */
321
    protected function explodePluckParameters($value, $key)
322
    {
323
        $value = is_array($value) ? $value : $this->splitPath($key);
324
325
        $key = is_null($key) || is_array($key) ? $key : $this->splitPath($key);
326
327
        return [$value, $key];
328
    }
329
}
330