collection.php (7693B)
1 <?php 2 /** 3 * Inspired by Laravel Collection. 4 * @link https://github.com/illuminate/collections 5 */ 6 namespace Elementor\Core\Utils; 7 8 if ( ! defined( 'ABSPATH' ) ) { 9 exit; // Exit if accessed directly. 10 } 11 12 class Collection implements \ArrayAccess, \Countable, \IteratorAggregate { 13 /** 14 * The items contained in the collection. 15 * 16 * @var array 17 */ 18 protected $items; 19 20 /** 21 * Collection constructor. 22 * 23 * @param array $items 24 */ 25 public function __construct( array $items ) { 26 $this->items = $items; 27 } 28 29 /** 30 * @param callable|null $callback 31 * 32 * @return $this 33 */ 34 public function filter( callable $callback = null ) { 35 if ( ! $callback ) { 36 return new static( array_filter( $this->items ) ); 37 } 38 39 return new static( array_filter( $this->items, $callback, ARRAY_FILTER_USE_BOTH ) ); 40 } 41 42 /** 43 * @param $items 44 * 45 * @return $this 46 */ 47 public function merge( $items ) { 48 if ( $items instanceof Collection ) { 49 $items = $items->all(); 50 } 51 52 return new static( array_merge( $this->items, $items ) ); 53 } 54 55 /** 56 * Union the collection with the given items. 57 * 58 * @param array $items 59 * 60 * @return $this 61 */ 62 public function union( array $items ) { 63 return new static( $this->all() + $items ); 64 } 65 66 /** 67 * Merge array recursively 68 * 69 * @param $items 70 * 71 * @return $this 72 */ 73 public function merge_recursive( $items ) { 74 if ( $items instanceof Collection ) { 75 $items = $items->all(); 76 } 77 78 return new static( array_merge_recursive( $this->items, $items ) ); 79 } 80 81 /** 82 * Replace array recursively 83 * 84 * @param $items 85 * 86 * @return $this 87 */ 88 public function replace_recursive( $items ) { 89 if ( $items instanceof Collection ) { 90 $items = $items->all(); 91 } 92 93 return new static( array_replace_recursive( $this->items, $items ) ); 94 } 95 96 /** 97 * Implode the items 98 * 99 * @param $glue 100 * 101 * @return string 102 */ 103 public function implode( $glue ) { 104 return implode( $glue, $this->items ); 105 } 106 107 /** 108 * Run a map over each of the items. 109 * 110 * @param callable $callback 111 * @return $this 112 */ 113 public function map( callable $callback ) { 114 $keys = array_keys( $this->items ); 115 116 $items = array_map( $callback, $this->items, $keys ); 117 118 return new static( array_combine( $keys, $items ) ); 119 } 120 121 /** 122 * @param callable $callback 123 * @param null $initial 124 * 125 * @return mixed|null 126 */ 127 public function reduce( callable $callback, $initial = null ) { 128 $result = $initial; 129 130 foreach ( $this->all() as $key => $value ) { 131 $result = $callback( $result, $value, $key ); 132 } 133 134 return $result; 135 } 136 137 /** 138 * @param callable $callback 139 * 140 * @return $this 141 */ 142 public function map_with_keys( callable $callback ) { 143 $result = []; 144 145 foreach ( $this->items as $key => $value ) { 146 $assoc = $callback( $value, $key ); 147 148 foreach ( $assoc as $map_key => $map_value ) { 149 $result[ $map_key ] = $map_value; 150 } 151 } 152 153 return new static( $result ); 154 } 155 156 /** 157 * Get all items except for those with the specified keys. 158 * 159 * @param array $keys 160 * 161 * @return $this 162 */ 163 public function except( array $keys ) { 164 return $this->filter( function ( $value, $key ) use ( $keys ) { 165 return ! in_array( $key, $keys, true ); 166 } ); 167 } 168 169 /** 170 * Get the items with the specified keys. 171 * 172 * @param array $keys 173 * 174 * @return $this 175 */ 176 public function only( array $keys ) { 177 return $this->filter( function ( $value, $key ) use ( $keys ) { 178 return in_array( $key, $keys, true ); 179 } ); 180 } 181 182 /** 183 * Run over the collection to get specific prop from the collection item. 184 * 185 * @param $key 186 * 187 * @return $this 188 */ 189 public function pluck( $key ) { 190 $result = []; 191 192 foreach ( $this->items as $item ) { 193 $result[] = $this->get_item_value( $item, $key ); 194 } 195 196 return new static( $result ); 197 } 198 199 /** 200 * Group the collection items by specific key in each collection item. 201 * 202 * @param $group_by 203 * 204 * @return $this 205 */ 206 public function group_by( $group_by ) { 207 $result = []; 208 209 foreach ( $this->items as $item ) { 210 $group_key = $this->get_item_value( $item, $group_by, 0 ); 211 212 $result[ $group_key ][] = $item; 213 } 214 215 return new static( $result ); 216 } 217 218 /** 219 * Sort keys 220 * 221 * @param false $descending 222 * 223 * @return $this 224 */ 225 public function sort_keys( $descending = false ) { 226 $items = $this->items; 227 228 if ( $descending ) { 229 krsort( $items ); 230 } else { 231 ksort( $items ); 232 } 233 234 return new static( $items ); 235 } 236 237 /** 238 * Get specific item from the collection. 239 * 240 * @param $key 241 * @param null $default 242 * 243 * @return mixed|null 244 */ 245 public function get( $key, $default = null ) { 246 if ( ! array_key_exists( $key, $this->items ) ) { 247 return $default; 248 } 249 250 return $this->items[ $key ]; 251 } 252 253 /** 254 * Get the first item. 255 * 256 * @param null $default 257 * 258 * @return mixed|null 259 */ 260 public function first( $default = null ) { 261 if ( $this->is_empty() ) { 262 return $default; 263 } 264 265 foreach ( $this->items as $item ) { 266 return $item; 267 } 268 } 269 270 /** 271 * Find an element from the items. 272 * 273 * @param callable $callback 274 * @param null $default 275 * 276 * @return mixed|null 277 */ 278 public function find( callable $callback, $default = null ) { 279 foreach ( $this->all() as $key => $item ) { 280 if ( $callback( $item, $key ) ) { 281 return $item; 282 } 283 } 284 285 return $default; 286 } 287 288 /** 289 * Make sure all the values inside the array are uniques. 290 * 291 * @param null|string|string[] $keys 292 * 293 * @return $this 294 */ 295 public function unique( $keys = null ) { 296 if ( ! $keys ) { 297 return new static( 298 array_unique( $this->items ) 299 ); 300 } 301 302 if ( ! is_array( $keys ) ) { 303 $keys = [ $keys ]; 304 } 305 306 $exists = []; 307 308 return $this->filter( function ( $item ) use ( $keys, &$exists ) { 309 $value = null; 310 311 foreach ( $keys as $key ) { 312 $current_value = $this->get_item_value( $item, $key ); 313 314 $value .= "{$key}:{$current_value};"; 315 } 316 317 // If no value for the specific key return the item. 318 if ( null === $value ) { 319 return true; 320 } 321 322 // If value is not exists, add to the exists array and return the item. 323 if ( ! in_array( $value, $exists, true ) ) { 324 $exists[] = $value; 325 326 return true; 327 } 328 329 return false; 330 } ); 331 } 332 333 /** 334 * @return array 335 */ 336 public function keys() { 337 return array_keys( $this->items ); 338 } 339 340 /** 341 * @return bool 342 */ 343 public function is_empty() { 344 return empty( $this->items ); 345 } 346 347 /** 348 * @return array 349 */ 350 public function all() { 351 return $this->items; 352 } 353 354 /** 355 * @return array 356 */ 357 public function values() { 358 return array_values( $this->all() ); 359 } 360 361 /** 362 * @param mixed $key 363 * 364 * @return bool 365 */ 366 public function offsetExists( $key ) { 367 return isset( $this->items[ $key ] ); 368 } 369 370 /** 371 * @param mixed $key 372 * 373 * @return mixed 374 */ 375 public function offsetGet( $key ) { 376 return $this->items[ $key ]; 377 } 378 379 /** 380 * @param mixed $key 381 * @param mixed $value 382 */ 383 public function offsetSet( $key, $value ) { 384 if ( is_null( $key ) ) { 385 $this->items[] = $value; 386 } else { 387 $this->items[ $key ] = $value; 388 } 389 } 390 391 /** 392 * @param mixed $key 393 */ 394 public function offsetUnset( $key ) { 395 unset( $this->items[ $key ] ); 396 } 397 398 /** 399 * @return \ArrayIterator|\Traversable 400 */ 401 public function getIterator() { 402 return new \ArrayIterator( $this->items ); 403 } 404 405 /** 406 * @return int|void 407 */ 408 public function count() { 409 return count( $this->items ); 410 } 411 412 /** 413 * @param $item 414 * @param $key 415 * @param null $default 416 * 417 * @return mixed|null 418 */ 419 private function get_item_value( $item, $key, $default = null ) { 420 $value = $default; 421 422 if ( is_object( $item ) && isset( $item->{$key} ) ) { 423 $value = $item->{$key}; 424 } elseif ( is_array( $item ) && isset( $item[ $key ] ) ) { 425 $value = $item[ $key ]; 426 } 427 428 return $value; 429 } 430 }