Failed Conditions
Pull Request — master (#75)
by
unknown
03:37
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 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, $minCount = 1, $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 the passed in value
71
     *
72
     * @see in_array()
73
     * @throws \InvalidArgumentException if $strict was not a bool
74
     * @throws Exception if $value is not in array $haystack
75
     */
76
    public static function in($value, array $haystack, $strict = true)
77
    {
78
        if ($strict !== true && $strict !== false) {
79
            throw new \InvalidArgumentException('$strict was not a bool');
80
        }
81
82
        if (!in_array($value, $haystack, $strict)) {
83
            throw new Exception(
84
                "Value '" . trim(var_export($value, true), "'") . "' is not in array " . var_export($haystack, true)
85
            );
86
        }
87
88
        return $value;
89
    }
90
91
    /**
92
     * Filter an array by applying filters to each member
93
     *
94
     * @param array $values an array to be filtered. Use the Arrays::filter() before this method to ensure counts when
95
     *                      you pass into Filterer
96
     * @param array $filters filters with each specified the same as in @see Filterer::filter.
97
     *                       Eg [['string', false, 2], ['uint']]
98
     *
99
     * @return array the filtered $values
100
     *
101
     * @throws Exception if any member of $values fails filtering
102
     */
103
    public static function ofScalars(array $values, array $filters)
104
    {
105
        $wrappedFilters = [];
106
        foreach ($values as $key => $item) {
107
            $wrappedFilters[$key] = $filters;
108
        }
109
110
        list($status, $result, $error) = Filterer::filter($wrappedFilters, $values);
111
        if (!$status) {
112
            throw new Exception($error);
113
        }
114
115
        return $result;
116
    }
117
118
    /**
119
     * Filter an array by applying filters to each member
120
     *
121
     * @param array $values as array to be filtered. Use the Arrays::filter() before this method to ensure counts when
122
     *                      you pass into Filterer
123
     * @param array $spec spec to apply to each $values member, specified the same as in @see Filterer::filter.
124
     *     Eg ['key' => ['required' => true, ['string', false], ['unit']], 'key2' => ...]
125
     *
126
     * @return array the filtered $values
127
     *
128
     * @throws Exception if any member of $values fails filtering
129
     */
130
    public static function ofArrays(array $values, array $spec)
131
    {
132
        $results = [];
133
        $errors = [];
134
        foreach ($values as $key => $item) {
135
            if (!is_array($item)) {
136
                $errors[] = "Value at position '{$key}' was not an array";
137
                continue;
138
            }
139
140
            list($status, $result, $error) = Filterer::filter($spec, $item);
141
            if (!$status) {
142
                $errors[] = $error;
143
                continue;
144
            }
145
146
            $results[$key] = $result;
147
        }
148
149
        if (!empty($errors)) {
150
            throw new Exception(implode("\n", $errors));
151
        }
152
153
        return $results;
154
    }
155
156
    /**
157
     * Filter $value by using a Filterer $spec and Filterer's default options.
158
     *
159
     * @param array $value array to be filtered. Use the Arrays::filter() before this method to ensure counts when you
160
     *                     pass into Filterer
161
     * @param array $spec spec to apply to $value, specified the same as in @see Filterer::filter.
162
     *     Eg ['key' => ['required' => true, ['string', false], ['unit']], 'key2' => ...]
163
     *
164
     * @return array the filtered $value
165
     *
166
     * @throws Exception if $value fails filtering
167
     */
168
    public static function ofArray(array $value, array $spec)
169
    {
170
        list($status, $result, $error) = Filterer::filter($spec, $value);
171
        if (!$status) {
172
            throw new Exception($error);
173
        }
174
175
        return $result;
176
    }
177
178
    /**
179
     * Given a multi-dimensional array, flatten the array to a single level.
180
     *
181
     * The order of the values will be maintained, but the keys will not.
182
     *
183
     * For example, given the array [[1, 2], [3, [4, 5]]], this would result in the array [1, 2, 3, 4, 5].
184
     *
185
     * @param array $value The array to flatten.
186
     *
187
     * @return array The single-dimension array.
188
     */
189
    public static function flatten(array $value)
190
    {
191
        $result = [];
192
193
        array_walk_recursive(
194
            $value,
195
            function ($item) use (&$result) {
196
                $result[] = $item;
197
            }
198
        );
199
200
        return $result;
201
    }
202
}
203