Arrays::filter()   C
last analyzed

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