Passed
Pull Request — master (#56)
by
unknown
27:42 queued 22:27
created

filters.php ➔ after()   B

Complexity

Conditions 9
Paths 3

Size

Total Lines 25

Duplication

Lines 12
Ratio 48 %

Code Coverage

Tests 11
CRAP Score 9

Importance

Changes 0
Metric Value
cc 9
nc 3
nop 3
dl 12
loc 25
ccs 11
cts 11
cp 1
crap 9
rs 8.0555
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Zicht Online <http://zicht.nl>
4
 */
5
6
namespace Zicht\Itertools\filters;
7
8
use Zicht\Itertools\conversions;
9
use Zicht\Itertools;
10
11
/**
12
 * Returns a filter closure that only accepts values that are instances of $CLASS.
13
 *
14
 * For example, the following will return a list where all items
15
 * are instances of class Bar:
16
 * > $list = iterable([new Foo(), new Bar(), new Moo()]);
17
 * > $result = $list->filter(type(Bar::class));
18
 * > // {1: Bar}
19
 *
20
 * For example, the following will return a list where all items
21
 * have a property or array index 'key' that is an instance
22
 * of class Foo:
23
 * > $list = iterable([['key' => new Foo()], ['key => new Bar()], ['key' => new Moo()]]);
24
 * > $result = $list->filter(type(Bar::class, 'key'));
25
 * > // {1: ['key' => Bar]}
26
 *
27
 * @param string $class
28
 * @param null|string|\Closure $strategy
29
 * @return \Closure
30
 */
31
function type($class, $strategy = null)
32
{
33 4
    $strategy = conversions\mixed_to_value_getter($strategy);
34
    return function ($value, $key = null) use ($class, $strategy) {
35 3
        return $strategy($value, $key) instanceof $class;
36 4
    };
37
}
38
39
/**
40
 * Returns a filter closure that only accepts values that are in $HAYSTACK.
41
 *
42
 * For example, the following will return a list where all items
43
 * are either 'b' or 'c':
44
 * > $list = iterable(['a', 'b', 'c', 'd', 'e']);
45
 * > $result = $list->filter(in(['b', 'c']));
46
 * > // {1: 'b', 2: 'c'}
47
 *
48
 * For example, the following will return a list where all items
49
 * have a property or array index 'key' that is either 'b' or 'c':
50
 * > $list = iterable([['key' => 'a'], ['key' => 'b'], ['key' => 'c'], ['key' => 'd'], ['key' => 'e']]);
51
 * > $result = $list->filter(in(['b', 'c'], 'key'));
52
 * > // {1: ['key' => 'b'], 2: ['key' => 'c']}
53
 *
54
 * @param null|array|string|\Iterator $haystack
55
 * @param null|string|\Closure $strategy
56
 * @param boolean $strict
57
 * @return \Closure
58
 */
59 View Code Duplication
function in($haystack, $strategy = null, $strict = false)
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
60
{
61 14
    if (!is_bool($strict)) {
62 5
        throw new \InvalidArgumentException('$STRICT must be a boolean');
63
    }
64 9
    if (!is_array($haystack)) {
65 5
        $haystack = Itertools\iterable($haystack)->values();
0 ignored issues
show
Bug introduced by
It seems like $haystack can also be of type null; however, Zicht\Itertools\iterable() does only seem to accept array|string|object<Iterator>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
66
    }
67 6
    $strategy = conversions\mixed_to_value_getter($strategy);
68
    return function ($value, $key = null) use ($haystack, $strategy, $strict) {
69 6
        return in_array($strategy($value, $key), $haystack, $strict);
70 6
    };
71
}
72
73
/**
74
 * Returns a filter closure that only accepts values that are not in $HAYSTACK.
75
 *
76
 * @param array|string|\Iterator $haystack
77
 * @param null|string|\Closure $strategy
78
 * @param boolean $strict
79
 * @return \Closure
80
 *
81
 * @deprecated Instead use not(in(...))
82
 */
83 View Code Duplication
function not_in($haystack, $strategy = null, $strict = false)
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
84
{
85
    if (!is_bool($strict)) {
86
        throw new \InvalidArgumentException('$STRICT must be a boolean');
87
    }
88
    if (!is_array($haystack)) {
89
        $haystack = Itertools\iterable($haystack)->values();
90
    }
91
    $strategy = conversions\mixed_to_value_getter($strategy);
92
    return function ($value, $key = null) use ($haystack, $strategy, $strict) {
93
        return !in_array($strategy($value, $key), $haystack, $strict);
94
    };
95
}
96
97
/**
98
 * Returns a filter closure that only accepts values that are equal to $EXPECTED
99
 *
100
 * For example, the following will return a list where all items
101
 * equal 'bar':
102
 * > $list = iterable(['foo', 'bar']);
103
 * > $result = $list->filter(equals('bar'));
104
 * > // {1: 'bar'}
105
 *
106
 * For example, the following will return a list where all items
107
 * have a property or array index 'foo' that equals 'bar':
108
 * > $list = iterable([['key' => 'foo'], ['key' => 'bar']]);
109
 * > $result = $list->filter(equals('bar', 'key'));
110
 * > // {1: ['key' => 'bar']}
111
 *
112
 * @param mixed $expected
113
 * @param null|string|\Closure $strategy
114
 * @param boolean $strict
115
 * @return \Closure
116
 */
117
function equals($expected, $strategy = null, $strict = false)
118
{
119 11
    if (!is_bool($strict)) {
120 5
        throw new \InvalidArgumentException('$STRICT must be a boolean');
121
    }
122 6
    $strategy = conversions\mixed_to_value_getter($strategy);
123 6
    if ($strict) {
124
        return function ($value, $key = null) use ($expected, $strategy) {
125 1
            return $expected === $strategy($value, $key);
126 1
        };
127
    } else {
128
        return function ($value, $key = null) use ($expected, $strategy) {
129 6
            return $expected == $strategy($value, $key);
130 6
        };
131
    }
132
}
133
134
/**
135
 * Returns a filter closute that only accepts values that are after $EXPECTED
136
 *
137
 * For example, the following will return a list where only
138
 * returns entries that are after 2020-04-01:
139
 * > $list = iterable([new \DateTime('2020-01-01'), new \DateTime('2020-03-01'), new \DateTime('2020-05-01')])
140
 * > $result = $list->filer(after(new \DateTimeImmutable('2020-04-01')));
141
 * > // [new \DateTime('2020-05-01')]
142
 *
143
 * @param \DateTimeInterface|int|float $expected
144
 * @param null|string|\Closure $strategy
145
 * @param bool $orEqual
146
 * @return \Closure
147
 */
148
function after($expected, $strategy = null, $orEqual = false)
149
{
150 17
    $strategy = conversions\mixed_to_value_getter($strategy);
151
152
    // Support DateTimeInterface
153 17 View Code Duplication
    if ($expected instanceof \DateTimeInterface) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
154
        return function ($value, $key = null) use ($expected, $strategy, $orEqual) {
155 5
            $value = $strategy($value, $key);
156 5
            return $value instanceof \DateTimeInterface && ($orEqual ? $expected <= $value : $expected < $value);
157 5
        };
158
    }
159
160
    // Support numbers
161 12 View Code Duplication
    if (is_int($expected) || is_float($expected)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
162
        return function ($value, $key = null) use ($expected, $strategy, $orEqual) {
163 11
            $value = $strategy($value, $key);
164 11
            return (is_int($value) || is_float($value)) && ($orEqual ? $expected <= $value : $expected < $value);
165 11
        };
166
    }
167
168
    // Everything else fails
169
    return function () {
170 1
        return false;
171 1
    };
172
}
173
174
/**
175
 * Returns a filter closute that only accepts values that are before $EXPECTED
176
 *
177
 * For example, the following will return a list where only
178
 * returns entries that are before 2020-04-01:
179
 * > $list = iterable([new \DateTime('2020-01-01'), new \DateTime('2020-03-01'), new \DateTime('2020-05-01')])
180
 * > $result = $list->filer(before(new \DateTimeImmutable('2020-04-01')));
181
 * > // [new \DateTime('2020-01-01'), new \DateTime('2020-03-01')]
182
 *
183
 * @param \DateTimeInterface|int|float $expected
184
 * @param null|string|\Closure $strategy
185
 * @param bool $orEqual
186
 * @return \Closure
187
 */
188
function before($expected, $strategy = null, $orEqual = false)
189
{
190 17
    $strategy = conversions\mixed_to_value_getter($strategy);
191
192
    // Support DateTimeInterface
193 17 View Code Duplication
    if ($expected instanceof \DateTimeInterface) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
194
        return function ($value, $key = null) use ($expected, $strategy, $orEqual) {
195 5
            $value = $strategy($value, $key);
196 5
            return $value instanceof \DateTimeInterface && ($orEqual ? $expected >= $value : $expected > $value);
197 5
        };
198
    }
199
200
    // Support numbers
201 12 View Code Duplication
    if (is_int($expected) || is_float($expected)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
202
        return function ($value, $key = null) use ($expected, $strategy, $orEqual) {
203 11
            $value = $strategy($value, $key);
204 11
            return (is_int($value) || is_float($value)) && ($orEqual ? $expected >= $value : $expected > $value);
205 11
        };
206
    }
207
208
    // Everything else fails
209
    return function () {
210 1
        return false;
211 1
    };
212
}
213
214
/**
215
 * Returns a filter closure that inverts the value
216
 *
217
 * For example, the following will return a list where none
218
 * of the items equal 'bar'
219
 * > $list = iterable(['foo', 'bar']);
220
 * > $result = $list->filter(not(equals('bar')));
221
 * > // {0: 'foo'}
222
 *
223
 * @param null|string|\Closure $strategy
224
 * @return \Closure
225
 */
226
function not($strategy = null)
227
{
228 2
    $strategy = conversions\mixed_to_value_getter($strategy);
229
    return function ($value, $key = null) use ($strategy) {
230 2
        return !($strategy($value, $key));
231 2
    };
232
}
233
234
/**
235
 * Returns a filter closure that only accepts values that match the given regular expression.
236
 *
237
 * For example, the following will return a list where all items
238
 * match 'bar':
239
 * > $list = iterable(['-= foo =-', '-= bar =-']);
240
 * > $result = $list->filter(match('/bar/i'));
241
 * > // {1: '-= bar =-'}
242
 *
243
 * @param string $pattern
244
 * @param null|string|\Closure $strategy
245
 * @return \Closure
246
 */
247
function match($pattern, $strategy = null)
248
{
249 7
    if (!is_string($pattern)) {
250 4
        throw new \InvalidArgumentException('$PATTERN must be a string');
251
    }
252
253 3
    $strategy = conversions\mixed_to_value_getter($strategy);
254
    return function ($value, $key = null) use ($pattern, $strategy) {
255 3
        return (bool)preg_match($pattern, $strategy($value, $key));
256 3
    };
257
}
258