[CLEANUP] Replace wrong/old file copyright comments
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Utility / ArrayUtility.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Utility;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2010-2012 Extbase Team (http://forge.typo3.org/projects/typo3v4-mvc)
8 * Extbase is a backport of TYPO3 Flow. All credits go to the TYPO3 Flow team.
9 * All rights reserved
10 *
11 * This script is part of the TYPO3 project. The TYPO3 project is
12 * free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * The GNU General Public License can be found at
18 * http://www.gnu.org/copyleft/gpl.html.
19 * A copy is found in the textfile GPL.txt and important notices to the license
20 * from the author is found in LICENSE.txt distributed with these scripts.
21 *
22 *
23 * This script is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * This copyright notice MUST APPEAR in all copies of the script!
29 ***************************************************************/
30 /**
31 * The array functions from the good old t3lib_div plus new code.
32 *
33 * @api
34 */
35 class ArrayUtility {
36
37 /**
38 * Explodes a $string delimited by $delimeter and passes each item in the array through intval().
39 * Corresponds to explode(), but with conversion to integers for all values.
40 *
41 * @param string $delimiter Delimiter string to explode with
42 * @param string $string The string to explode
43 * @return array Exploded values, all converted to integers
44 * @api
45 */
46 static public function integerExplode($delimiter, $string) {
47 $explodedValues = self::trimExplode($delimiter, $string);
48 return array_map('intval', $explodedValues);
49 }
50
51 /**
52 * Explodes a string and trims all values for whitespace in the ends.
53 * If $onlyNonEmptyValues is set, then all blank ('') values are removed.
54 *
55 * @param string $delimiter Delimiter string to explode with
56 * @param string $string The string to explode
57 * @param boolean $onlyNonEmptyValues If set, all empty values (='') will NOT be set in output
58 * @return array Exploded values
59 * @api
60 */
61 static public function trimExplode($delimiter, $string, $onlyNonEmptyValues = FALSE) {
62 $chunksArr = explode($delimiter, $string);
63 $newChunksArr = array();
64 foreach ($chunksArr as $value) {
65 if ($onlyNonEmptyValues === FALSE || strcmp('', trim($value))) {
66 $newChunksArr[] = trim($value);
67 }
68 }
69 reset($newChunksArr);
70 return $newChunksArr;
71 }
72
73 /**
74 * Merges two arrays recursively and "binary safe" (integer keys are overridden as well), overruling similar values in the first array ($firstArray) with the values of the second array ($secondArray)
75 * In case of identical keys, ie. keeping the values of the second.
76 *
77 * @param array $firstArray First array
78 * @param array $secondArray Second array, overruling the first array
79 * @param boolean $dontAddNewKeys If set, keys that are NOT found in $firstArray (first array) will not be set. Thus only existing value can/will be overruled from second array.
80 * @param boolean $emptyValuesOverride If set (which is the default), values from $secondArray will overrule if they are empty (according to PHP's empty() function)
81 * @return array Resulting array where $secondArray values has overruled $firstArray values
82 * @api
83 */
84 static public function arrayMergeRecursiveOverrule(array $firstArray, array $secondArray, $dontAddNewKeys = FALSE, $emptyValuesOverride = TRUE) {
85 foreach ($secondArray as $key => $value) {
86 if (array_key_exists($key, $firstArray) && is_array($firstArray[$key])) {
87 if (is_array($secondArray[$key])) {
88 $firstArray[$key] = self::arrayMergeRecursiveOverrule($firstArray[$key], $secondArray[$key], $dontAddNewKeys, $emptyValuesOverride);
89 } else {
90 $firstArray[$key] = $secondArray[$key];
91 }
92 } else {
93 if ($dontAddNewKeys) {
94 if (array_key_exists($key, $firstArray)) {
95 if ($emptyValuesOverride || !empty($value)) {
96 $firstArray[$key] = $value;
97 }
98 }
99 } else {
100 if ($emptyValuesOverride || !empty($value)) {
101 $firstArray[$key] = $value;
102 }
103 }
104 }
105 }
106 reset($firstArray);
107 return $firstArray;
108 }
109
110 /**
111 * Randomizes the order of array values. The array should not be an associative array
112 * as the key-value relations will be lost.
113 *
114 * @param array $array Array to reorder
115 * @return array The array with randomly ordered values
116 * @api
117 */
118 static public function randomizeArrayOrder(array $array) {
119 $reorderedArray = array();
120 if (count($array) > 1) {
121 $keysInRandomOrder = array_rand($array, count($array));
122 foreach ($keysInRandomOrder as $key) {
123 $reorderedArray[] = $array[$key];
124 }
125 } else {
126 $reorderedArray = $array;
127 }
128 return $reorderedArray;
129 }
130
131 /**
132 * Returns TRUE if the given array contains elements of varying types
133 *
134 * @param array $array
135 * @return boolean
136 * @api
137 */
138 static public function containsMultipleTypes(array $array) {
139 if (count($array) > 0) {
140 foreach ($array as $value) {
141 if (!isset($previousType)) {
142 $previousType = gettype($value);
143 } elseif ($previousType !== gettype($value)) {
144 return TRUE;
145 }
146 }
147 }
148 return FALSE;
149 }
150
151 /**
152 * Replacement for array_reduce that allows any type for $initial (instead
153 * of only integer)
154 *
155 * @param array $array the array to reduce
156 * @param string $function the reduce function with the same order of parameters as in the native array_reduce (i.e. accumulator first, then current array element)
157 * @param mixed $initial the initial accumulator value
158 * @return mixed
159 * @api
160 */
161 static public function array_reduce(array $array, $function, $initial = NULL) {
162 $accumlator = $initial;
163 foreach ($array as $value) {
164 $accumlator = $function($accumlator, $value);
165 }
166 return $accumlator;
167 }
168
169 /**
170 * Returns the value of a nested array by following the specifed path.
171 *
172 * @param array &$array The array to traverse as a reference
173 * @param array|string $path The path to follow. Either a simple array of keys or a string in the format 'foo.bar.baz'
174 * @throws \InvalidArgumentException
175 * @return mixed The value found, NULL if the path didn't exist
176 * @api
177 */
178 static public function getValueByPath(array &$array, $path) {
179 if (is_string($path)) {
180 $path = explode('.', $path);
181 } elseif (!is_array($path)) {
182 throw new \InvalidArgumentException('getValueByPath() expects $path to be string or array, "' . gettype($path) . '" given.', 1304950007);
183 }
184 $key = array_shift($path);
185 if (isset($array[$key])) {
186 if (count($path) > 0) {
187 return is_array($array[$key]) ? self::getValueByPath($array[$key], $path) : NULL;
188 } else {
189 return $array[$key];
190 }
191 } else {
192 return NULL;
193 }
194 }
195
196 /**
197 * Sets the given value in a nested array or object by following the specified path.
198 *
199 * @param array|\ArrayAccess $subject The array or ArrayAccess instance to work on
200 * @param array|string $path The path to follow. Either a simple array of keys or a string in the format 'foo.bar.baz'
201 * @param mixed $value The value to set
202 * @throws \InvalidArgumentException
203 * @return array The modified array or object
204 */
205 static public function setValueByPath($subject, $path, $value) {
206 if (!is_array($subject) && !$subject instanceof \ArrayAccess) {
207 throw new \InvalidArgumentException('setValueByPath() expects $subject to be array or an object implementing \\ArrayAccess, "' . (is_object($subject) ? get_class($subject) : gettype($subject)) . '" given.', 1306424308);
208 }
209 if (is_string($path)) {
210 $path = explode('.', $path);
211 } elseif (!is_array($path)) {
212 throw new \InvalidArgumentException('setValueByPath() expects $path to be string or array, "' . gettype($path) . '" given.', 1305111499);
213 }
214 $key = array_shift($path);
215 if (count($path) === 0) {
216 $subject[$key] = $value;
217 } else {
218 if (!isset($subject[$key]) || !is_array($subject[$key])) {
219 $subject[$key] = array();
220 }
221 $subject[$key] = self::setValueByPath($subject[$key], $path, $value);
222 }
223 return $subject;
224 }
225
226 /**
227 * Unsets an element/part of a nested array by following the specified path.
228 *
229 * @param array $array The array
230 * @param array|string $path The path to follow. Either a simple array of keys or a string in the format 'foo.bar.baz'
231 * @throws \InvalidArgumentException
232 * @return array The modified array
233 */
234 static public function unsetValueByPath(array $array, $path) {
235 if (is_string($path)) {
236 $path = explode('.', $path);
237 } elseif (!is_array($path)) {
238 throw new \InvalidArgumentException('unsetValueByPath() expects $path to be string or array, "' . gettype($path) . '" given.', 1305111513);
239 }
240 $key = array_shift($path);
241 if (count($path) === 0) {
242 unset($array[$key]);
243 } else {
244 if (!isset($array[$key]) || !is_array($array[$key])) {
245 return $array;
246 }
247 $array[$key] = self::unsetValueByPath($array[$key], $path);
248 }
249 return $array;
250 }
251
252 /**
253 * Sorts multidimensional arrays by recursively calling ksort on its elements.
254 *
255 * @param array $array the array to sort
256 * @param integer $sortFlags may be used to modify the sorting behavior using these values (see http://www.php.net/manual/en/function.sort.php)
257 * @return boolean TRUE on success, FALSE on failure
258 * @see asort()
259 * @api
260 */
261 static public function sortKeysRecursively(array &$array, $sortFlags = NULL) {
262 foreach ($array as &$value) {
263 if (is_array($value)) {
264 if (self::sortKeysRecursively($value, $sortFlags) === FALSE) {
265 return FALSE;
266 }
267 }
268 }
269 return ksort($array, $sortFlags);
270 }
271
272 /**
273 * Recursively convert an object hierarchy into an associative array.
274 *
275 * @param mixed $subject An object or array of objects
276 * @throws \InvalidArgumentException
277 * @return array The subject represented as an array
278 */
279 static public function convertObjectToArray($subject) {
280 if (!is_object($subject) && !is_array($subject)) {
281 throw new \InvalidArgumentException('convertObjectToArray expects either array or object as input, ' . gettype($subject) . ' given.', 1287059709);
282 }
283 if (is_object($subject)) {
284 $subject = (array) $subject;
285 }
286 foreach ($subject as $key => $value) {
287 if (is_array($value) || is_object($value)) {
288 $subject[$key] = self::convertObjectToArray($value);
289 }
290 }
291 return $subject;
292 }
293
294 /**
295 * Recursively removes empty array elements.
296 *
297 * @param array $array
298 * @return array the modified array
299 */
300 static public function removeEmptyElementsRecursively(array $array) {
301 $result = $array;
302 foreach ($result as $key => $value) {
303 if (is_array($value)) {
304 $result[$key] = self::removeEmptyElementsRecursively($value);
305 if ($result[$key] === array()) {
306 unset($result[$key]);
307 }
308 } elseif ($value === NULL) {
309 unset($result[$key]);
310 }
311 }
312 return $result;
313 }
314 }
315
316 ?>