Passed
Push — master ( 89d351...c23d0c )
by Pauli
01:55
created

Util::explode()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 4
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 5
ccs 0
cts 4
cp 0
crap 12
rs 10
1
<?php
2
3
/**
4
 * ownCloud - Music app
5
 *
6
 * This file is licensed under the Affero General Public License version 3 or
7
 * later. See the COPYING file.
8
 *
9
 * @author Pauli Järvinen <[email protected]>
10
 * @copyright Pauli Järvinen 2018 - 2020
11
 */
12
13
namespace OCA\Music\Utility;
14
15
/**
16
 * Miscellaneous static utility functions
17
 */
18
class Util {
19
20
	/**
21
	 * Extract ID of each array element by calling getId and return
22
	 * the IDs as an array
23
	 * @param array $arr
24
	 * @return array
25
	 */
26 4
	public static function extractIds(array $arr) {
27
		return \array_map(function ($i) {
28 4
			return $i->getId();
29 4
		}, $arr);
30
	}
31
32
	/**
33
	 * Extract User ID of each array element by calling getUserId and return
34
	 * the IDs as an array
35
	 * @param array $arr
36
	 * @return array
37
	 */
38
	public static function extractUserIds(array $arr) {
39
		return \array_map(function ($i) {
40
			return $i->getUserId();
41
		}, $arr);
42
	}
43
44
	/**
45
	 * Create look-up table from given array of items which have a `getId` function.
46
	 * @param array $array
47
	 * @return array where keys are the values returned by `getId` of each item
48
	 */
49
	public static function createIdLookupTable(array $array) {
50
		$lut = [];
51
		foreach ($array as $item) {
52
			$lut[$item->getId()] = $item;
53
		}
54
		return $lut;
55
	}
56
57
	/**
58
	 * Get difference of two arrays, i.e. elements belonging to $b but not $a.
59
	 * This function is faster than the built-in array_diff for large arrays but
60
	 * at the expense of higher RAM usage and can be used only for arrays of
61
	 * integers or strings.
62
	 * From https://stackoverflow.com/a/8827033
63
	 * @param array $b
64
	 * @param array $a
65
	 * @return array
66
	 */
67
	public static function arrayDiff(array $b, array $a) {
68
		$at = \array_flip($a);
69
		$d = [];
70
		foreach ($b as $i) {
71
			if (!isset($at[$i])) {
72
				$d[] = $i;
73
			}
74
		}
75
		return $d;
76
	}
77
78
	/**
79
	 * Get multiple items from @a $array, as indicated by a second array @a $indices.
80
	 * @param array $array
81
	 * @param array $indices
82
	 * @return array
83
	 */
84
	public static function arrayMultiGet(array $array, array $indices) {
85
		$result = [];
86
		foreach ($indices as $index) {
87
			$result[] = $array[$index];
88
		}
89
		return $result;
90
	}
91
92
	/**
93
	 * Convert the given array $arr so that keys of the potentially multi-dimensional array
94
	 * are converted using the mapping given in $dictionary. Keys not found from $dictionary
95
	 * are not altered. 
96
	 * @param array $arr
97
	 * @param array $dictionary
98
	 * @return array
99
	 */
100
	public static function convertArrayKeys(array $arr, array $dictionary) {
101
		$newArr = [];
102
103
		foreach ($arr as $k => $v) {
104
			$key = self::arrayGetOrDefault($dictionary, $k, $k);
105
			$newArr[$key] = is_array($v) ? self::convertArrayKeys($v, $dictionary) : $v;
106
		}
107
108
		return $newArr;
109
	}
110
111
	/**
112
	 * Get array value if exists, otherwise return a default value or null.
113
	 * The function supports getting value from a nested array by giving an array-type $key.
114
	 * In that case, the first value of the $key is used on the outer-most array, second value
115
	 * from $key on the next level, and so on. That is, arrayGetOrDefault($arr, ['a', 'b', 'c'])
116
	 * will return $arr['a']['b']['c'] is all the keys along the path are found.
117
	 *
118
	 * @param array $array
119
	 * @param int|string|array $key
120
	 * @param mixed|null $default
121
	 * @return mixed|null
122
	 */
123 3
	public static function arrayGetOrDefault(array $array, $key, $default=null) {
124 3
		if (!\is_array($key)) {
125 3
			$key = [$key];
126
		}
127
128 3
		$temp = $array;
129 3
		foreach ($key as $k) {
130 3
			if (isset($temp[$k])) {
131
				$temp = $temp[$k];
132
			} else {
133 3
				return $default;
134
			}
135
		}
136
		return $temp;
137
	}
138
139
	/**
140
	 * Like the built-in \explode(...) function but this one can be safely called with
141
	 * null string, and no warning will be emitted. Also, this returns an empty array from
142
	 * null and '' inputs while the built-in alternative returns a 1-item array containing
143
	 * an empty string.
144
	 * @param string $delimiter
145
	 * @param string|null $string
146
	 * @return array
147
	 */
148
	public static function explode($delimiter, $string) {
149
		if ($string === null || $string === '') {
150
			return [];
151
		} else {
152
			return \explode($delimiter, $string);
153
		}
154
	}
155
156
	/**
157
	 * Truncate the given string to maximum length, appendig ellipsis character
158
	 * if the truncation happened. Also null argument may be safely passed and
159
	 * it remains unaltered.
160
	 * @param string|null $string
161
	 * @param int $maxLength
162
	 * @return string|null
163
	 */
164 3
	public static function truncate($string, $maxLength) {
165 3
		if ($string === null) {
166 1
			return null;
167
		} else {
168 2
			return \mb_strimwidth($string, 0, $maxLength, "\u{2026}");
169
		}
170
	}
171
172
	/**
173
	 * Test if given string starts with another given string
174
	 * @param string $string
175
	 * @param string $potentialStart
176
	 * @param boolean $ignoreCase
177
	 * @return boolean
178
	 */
179
	public static function startsWith($string, $potentialStart, $ignoreCase=false) {
180
		$actualStart = \substr($string, 0, \strlen($potentialStart));
181
		if ($ignoreCase) {
182
			$actualStart= \mb_strtolower($actualStart);
183
			$potentialStart= \mb_strtolower($potentialStart);
184
		}
185
		return $actualStart === $potentialStart;
186
	}
187
188
	/**
189
	 * Test if given string ends with another given string
190
	 * @param string $string
191
	 * @param string $potentialEnd
192
	 * @param boolean $ignoreCase
193
	 * @return boolean
194
	 */
195
	public static function endsWith($string, $potentialEnd, $ignoreCase=false) {
196
		$actualEnd = \substr($string, -\strlen($potentialEnd));
197
		if ($ignoreCase) {
198
			$actualEnd = \mb_strtolower($actualEnd);
199
			$potentialEnd = \mb_strtolower($potentialEnd);
200
		}
201
		return $actualEnd === $potentialEnd;
202
	}
203
204
	/**
205
	 * Multi-byte safe case-insensitive string comparison
206
	 * @param string $a
207
	 * @param string $b
208
	 * @return int < 0 if $a is less than $b; > 0 if $a is greater than $b, and 0 if they are equal. 
209
	 */
210
	public static function stringCaseCompare($a, $b) {
211
		return \strcmp(\mb_strtolower($a), \mb_strtolower($b));
212
	}
213
214
	/**
215
	 * Convert file size given in bytes to human-readable format
216
	 * @param int $bytes
217
	 * @param int $decimals
218
	 * @return string
219
	 */
220
	public static function formatFileSize($bytes, $decimals = 1) {
221
		$units = 'BKMGTP';
222
		$factor = \floor((\strlen($bytes) - 1) / 3);
223
		return \sprintf("%.{$decimals}f", $bytes / \pow(1024, $factor)) . @$units[(int)$factor];
224
	}
225
226
	/**
227
	 * @param Folder $parentFolder
0 ignored issues
show
Bug introduced by
The type OCA\Music\Utility\Folder was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
228
	 * @param string $relativePath
229
	 * @return Folder
230
	 */
231
	public static function getFolderFromRelativePath($parentFolder, $relativePath) {
232
		if ($relativePath !== null && $relativePath !== '/' && $relativePath !== '') {
233
			return $parentFolder->get($relativePath);
234
		} else {
235
			return $parentFolder;
236
		}
237
	}
238
239
	/**
240
	 * Create relative path from the given working dir (CWD) to the given target path
241
	 * @param string $cwdPath Absolute CWD path
242
	 * @param string $targetPath Absolute target path
243
	 * @return string
244
	 */
245
	public static function relativePath($cwdPath, $targetPath) {
246
		$cwdParts = \explode('/', $cwdPath);
247
		$targetParts = \explode('/', $targetPath);
248
249
		// remove the common prefix of the paths
250
		while (\count($cwdParts) > 0 && \count($targetParts) > 0 && $cwdParts[0] === $targetParts[0]) {
251
			\array_shift($cwdParts);
252
			\array_shift($targetParts);
253
		}
254
255
		// prepend up-navigation from CWD to the closest common parent folder with the target
256
		for ($i = 0, $count = \count($cwdParts); $i < $count; ++$i) {
257
			\array_unshift($targetParts, '..');
258
		}
259
260
		return \implode('/', $targetParts);
261
	}
262
263
	/**
264
	 * Given a current working directory path (CWD) and a relative path (possibly containing '..' parts),
265
	 * form an absolute path matching the relative path. This is a reverse operation for Util::relativePath().
266
	 * @param string $cwdPath
267
	 * @param string $relativePath
268
	 * @return string
269
	 */
270
	public static function resolveRelativePath($cwdPath, $relativePath) {
271
		$cwdParts = \explode('/', $cwdPath);
272
		$relativeParts = \explode('/', $relativePath);
273
274
		// get rid of the trailing empty part of CWD which appears when CWD has a trailing '/'
275
		if ($cwdParts[\count($cwdParts)-1] === '') {
276
			\array_pop($cwdParts);
277
		}
278
279
		foreach ($relativeParts as $part) {
280
			if ($part === '..') {
281
				\array_pop($cwdParts);
282
			} else {
283
				\array_push($cwdParts, $part);
284
			}
285
		}
286
287
		return \implode('/', $cwdParts);
288
	}
289
290
	/**
291
	 * Encode a file path so that it can be used as part of a WebDAV URL
292
	 * @param string $path
293
	 * @return string
294
	 */
295
	public static function urlEncodePath($path) {
296
		// URL encode each part of the file path
297
		return \join('/', \array_map('rawurlencode', \explode('/', $path)));
298
	}
299
300
	/**
301
	 * Swap values of two variables in place
302
	 * @param mixed $a
303
	 * @param mixed $b
304
	 */
305
	public static function swap(&$a, &$b) {
306
		$temp = $a;
307
		$a = $b;
308
		$b = $temp;
309
	}
310
}
311