1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\Utils;
9:
10: use Nette;
11:
12:
13: 14: 15: 16: 17:
18: class Arrays
19: {
20:
21: 22: 23:
24: final public function __construct()
25: {
26: throw new Nette\StaticClassException;
27: }
28:
29:
30: 31: 32: 33:
34: public static function get(array $arr, $key, $default = NULL)
35: {
36: foreach (is_array($key) ? $key : array($key) as $k) {
37: if (is_array($arr) && array_key_exists($k, $arr)) {
38: $arr = $arr[$k];
39: } else {
40: if (func_num_args() < 3) {
41: throw new Nette\InvalidArgumentException("Missing item '$k'.");
42: }
43: return $default;
44: }
45: }
46: return $arr;
47: }
48:
49:
50: 51: 52: 53:
54: public static function & getRef(& $arr, $key)
55: {
56: foreach (is_array($key) ? $key : array($key) as $k) {
57: if (is_array($arr) || $arr === NULL) {
58: $arr = & $arr[$k];
59: } else {
60: throw new Nette\InvalidArgumentException('Traversed item is not an array.');
61: }
62: }
63: return $arr;
64: }
65:
66:
67: 68: 69: 70:
71: public static function mergeTree($arr1, $arr2)
72: {
73: $res = $arr1 + $arr2;
74: foreach (array_intersect_key($arr1, $arr2) as $k => $v) {
75: if (is_array($v) && is_array($arr2[$k])) {
76: $res[$k] = self::mergeTree($v, $arr2[$k]);
77: }
78: }
79: return $res;
80: }
81:
82:
83: 84: 85: 86:
87: public static function searchKey($arr, $key)
88: {
89: $foo = array($key => NULL);
90: return array_search(key($foo), array_keys($arr), TRUE);
91: }
92:
93:
94: 95: 96: 97:
98: public static function insertBefore(array & $arr, $key, array $inserted)
99: {
100: $offset = self::searchKey($arr, $key);
101: $arr = array_slice($arr, 0, $offset, TRUE) + $inserted + array_slice($arr, $offset, count($arr), TRUE);
102: }
103:
104:
105: 106: 107: 108:
109: public static function insertAfter(array & $arr, $key, array $inserted)
110: {
111: $offset = self::searchKey($arr, $key);
112: $offset = $offset === FALSE ? count($arr) : $offset + 1;
113: $arr = array_slice($arr, 0, $offset, TRUE) + $inserted + array_slice($arr, $offset, count($arr), TRUE);
114: }
115:
116:
117: 118: 119: 120:
121: public static function renameKey(array & $arr, $oldKey, $newKey)
122: {
123: $offset = self::searchKey($arr, $oldKey);
124: if ($offset !== FALSE) {
125: $keys = array_keys($arr);
126: $keys[$offset] = $newKey;
127: $arr = array_combine($keys, $arr);
128: }
129: }
130:
131:
132: 133: 134: 135:
136: public static function grep(array $arr, $pattern, $flags = 0)
137: {
138: set_error_handler(function($severity, $message) use ($pattern) {
139: restore_error_handler();
140: throw new RegexpException("$message in pattern: $pattern");
141: });
142: $res = preg_grep($pattern, $arr, $flags);
143: restore_error_handler();
144: if (preg_last_error()) {
145: throw new RegexpException(NULL, preg_last_error(), $pattern);
146: }
147: return $res;
148: }
149:
150:
151: 152: 153: 154:
155: public static function flatten(array $arr, $preserveKeys = FALSE)
156: {
157: $res = array();
158: $cb = $preserveKeys
159: ? function($v, $k) use (& $res) { $res[$k] = $v; }
160: : function($v) use (& $res) { $res[] = $v; };
161: array_walk_recursive($arr, $cb);
162: return $res;
163: }
164:
165:
166: 167: 168: 169:
170: public static function isList($value)
171: {
172: return is_array($value) && (!$value || array_keys($value) === range(0, count($value) - 1));
173: }
174:
175:
176: 177: 178: 179:
180: public static function associate(array $arr, $path)
181: {
182: $parts = is_array($path)
183: ? $path
184: : preg_split('#(\[\]|->|=|\|)#', $path, NULL, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
185:
186: if (!$parts || $parts[0] === '=' || $parts[0] === '|' || $parts === array('->')) {
187: throw new Nette\InvalidArgumentException("Invalid path '$path'.");
188: }
189:
190: $res = $parts[0] === '->' ? new \stdClass : array();
191:
192: foreach ($arr as $rowOrig) {
193: $row = (array) $rowOrig;
194: $x = & $res;
195:
196: for ($i = 0; $i < count($parts); $i++) {
197: $part = $parts[$i];
198: if ($part === '[]') {
199: $x = & $x[];
200:
201: } elseif ($part === '=') {
202: if (isset($parts[++$i])) {
203: $x = $row[$parts[$i]];
204: $row = NULL;
205: }
206:
207: } elseif ($part === '->') {
208: if (isset($parts[++$i])) {
209: $x = & $x->{$row[$parts[$i]]};
210: } else {
211: $row = is_object($rowOrig) ? $rowOrig : (object) $row;
212: }
213:
214: } elseif ($part !== '|') {
215: $x = & $x[(string) $row[$part]];
216: }
217: }
218:
219: if ($x === NULL) {
220: $x = $row;
221: }
222: }
223:
224: return $res;
225: }
226:
227: }
228: