Completed
Push — master ( da4b4a...f70588 )
by Chad
12s queued 11s
created

Arrays::findDuplicates()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 1
dl 0
loc 14
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace TraderInteractive\Filter;
4
5
use InvalidArgumentException;
6
use TraderInteractive\Exceptions\FilterException;
7
use TraderInteractive\Filter\Exceptions\DuplicateValuesException;
8
9
/**
10
 * A collection of filters for arrays.
11
 */
12
final class Arrays
13
{
14
    /**
15
     * @var int
16
     */
17
    const ARRAY_PAD_END = 1;
18
19
    /**
20
     * @var int
21
     */
22
    const ARRAY_PAD_FRONT = 2;
23
24
    /**
25
     * @var int
26
     */
27
    const ARRAY_UNIQUE_SORT_REGULAR = \SORT_REGULAR;
28
29
    /**
30
     * @var int
31
     */
32
    const ARRAY_UNIQUE_SORT_NUMERIC = \SORT_NUMERIC;
33
34
    /**
35
     * @var int
36
     */
37
    const ARRAY_UNIQUE_SORT_STRING = \SORT_STRING;
38
39
    /**
40
     * @var int
41
     */
42
    const ARRAY_UNIQUE_SORT_LOCALE_STRING = \SORT_LOCALE_STRING;
43
44
    /**
45
     * Filter an array by throwing if not an array or count not in the min/max range.
46
     *
47
     * @param mixed   $value    The value to filter.
48
     * @param integer $minCount The minimum allowed count in the array.
49
     * @param integer $maxCount The maximum allowed count in the array.
50
     *
51
     * @return array
52
     *
53
     * @throws FilterException if $value is not an array
54
     * @throws FilterException if $value count is less than $minCount
55
     * @throws FilterException if $value count is greater than $maxCount
56
     */
57
    public static function filter($value, int $minCount = 1, int $maxCount = PHP_INT_MAX) : array
58
    {
59
        if (!is_array($value)) {
60
            throw new FilterException("Value '" . trim(var_export($value, true), "'") . "' is not an array");
61
        }
62
63
        $count = count($value);
64
        if ($count < $minCount) {
65
            throw new FilterException("\$value count of {$count} is less than {$minCount}");
66
        }
67
68
        if ($count > $maxCount) {
69
            throw new FilterException("\$value count of {$count} is greater than {$maxCount}");
70
        }
71
72
        return $value;
73
    }
74
75
    /**
76
     * Filter an array by throwing if $value is not in $haystack adhering to $strict.
77
     *
78
     * @param mixed $value    The searched value.
79
     * @param array $haystack The array to be searched.
80
     * @param bool  $strict   Flag to compare strictly or not. @see in_array()
81
     *
82
     * @return mixed The passed in value
83
     *
84
     * @throws FilterException if $value is not in array $haystack
85
     */
86
    public static function in($value, array $haystack, bool $strict = true)
87
    {
88
        if (!in_array($value, $haystack, $strict)) {
89
            throw new FilterException(
90
                "Value '" . trim(var_export($value, true), "'") . "' is not in array " . var_export($haystack, true)
91
            );
92
        }
93
94
        return $value;
95
    }
96
97
    /**
98
     * Given a multi-dimensional array, flatten the array to a single level.
99
     *
100
     * The order of the values will be maintained, but the keys will not.
101
     *
102
     * For example, given the array [[1, 2], [3, [4, 5]]], this would result in the array [1, 2, 3, 4, 5].
103
     *
104
     * @param array $value The array to flatten.
105
     *
106
     * @return array The single-dimension array.
107
     */
108
    public static function flatten(array $value) : array
109
    {
110
        $result = [];
111
112
        $callBack = function ($item) use (&$result) {
113
            $result[] = $item;
114
        };
115
116
        array_walk_recursive($value, $callBack);
117
118
        return $result;
119
    }
120
121
    /**
122
     * Converts any non-array value to a single element array.
123
     *
124
     * @param mixed $value The value to convert.
125
     *
126
     * @return array The coverted array or the original value.
127
     */
128
    public static function arrayize($value) : array
129
    {
130
        if ($value === null) {
131
            return [];
132
        }
133
134
        if (!is_array($value)) {
135
            return [$value];
136
        }
137
138
        return $value;
139
    }
140
141
    /**
142
     * Copies values from the $source array into a new array using the $keyMap for destination keys.
143
     *
144
     * @param array[] $source The arrays with values to be copied.
145
     * @param array   $keyMap mapping of dest keys to source keys. If $keyMap is associative, the keys will be the
146
     *                        destination keys. If numeric the values will be the destination keys
147
     *
148
     * @return array
149
     */
150
    public static function copyEach(array $source, array $keyMap) : array
151
    {
152
        $result = [];
153
        foreach ($source as $sourceArray) {
154
            $result[] = self::copy($sourceArray, $keyMap);
155
        }
156
157
        return $result;
158
    }
159
160
    /**
161
     * Copies values from the $source array into a new array using the $keyMap for destination keys.
162
     *
163
     * @param array $source The array with values to be copied.
164
     * @param array $keyMap mapping of dest keys to source keys. If $keyMap is associative, the keys will be the
165
     *                      destination keys. If numeric the values will be the destination keys
166
     *
167
     * @return array
168
     */
169
    public static function copy(array $source, array $keyMap) : array
170
    {
171
        $result = [];
172
        foreach ($keyMap as $destinationKey => $sourceKey) {
173
            if (is_int($destinationKey)) {
174
                $destinationKey = $sourceKey;
175
            }
176
177
            if (array_key_exists($sourceKey, $source)) {
178
                $result[$destinationKey] = $source[$sourceKey];
179
            }
180
        }
181
182
        return $result;
183
    }
184
185
    /**
186
     * Pad array to the specified length with a value. Padding optionally to the front or end of the array.
187
     *
188
     * @param array $input    Initial array of values to pad.
189
     * @param int   $size     The new size of the array.
190
     * @param mixed $padValue Value to pad if $input is less than $size.
191
     * @param int   $padType  Optional argument to specify which end of the array to pad.
192
     *
193
     * @return array Returns a copy of the $input array padded to size specified by $size with value $padValue
194
     *
195
     * @throws InvalidArgumentException Thrown if $padType is invalid.
196
     */
197
    public static function pad(array $input, int $size, $padValue = null, int $padType = self::ARRAY_PAD_END) : array
198
    {
199
        if ($padType === self::ARRAY_PAD_END) {
200
            return array_pad($input, $size, $padValue);
201
        }
202
203
        if ($padType !== self::ARRAY_PAD_FRONT) {
204
            throw new InvalidArgumentException('Invalid $padType value provided');
205
        }
206
207
        while (count($input) < $size) {
208
            array_unshift($input, $padValue);
209
        }
210
211
        return $input;
212
    }
213
214
    /**
215
     * Removes duplicate values from an array.
216
     *
217
     * @param array $input     The array to be filtered.
218
     * @param int   $sortFlags Optional parameter used to modify the sorting behavior.
219
     * @param bool  $strict    If set to TRUE the filter will throw exception if the $input array contains duplicates.
220
     *
221
     * @return array
222
     *
223
     * @throws FilterException Thrown if the array contains duplicates and $strict is true.
224
     */
225
    public static function unique(
226
        array $input,
227
        int $sortFlags = self::ARRAY_UNIQUE_SORT_REGULAR,
228
        bool $strict = false
229
    ) : array {
230
        $unique = array_unique($input, $sortFlags);
231
        if ($unique !== $input && $strict === true) {
232
            $duplicateValues = self::findDuplicates($input);
233
            throw new DuplicateValuesException($duplicateValues);
234
        }
235
236
        return $unique;
237
    }
238
239
    private static function findDuplicates(array $input) : array
240
    {
241
        $temp = [];
242
        $duplicates = [];
243
        foreach ($input as $key => $value) {
244
            if (!in_array($value, $temp, true)) {
245
                $temp[] = $value;
246
                continue;
247
            }
248
249
            $duplicates[$key] = $value;
250
        }
251
252
        return $duplicates;
253
    }
254
}
255