Failed Conditions
Pull Request — master (#75)
by
unknown
01:48
created

Arrays::filter()   C

Complexity

Conditions 8
Paths 7

Size

Total Lines 31
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 31
rs 5.3846
c 0
b 0
f 0
cc 8
eloc 15
nc 7
nop 3
1
<?php
2
3
namespace TraderInteractive\Filter;
4
5
use TraderInteractive\Filterer;
6
7
/**
8
 * A collection of filters for arrays.
9
 */
10
final class Arrays
11
{
12
    /**
13
     * Filter an array by throwing if not an array or count not in the min/max range.
14
     *
15
     * The return value is the $value, as expected by the \TraderInteractive\Filterer class.
16
     *
17
     * @param mixed $value the value to filter
18
     * @param int $minCount the minimum allowed count in the array
19
     * @param int $maxCount the maximum allowed count in the array
20
     *
21
     * @return mixed The passed in value
22
     *
23
     * @throws \InvalidArgumentException if $minCount was not an int
24
     * @throws \InvalidArgumentException if $maxCount was not an int
25
     * @throws Exception if $value is not an array
26
     * @throws Exception if $value count is less than $minCount
27
     * @throws Exception if $value count is greater than $maxCount
28
     */
29
    public static function filter($value, int $minCount = 1, int $maxCount = PHP_INT_MAX)
30
    {
31
        if (!is_int($minCount)) {
32
            throw new \InvalidArgumentException('$minCount was not an int');
33
        }
34
35
        if (!is_int($maxCount)) {
36
            throw new \InvalidArgumentException('$maxCount was not an int');
37
        }
38
39
        if (!is_array($value)) {
40
            throw new Exception("Value '" . trim(var_export($value, true), "'") . "' is not an array");
41
        }
42
43
        //optimization for default case
44
        if ($minCount === 1 && empty($value)) {
45
            throw new Exception('$value count of 0 is less than 1');
46
        }
47
48
        $count = count($value);
49
50
        if ($count < $minCount) {
51
            throw new Exception("\$value count of {$count} is less than {$minCount}");
52
        }
53
54
        if ($count > $maxCount) {
55
            throw new Exception("\$value count of {$count} is greater than {$maxCount}");
56
        }
57
58
        return $value;
59
    }
60
61
    /**
62
     * Filter an array by throwing if $value is not in $haystack adhering to $strict.
63
     *
64
     * The return value is the $value, as expected by the \TraderInteractive\Filterer class.
65
     *
66
     * @param mixed $value value to search for
67
     * @param array $haystack array to search in
68
     * @param bool $strict to compare strictly or not. @see in_array()
69
     *
70
     * @return mixed The passed in value
71
     *
72
     * @see in_array()
73
     *
74
     * @throws Exception if $value is not in array $haystack
75
     */
76
    public static function in($value, array $haystack, bool $strict = true)
77
    {
78
        if (!in_array($value, $haystack, $strict)) {
79
            throw new Exception(
80
                "Value '" . trim(var_export($value, true), "'") . "' is not in array " . var_export($haystack, true)
81
            );
82
        }
83
84
        return $value;
85
    }
86
87
    /**
88
     * Filter an array by applying filters to each member
89
     *
90
     * @param array $values an array to be filtered. Use the Arrays::filter() before this method to ensure counts when
91
     *                      you pass into Filterer
92
     * @param array $filters filters with each specified the same as in @see Filterer::filter.
93
     *                       Eg [['string', false, 2], ['uint']]
94
     *
95
     * @return array the filtered $values
96
     *
97
     * @throws Exception if any member of $values fails filtering
98
     */
99
    public static function ofScalars(array $values, array $filters) : array
100
    {
101
        $wrappedFilters = [];
102
        foreach ($values as $key => $item) {
103
            $wrappedFilters[$key] = $filters;
104
        }
105
106
        list($status, $result, $error) = Filterer::filter($wrappedFilters, $values);
107
        if (!$status) {
108
            throw new Exception($error);
109
        }
110
111
        return $result;
112
    }
113
114
    /**
115
     * Filter an array by applying filters to each member
116
     *
117
     * @param array $values as array to be filtered. Use the Arrays::filter() before this method to ensure counts when
118
     *                      you pass into Filterer
119
     * @param array $spec spec to apply to each $values member, specified the same as in @see Filterer::filter.
120
     *     Eg ['key' => ['required' => true, ['string', false], ['unit']], 'key2' => ...]
121
     *
122
     * @return array the filtered $values
123
     *
124
     * @throws Exception if any member of $values fails filtering
125
     */
126
    public static function ofArrays(array $values, array $spec) : array
127
    {
128
        $results = [];
129
        $errors = [];
130
        foreach ($values as $key => $item) {
131
            if (!is_array($item)) {
132
                $errors[] = "Value at position '{$key}' was not an array";
133
                continue;
134
            }
135
136
            list($status, $result, $error) = Filterer::filter($spec, $item);
137
            if (!$status) {
138
                $errors[] = $error;
139
                continue;
140
            }
141
142
            $results[$key] = $result;
143
        }
144
145
        if (!empty($errors)) {
146
            throw new Exception(implode("\n", $errors));
147
        }
148
149
        return $results;
150
    }
151
152
    /**
153
     * Filter $value by using a Filterer $spec and Filterer's default options.
154
     *
155
     * @param array $value array to be filtered. Use the Arrays::filter() before this method to ensure counts when you
156
     *                     pass into Filterer
157
     * @param array $spec spec to apply to $value, specified the same as in @see Filterer::filter.
158
     *     Eg ['key' => ['required' => true, ['string', false], ['unit']], 'key2' => ...]
159
     *
160
     * @return array the filtered $value
161
     *
162
     * @throws Exception if $value fails filtering
163
     */
164
    public static function ofArray(array $value, array $spec) : array
165
    {
166
        list($status, $result, $error) = Filterer::filter($spec, $value);
167
        if (!$status) {
168
            throw new Exception($error);
169
        }
170
171
        return $result;
172
    }
173
174
    /**
175
     * Given a multi-dimensional array, flatten the array to a single level.
176
     *
177
     * The order of the values will be maintained, but the keys will not.
178
     *
179
     * For example, given the array [[1, 2], [3, [4, 5]]], this would result in the array [1, 2, 3, 4, 5].
180
     *
181
     * @param array $value The array to flatten.
182
     *
183
     * @return array The single-dimension array.
184
     */
185
    public static function flatten(array $value) : array
186
    {
187
        $result = [];
188
189
        array_walk_recursive(
190
            $value,
191
            function ($item) use (&$result) {
192
                $result[] = $item;
193
            }
194
        );
195
196
        return $result;
197
    }
198
}
199