1: <?php
2:
3: namespace Xu\Model;
4:
5: use ArrayAccess;
6: use ReflectionClass;
7: use Xu\Foundation\Jsonable;
8:
9: class Collection extends Jsonable implements ArrayAccess {
10:
11: 12: 13: 14: 15:
16: protected $items = [];
17:
18: 19: 20: 21: 22:
23: public function __construct( array $items = [] ) {
24: $this->items = $items;
25: }
26:
27: 28: 29: 30: 31:
32: public function all() {
33: return $this->items;
34: }
35:
36: 37: 38: 39: 40:
41: public function count() {
42: return count( $this->items );
43: }
44:
45: 46: 47: 48: 49: 50: 51:
52: public function eq( $offset ) {
53: return $this->offsetGet( $offset );
54: }
55:
56: 57: 58: 59: 60: 61: 62: 63: 64:
65: public function filter( $callback, $value = null ) {
66: if ( ! is_callable( $callback ) ) {
67: $callback = function ( $item ) use ( $callback, $value ) {
68: return $item[$callback] === $value;
69: };
70: }
71:
72: return new static( array_values( array_filter( $this->items, $callback ) ) );
73: }
74:
75: 76: 77: 78: 79: 80: 81: 82: 83:
84: protected function find_in_item( $attributes, $key, $default = null ) {
85: if ( empty( $key ) || ! is_string( $key ) ) {
86: return;
87: }
88:
89: $key = explode( '.', $key );
90:
91: foreach ( $key as $part ) {
92: if ( is_object( $attributes ) && get_class( $attributes ) === 'stdClass' ) {
93: $attributes = (array) $attributes;
94: }
95:
96: if (
97: $attributes instanceof Model === false
98: &&
99: ( ! is_array( $attributes ) || ! array_key_exists( $part, $attributes ) )
100: ) {
101: return $default;
102: }
103:
104: $attributes = $attributes[$part];
105: }
106:
107: if ( is_null( $attributes ) ) {
108: return $default;
109: }
110:
111: return $attributes;
112: }
113:
114: 115: 116: 117: 118: 119: 120:
121: public function first( callable $callback = null ) {
122: if ( empty( $callback ) ) {
123: return $this->items[0];
124: }
125:
126: if ( $items = $this->filter( $callback ) ) {
127: return $items->first();
128: }
129: }
130:
131: 132: 133: 134: 135:
136: public function is_empty() {
137: return empty( $this->items );
138: }
139:
140: 141: 142: 143: 144: 145: 146:
147: public function last( callable $callback = null ) {
148: if ( empty( $callback ) ) {
149: return $this->items[count( $this->items ) - 1];
150: }
151:
152: if ( $items = $this->filter( $callback ) ) {
153: return $items->last();
154: }
155: }
156:
157: 158: 159: 160: 161: 162: 163:
164: public function map( callable $callback ) {
165: $keys = array_keys( $this->items );
166: $items = array_map( $callback, $this->items, $keys );
167: return new static( array_combine( $keys, $items ) );
168: }
169:
170: 171: 172: 173: 174: 175: 176:
177: public function offsetExists( $offset ) {
178: return isset( $this->items[$offset] );
179: }
180:
181: 182: 183: 184: 185: 186: 187:
188: public function offsetGet( $offset ) {
189: return $this->items[$offset];
190: }
191:
192: 193: 194: 195: 196: 197:
198: public function offsetSet( $offset, $value ) {
199: $this->items[$offset] = $value;
200: }
201:
202: 203: 204: 205: 206:
207: public function offsetUnset( $offset ) {
208: unset( $this->items[$offset] );
209: }
210:
211: 212: 213: 214: 215: 216: 217:
218: public function pluck( $key ) {
219: return wp_list_pluck( $this->items, $key );
220: }
221:
222: 223: 224: 225: 226:
227: public function pop() {
228: return array_pop( $this->items );
229: }
230:
231: 232: 233: 234: 235: 236: 237: 238: 239:
240: public function reject( $callback, $value = null ) {
241: if ( ! is_callable( $callback ) ) {
242: $callback = function ( $item ) use ( $callback, $value ) {
243: return $item[$callback] === $value;
244: };
245: }
246:
247: return $this->filter( function ( $item ) use ( $callback ) {
248: return ! $callback( $item );
249: } );
250: }
251:
252: 253: 254: 255: 256:
257: public function reverse() {
258: return new static( array_reverse( $this->items ) );
259: }
260:
261: 262: 263: 264: 265:
266: public function shift() {
267: return array_shift( $this->items );
268: }
269:
270: 271: 272: 273: 274: 275: 276: 277: 278:
279: public function slice( $offset, $length = null, $preserve_keys = false ) {
280: return new static( array_slice( $this->items, $offset ) );
281: }
282:
283: 284: 285: 286: 287: 288: 289:
290: public function sort( callable $callback ) {
291: $items = $this->all();
292: uasort( $items, $callback );
293: return new static( array_values( $items ) );
294: }
295:
296: 297: 298: 299: 300: 301: 302: 303:
304: public function where( $key, $value = null ) {
305: if ( is_callable( $key ) ) {
306: return $this->filter( $key );
307: }
308:
309: return $this->filter( function ( $item ) use ( $key, $value ) {
310: return $this->find_in_item( $item, $key ) === $value;
311: } );
312: }
313:
314: 315: 316: 317: 318:
319: public function to_array() {
320: return $this->items;
321: }
322: }
323: