Arr::intersectRecursive()   B
last analyzed

Complexity

Conditions 9
Paths 9

Size

Total Lines 34
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 9

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 17
c 1
b 0
f 0
dl 0
loc 34
ccs 16
cts 16
cp 1
rs 8.0555
cc 9
nc 9
nop 3
crap 9
1
<?php
2
3
namespace ElegantMedia\PHPToolkit;
4
5
class Arr
6
{
7
	/**
8
	 * Is the array an associative array?
9
	 *
10
	 * @param $input
11
	 *
12
	 * @return bool
13
	 */
14
	public static function isAssoc($input): bool
15
	{
16
		if (!is_array($input)) {
17 27
			return false;
18
		}
19 27
20 3
		return array_keys($input) !== range(0, count($input) - 1);
21
	}
22 24
23
	/**
24
	 * Find matching structure on a nested array recursively.
25
	 *
26
	 * @param       $subset
27
	 * @param       $array
28
	 * @param array $results
29
	 *
30
	 * @return array
31
	 */
32
	public static function intersectRecursive($array, $subset, $results = []): array
33
	{
34
		$isAssocArray = self::isAssoc($subset);
35
36 21
		if ($isAssocArray) {
37
			// loop each row of array
38 21
			// iterating through parents
39
			foreach ($subset as $key => $value) {
40 21
				if ($key) {
41
					if (isset($array[$key])) {
42
						$filteredSource = $array[$key];
43 12
44 12
						//if the value is array, it will do the recursive
45 12
						if (is_array($value)) {
46 12
							$loopResults = self::intersectRecursive($filteredSource, $subset[$key], $results);
47
							$results[$key] = $loopResults;
48
						}
49 12
					}
50 12
				}
51 12
			}
52
		} else {
53
			// iterate through final leaf nodes
54
			foreach ($subset as $subsetRow) {
55
				foreach ($array as $sourceRow) {
56
					$subsetRow = self::removeChildArrays($subsetRow);
57
					$sourceRow = self::removeChildArrays($sourceRow);
58 21
					if (array_intersect($subsetRow, $sourceRow) == $subsetRow) {
59 21
						$results[] = $subsetRow;
60 21
					}
61 21
				}
62 21
			}
63 18
		}
64
65
		return $results;
66
	}
67
68
	public static function removeChildArrays($array): array
69 21
	{
70
		$response = [];
71
		foreach ($array as $key => $value) {
72
			if (is_array($value)) {
73 21
				$response[$key] = json_encode($value);
74
			} else {
75 21
				$response[$key] = $value;
76 21
			}
77 21
		}
78 3
79
		return $response;
80 21
	}
81
82
	/**
83 21
	 * Implode but don't include empty values.
84
	 *
85
	 * @param $glue
86
	 * @param $pieces
87
	 *
88
	 * @return string
89
	 */
90
	public static function implodeIgnoreEmpty($glue, $pieces): string
91
	{
92
		// remove empty values
93
		$pieces = array_filter($pieces);
94
95 3
		return implode($glue, $pieces);
96
	}
97
98 3
	/**
99
	 * Replace an existing key of an array with a new one, recursively if required.
100 3
	 *
101
	 * @param array $array
102
	 * @param       $existingKey
103
	 * @param       $newKey
104
	 * @param bool  $recursive
105
	 *
106
	 * @return array
107
	 */
108
	public static function swapKey(array $array, $existingKey, $newKey, $recursive = false): array
109
	{
110
		$allArrayData = [];
111
		foreach ($array as $item) {
112
			$arrayData = $item;
113 6
			if (array_key_exists($existingKey, $arrayData)) {
114
				$arrayData[$newKey] = $arrayData[$existingKey];
115 6
				unset($arrayData[$existingKey]);
116 6
			}
117 6
118 6
			// do this recursively
119 6
			if ($recursive) {
120 6
				if (isset($arrayData[$newKey]) && is_array($arrayData[$newKey]) && count($arrayData[$newKey])) {
121
					$arrayData[$newKey] = self::swapKey($arrayData[$newKey], $existingKey, $newKey, true);
122
				}
123
			}
124 6
125 3
			$allArrayData[] = $arrayData;
126 3
		}
127
128
		return $allArrayData;
129
	}
130 6
131
	/**
132 6
	 * Replace keys of a given array based on a given function
133
	 * Based on http://stackoverflow.com/questions/1444484/how-to-convert-all-keys-in-a-multi-dimenional-array-to-snake-case.
134
	 *
135
	 * @param mixed     $mixed
136
	 * @param callable  $keyReplaceFunction
137
	 * @param bool|true $recursive
138
	 */
139
	public static function swapKeysFn(&$mixed, callable $keyReplaceFunction, $recursive = true): void
140
	{
141
		if (is_array($mixed)) {
142
			foreach (array_keys($mixed) as $key) :
143
				# Working with references here to avoid copying the value,
144
				# Since input data can be large
145
				$value = &$mixed[$key];
146
				unset($mixed[$key]);
147
148
				#  - camelCase to snake_case
149
				$transformedKey = $keyReplaceFunction($key);
150
151
				# Work recursively
152
				if ($recursive && is_array($value)) {
153
					self::swapKeysFn($value, $keyReplaceFunction, $recursive);
154
				}
155
156
				# Store with new key
157 3
				$mixed[$transformedKey] = $value;
158
				# Do not forget to unset references!
159 3
				unset($value);
160
			endforeach;
161 3
		} else {
162 3
			$newVal = preg_replace('/[A-Z]/', '_$0', $mixed);
163 3
			$newVal = strtolower($newVal);
164 3
			$newVal = ltrim($newVal, '_');
165
			$mixed = $newVal;
166
			unset($newVal);
167
		}
168
	}
169 3
170
	/**
171
	 * Get an array and key it by a given key.
172
	 *
173
	 * @example
174
	 * [
175
	 *        [ 'name' => 'john', 'age' => 45 ],
176
	 *        [ 'name' => 'jane', 'age', => 32 ],
177
	 * ]
178
	 * $people = Arr::keyBy($rows, 'name');
179
	 *
180
	 * becomes
181
	 * [
182
	 *        'john' => [ 'age' => 45 ],
183
	 *        'jane' => [ 'age' => 32 ],
184
	 * ]
185
	 *
186
	 * @param $array
187
	 * @param $keyBy
188
	 *
189
	 * @return array
190
	 */
191
	public static function keyBy($array, $keyBy): array
192
	{
193
		$newValues = [];
194
195
		foreach ($array as $key => $value) {
196
			if (is_array($value)) {
197
				if (isset($value[$keyBy]) && $value[$keyBy] !== '') {
198
					$newValues[$value[$keyBy]][] = $value;
199
				}
200
			}
201
		}
202
203
		return $newValues;
204
	}
205
}
206