Completed
Pull Request — master (#15)
by James
03:45
created
src/Contract/Axolotl/Collection.php 1 patch
Indentation   +314 added lines, -314 removed lines patch added patch discarded remove patch
@@ -9,318 +9,318 @@
 block discarded – undo
9 9
 
10 10
 interface Collection extends Iterator, Countable, Serializes {
11 11
 
12
-	/**
13
-	 * Returns the type of the collection.
14
-	 *
15
-	 * @return string
16
-	 */
17
-	public function get_type();
18
-
19
-	/**
20
-	 * Returns a collection with $element added.
21
-	 *
22
-	 * @param  mixed $element
23
-	 * @return Collection
24
-	 * @throws InvalidArgumentException
25
-	 */
26
-	public function add( $element );
27
-
28
-	/**
29
-	 * Removes every element from the collection.
30
-	 *
31
-	 * @return Collection
32
-	 */
33
-	public function clear();
34
-
35
-	/**
36
-	 * Returns true if the collection contains any elements that satisfy
37
-	 * $condition, returns false if it contains none.
38
-	 *
39
-	 * @param callable $condition
40
-	 * @return bool
41
-	 */
42
-	public function contains( callable $condition );
43
-
44
-	/**
45
-	 * Returns the first element in the collection that satisfies
46
-	 * $condition, returns false if no such element exists.
47
-	 *
48
-	 * @param callable $condition
49
-	 * @return mixed
50
-	 */
51
-	public function find( callable $condition );
52
-
53
-	/**
54
-	 * Returns the index of the first element in the collection that satisfies
55
-	 * $condition, returns -1 if no such element exists.
56
-	 *
57
-	 * @param callable $condition
58
-	 * @return int
59
-	 */
60
-	public function find_index( callable $condition );
61
-
62
-	/**
63
-	 * Returns the element in the collection at $index.
64
-	 *
65
-	 * @param  int $index Index to get element from.
66
-	 * @return mixed
67
-	 * @throws OutOfRangeException
68
-	 */
69
-	public function at( $index );
70
-
71
-	/**
72
-	 * Returns true if $index is within the collection's range and returns false
73
-	 * if it is not.
74
-	 *
75
-	 * @param  int $index Index to check for existence.
76
-	 * @return bool
77
-	 * @throws InvalidArgumentException
78
-	 */
79
-	public function index_exists( $index );
80
-
81
-	/**
82
-	 * Returns the number of elements in the collection.
83
-	 *
84
-	 * @return int
85
-	 */
86
-	public function count();
87
-
88
-	/**
89
-	 * Returns a collection that only contains the elements which satisfy
90
-	 * $condition.
91
-	 *
92
-	 * @param callable $condition
93
-	 * @return Collection
94
-	 */
95
-	public function filter( callable $condition );
96
-
97
-	/**
98
-	 * Returns the last element in the collection that satisfies $condition,
99
-	 * returns false if no such element exists.
100
-	 *
101
-	 * @param callable $condition
102
-	 * @return mixed
103
-	 */
104
-	public function find_last( callable $condition );
105
-
106
-	/**
107
-	 * Returns the index of the last element in the collection that satisfies
108
-	 * $condition, returns -1 if no such element exists.
109
-	 *
110
-	 * @param callable $condition
111
-	 * @return int
112
-	 */
113
-	public function find_last_index( callable $condition );
114
-
115
-	/**
116
-	 * Returns a collection that contains the subset of elements ranging from the
117
-	 * index $start to $end.
118
-	 *
119
-	 * @param  int $start Begining index to slice from.
120
-	 * @param  int $end   End index to slice to.
121
-	 * @return Collection
122
-	 * @throws InvalidArgumentException
123
-	 */
124
-	public function slice( $start, $end );
125
-
126
-	/**
127
-	 * Inserts $element at $index.
128
-	 *
129
-	 * @param int   $index     Index to start at.
130
-	 * @param mixed $element Element to insert.
131
-	 * @return Collection
132
-	 * @throws InvalidArgumentException
133
-	 * @throws OutOfRangeException
134
-	 */
135
-	public function insert( $index, $element );
136
-
137
-	/**
138
-	 * Inserts the range $elements at $index.
139
-	 *
140
-	 * @param int   $index
141
-	 * @param array $elements
142
-	 * @return Collection
143
-	 * @throws OutOfRangeException
144
-	 */
145
-	public function insert_range( $index, array $elements );
146
-
147
-	/**
148
-	 * Removes all of the elements that satisfy $condition.
149
-	 *
150
-	 * @param  callable $condition
151
-	 * @return Collection
152
-	 */
153
-	public function without( callable $condition );
154
-
155
-	/**
156
-	 * Removes the element at $index.
157
-	 *
158
-	 * @param  int $index Index to remove.
159
-	 * @return Collection
160
-	 * @throws OutOfRangeException
161
-	 */
162
-	public function remove_at( $index );
163
-
164
-	/**
165
-	 * Reverses the order of the elements in the collection.
166
-	 *
167
-	 * @return Collection
168
-	 */
169
-	public function reverse();
170
-
171
-	/**
172
-	 * Sorts the elements in the collection using the user supplied comparison
173
-	 * function $callback.
174
-	 *
175
-	 * @param callable $callback
176
-	 * @return Collection
177
-	 */
178
-	public function sort( callable $callback );
179
-
180
-	/**
181
-	 * Returns an array containing the elements in the collection.
182
-	 *
183
-	 * @return array
184
-	 */
185
-	public function to_array();
186
-
187
-	/**
188
-	 * Iteratively reduces the collection to a single value using the callback
189
-	 * function $callable.
190
-	 *
191
-	 * @param callable $callable
192
-	 * @param null     $initial
193
-	 * @return mixed
194
-	 */
195
-	public function reduce( callable $callable, $initial = null );
196
-
197
-	/**
198
-	 * Returns true if every element in the collection satisfies $condition,
199
-	 * returns false if not.
200
-	 *
201
-	 * @param callable $condition
202
-	 * @return bool
203
-	 */
204
-	public function every( callable $condition );
205
-
206
-	/**
207
-	 * Removes all of the elements in the collection starting at index $num.
208
-	 *
209
-	 * @param  int $num Number of elements to drop.
210
-	 * @return Collection
211
-	 * @throws InvalidArgumentException
212
-	 */
213
-	public function drop( $num );
214
-
215
-	/**
216
-	 * Removes all of the elements in the collectioin between index 0 and $num.
217
-	 *
218
-	 * @param int $num Number of elements to drop.
219
-	 * @return Collection
220
-	 * @throws InvalidArgumentException
221
-	 */
222
-	public function drop_right( $num );
223
-
224
-	/**
225
-	 * Iteratively drops elements in the collection that satisfy $condition until
226
-	 * an element is encountered that does not satisfy $condition.
227
-	 *
228
-	 * @param callable $condition
229
-	 * @return Collection
230
-	 */
231
-	public function drop_while( callable $condition );
232
-
233
-	/**
234
-	 * Removes the first element in the collection.
235
-	 *
236
-	 * @return Collection
237
-	 * @throws InvalidArgumentException
238
-	 */
239
-	public function tail();
240
-
241
-	/**
242
-	 * Removes all of the elements in the collection starting at index $num.
243
-	 *
244
-	 * @param  int $num Number of elements to take.
245
-	 * @return Collection
246
-	 * @throws InvalidArgumentException
247
-	 */
248
-	public function take( $num );
249
-
250
-	/**
251
-	 * Removes all of the elements in the collection before index $num.
252
-	 *
253
-	 * @param int $num Number of elements to take.
254
-	 * @return Collection
255
-	 * @throws InvalidArgumentException
256
-	 */
257
-	public function take_right( $num );
258
-
259
-	/**
260
-	 * Iterates through the collection until an element is encountered that does
261
-	 * not satisfy $condition, then drops all of the elements starting at that
262
-	 * index.
263
-	 *
264
-	 * @param callable $condition
265
-	 * @return Collection
266
-	 */
267
-	public function take_while( callable $condition );
268
-
269
-	/**
270
-	 * Applies the callback function $callable to each element in the collection.
271
-	 *
272
-	 * @param callable $callable
273
-	 */
274
-	public function each( callable $callable );
275
-
276
-	/**
277
-	 * Returns a new instance of the collection with the callback function
278
-	 * $callable applied to each element.
279
-	 *
280
-	 * @param callable $callable
281
-	 * @return Collection
282
-	 */
283
-	public function map( callable $callable );
284
-
285
-	/**
286
-	 * Iteratively reduces the collection to a single value using the callback
287
-	 * function $callable starting at the rightmost index.
288
-	 *
289
-	 * @param callable $callable
290
-	 * @param null     $initial
291
-	 * @return mixed
292
-	 */
293
-	public function reduce_right( callable $callable, $initial = null );
294
-
295
-	/**
296
-	 * Randomly reorders the elements in the collection.
297
-	 *
298
-	 * @return Collection
299
-	 */
300
-	public function shuffle();
301
-
302
-	/**
303
-	 * Adds every member of $elements to the collection.
304
-	 *
305
-	 * @param array|Collection $elements Array of elements to merge.
306
-	 * @return Collection
307
-	 * @throws InvalidArgumentException
308
-	 */
309
-	public function merge( $elements );
310
-
311
-	/**
312
-	 * Get first element of the collection
313
-	 *
314
-	 * @return mixed
315
-	 * @throws OutOfBoundsException
316
-	 */
317
-	public function first();
318
-
319
-	/**
320
-	 * Get last element of the collection
321
-	 *
322
-	 * @return mixed
323
-	 * @throws OutOfBoundsException
324
-	 */
325
-	public function last();
12
+    /**
13
+     * Returns the type of the collection.
14
+     *
15
+     * @return string
16
+     */
17
+    public function get_type();
18
+
19
+    /**
20
+     * Returns a collection with $element added.
21
+     *
22
+     * @param  mixed $element
23
+     * @return Collection
24
+     * @throws InvalidArgumentException
25
+     */
26
+    public function add( $element );
27
+
28
+    /**
29
+     * Removes every element from the collection.
30
+     *
31
+     * @return Collection
32
+     */
33
+    public function clear();
34
+
35
+    /**
36
+     * Returns true if the collection contains any elements that satisfy
37
+     * $condition, returns false if it contains none.
38
+     *
39
+     * @param callable $condition
40
+     * @return bool
41
+     */
42
+    public function contains( callable $condition );
43
+
44
+    /**
45
+     * Returns the first element in the collection that satisfies
46
+     * $condition, returns false if no such element exists.
47
+     *
48
+     * @param callable $condition
49
+     * @return mixed
50
+     */
51
+    public function find( callable $condition );
52
+
53
+    /**
54
+     * Returns the index of the first element in the collection that satisfies
55
+     * $condition, returns -1 if no such element exists.
56
+     *
57
+     * @param callable $condition
58
+     * @return int
59
+     */
60
+    public function find_index( callable $condition );
61
+
62
+    /**
63
+     * Returns the element in the collection at $index.
64
+     *
65
+     * @param  int $index Index to get element from.
66
+     * @return mixed
67
+     * @throws OutOfRangeException
68
+     */
69
+    public function at( $index );
70
+
71
+    /**
72
+     * Returns true if $index is within the collection's range and returns false
73
+     * if it is not.
74
+     *
75
+     * @param  int $index Index to check for existence.
76
+     * @return bool
77
+     * @throws InvalidArgumentException
78
+     */
79
+    public function index_exists( $index );
80
+
81
+    /**
82
+     * Returns the number of elements in the collection.
83
+     *
84
+     * @return int
85
+     */
86
+    public function count();
87
+
88
+    /**
89
+     * Returns a collection that only contains the elements which satisfy
90
+     * $condition.
91
+     *
92
+     * @param callable $condition
93
+     * @return Collection
94
+     */
95
+    public function filter( callable $condition );
96
+
97
+    /**
98
+     * Returns the last element in the collection that satisfies $condition,
99
+     * returns false if no such element exists.
100
+     *
101
+     * @param callable $condition
102
+     * @return mixed
103
+     */
104
+    public function find_last( callable $condition );
105
+
106
+    /**
107
+     * Returns the index of the last element in the collection that satisfies
108
+     * $condition, returns -1 if no such element exists.
109
+     *
110
+     * @param callable $condition
111
+     * @return int
112
+     */
113
+    public function find_last_index( callable $condition );
114
+
115
+    /**
116
+     * Returns a collection that contains the subset of elements ranging from the
117
+     * index $start to $end.
118
+     *
119
+     * @param  int $start Begining index to slice from.
120
+     * @param  int $end   End index to slice to.
121
+     * @return Collection
122
+     * @throws InvalidArgumentException
123
+     */
124
+    public function slice( $start, $end );
125
+
126
+    /**
127
+     * Inserts $element at $index.
128
+     *
129
+     * @param int   $index     Index to start at.
130
+     * @param mixed $element Element to insert.
131
+     * @return Collection
132
+     * @throws InvalidArgumentException
133
+     * @throws OutOfRangeException
134
+     */
135
+    public function insert( $index, $element );
136
+
137
+    /**
138
+     * Inserts the range $elements at $index.
139
+     *
140
+     * @param int   $index
141
+     * @param array $elements
142
+     * @return Collection
143
+     * @throws OutOfRangeException
144
+     */
145
+    public function insert_range( $index, array $elements );
146
+
147
+    /**
148
+     * Removes all of the elements that satisfy $condition.
149
+     *
150
+     * @param  callable $condition
151
+     * @return Collection
152
+     */
153
+    public function without( callable $condition );
154
+
155
+    /**
156
+     * Removes the element at $index.
157
+     *
158
+     * @param  int $index Index to remove.
159
+     * @return Collection
160
+     * @throws OutOfRangeException
161
+     */
162
+    public function remove_at( $index );
163
+
164
+    /**
165
+     * Reverses the order of the elements in the collection.
166
+     *
167
+     * @return Collection
168
+     */
169
+    public function reverse();
170
+
171
+    /**
172
+     * Sorts the elements in the collection using the user supplied comparison
173
+     * function $callback.
174
+     *
175
+     * @param callable $callback
176
+     * @return Collection
177
+     */
178
+    public function sort( callable $callback );
179
+
180
+    /**
181
+     * Returns an array containing the elements in the collection.
182
+     *
183
+     * @return array
184
+     */
185
+    public function to_array();
186
+
187
+    /**
188
+     * Iteratively reduces the collection to a single value using the callback
189
+     * function $callable.
190
+     *
191
+     * @param callable $callable
192
+     * @param null     $initial
193
+     * @return mixed
194
+     */
195
+    public function reduce( callable $callable, $initial = null );
196
+
197
+    /**
198
+     * Returns true if every element in the collection satisfies $condition,
199
+     * returns false if not.
200
+     *
201
+     * @param callable $condition
202
+     * @return bool
203
+     */
204
+    public function every( callable $condition );
205
+
206
+    /**
207
+     * Removes all of the elements in the collection starting at index $num.
208
+     *
209
+     * @param  int $num Number of elements to drop.
210
+     * @return Collection
211
+     * @throws InvalidArgumentException
212
+     */
213
+    public function drop( $num );
214
+
215
+    /**
216
+     * Removes all of the elements in the collectioin between index 0 and $num.
217
+     *
218
+     * @param int $num Number of elements to drop.
219
+     * @return Collection
220
+     * @throws InvalidArgumentException
221
+     */
222
+    public function drop_right( $num );
223
+
224
+    /**
225
+     * Iteratively drops elements in the collection that satisfy $condition until
226
+     * an element is encountered that does not satisfy $condition.
227
+     *
228
+     * @param callable $condition
229
+     * @return Collection
230
+     */
231
+    public function drop_while( callable $condition );
232
+
233
+    /**
234
+     * Removes the first element in the collection.
235
+     *
236
+     * @return Collection
237
+     * @throws InvalidArgumentException
238
+     */
239
+    public function tail();
240
+
241
+    /**
242
+     * Removes all of the elements in the collection starting at index $num.
243
+     *
244
+     * @param  int $num Number of elements to take.
245
+     * @return Collection
246
+     * @throws InvalidArgumentException
247
+     */
248
+    public function take( $num );
249
+
250
+    /**
251
+     * Removes all of the elements in the collection before index $num.
252
+     *
253
+     * @param int $num Number of elements to take.
254
+     * @return Collection
255
+     * @throws InvalidArgumentException
256
+     */
257
+    public function take_right( $num );
258
+
259
+    /**
260
+     * Iterates through the collection until an element is encountered that does
261
+     * not satisfy $condition, then drops all of the elements starting at that
262
+     * index.
263
+     *
264
+     * @param callable $condition
265
+     * @return Collection
266
+     */
267
+    public function take_while( callable $condition );
268
+
269
+    /**
270
+     * Applies the callback function $callable to each element in the collection.
271
+     *
272
+     * @param callable $callable
273
+     */
274
+    public function each( callable $callable );
275
+
276
+    /**
277
+     * Returns a new instance of the collection with the callback function
278
+     * $callable applied to each element.
279
+     *
280
+     * @param callable $callable
281
+     * @return Collection
282
+     */
283
+    public function map( callable $callable );
284
+
285
+    /**
286
+     * Iteratively reduces the collection to a single value using the callback
287
+     * function $callable starting at the rightmost index.
288
+     *
289
+     * @param callable $callable
290
+     * @param null     $initial
291
+     * @return mixed
292
+     */
293
+    public function reduce_right( callable $callable, $initial = null );
294
+
295
+    /**
296
+     * Randomly reorders the elements in the collection.
297
+     *
298
+     * @return Collection
299
+     */
300
+    public function shuffle();
301
+
302
+    /**
303
+     * Adds every member of $elements to the collection.
304
+     *
305
+     * @param array|Collection $elements Array of elements to merge.
306
+     * @return Collection
307
+     * @throws InvalidArgumentException
308
+     */
309
+    public function merge( $elements );
310
+
311
+    /**
312
+     * Get first element of the collection
313
+     *
314
+     * @return mixed
315
+     * @throws OutOfBoundsException
316
+     */
317
+    public function first();
318
+
319
+    /**
320
+     * Get last element of the collection
321
+     *
322
+     * @return mixed
323
+     * @throws OutOfBoundsException
324
+     */
325
+    public function last();
326 326
 }
Please login to merge, or discard this patch.
src/Axolotl/Collection.php 1 patch
Indentation   +735 added lines, -735 removed lines patch added patch discarded remove patch
@@ -15,739 +15,739 @@
 block discarded – undo
15 15
  */
16 16
 class Collection implements CollectionContract {
17 17
 
18
-	/**
19
-	 * Collection elements.
20
-	 *
21
-	 * @var array
22
-	 */
23
-	protected $elements = array();
24
-
25
-	/**
26
-	 * Collection type to enforce.
27
-	 *
28
-	 * @var Type
29
-	 */
30
-	private $type;
31
-
32
-	/**
33
-	 * Where Collection is in loop.
34
-	 *
35
-	 * @var int
36
-	 */
37
-	protected $position = 0;
38
-
39
-	/**
40
-	 * Collection constructor.
41
-	 *
42
-	 * @param string $type
43
-	 * @param array  $elements
44
-	 */
45
-	public function __construct( $type, array $elements = array() ) {
46
-		$this->type = new Type( $type );
47
-
48
-		if ( $elements ) {
49
-			$this->type->validate_elements( $elements );
50
-		}
51
-
52
-		$this->elements = $elements;
53
-	}
54
-
55
-	/**
56
-	 * {@inheritdoc}
57
-	 *
58
-	 * @return string
59
-	 */
60
-	public function get_type() {
61
-		return $this->type->get_type();
62
-	}
63
-
64
-	/**
65
-	 * {@inheritdoc}
66
-	 *
67
-	 * @param mixed $element
68
-	 *
69
-	 * @return Collection
70
-	 *
71
-	 * @throws InvalidArgumentException
72
-	 */
73
-	public function add( $element ) {
74
-		if ( $this->type->is_model() && is_array( $element ) ) {
75
-			$element = $this->type->create_model( $element );
76
-		}
77
-
78
-		$this->type->validate_element( $element );
79
-
80
-		$elements   = $this->elements;
81
-		$elements[] = $element;
82
-
83
-		$collection = new static( $this->get_type() );
84
-		$collection->set_from_trusted( $elements );
85
-
86
-		return $collection;
87
-	}
88
-
89
-	/**
90
-	 * {@inheritdoc}
91
-	 *
92
-	 * @return Collection
93
-	 */
94
-	public function clear() {
95
-		return new static( $this->get_type() );
96
-	}
97
-
98
-	/**
99
-	 * {@inheritdoc}
100
-	 *
101
-	 * @param  callable $condition Condition to satisfy.
102
-	 *
103
-	 * @return bool
104
-	 */
105
-	public function contains( callable $condition ) {
106
-		return (bool) $this->find( $condition );
107
-	}
108
-
109
-	/**
110
-	 * {@inheritdoc}
111
-	 *
112
-	 * @param  callable $condition Condition to satisfy.
113
-	 *
114
-	 * @return mixed
115
-	 */
116
-	public function find( callable $condition ) {
117
-		$index = $this->find_index( $condition );
118
-
119
-		return -1 === $index ? false : $this->elements[ $index ];
120
-	}
121
-
122
-	/**
123
-	 * {@inheritdoc}
124
-	 *
125
-	 * @param  callable $condition Condition to satisfy.
126
-	 *
127
-	 * @return int
128
-	 */
129
-	public function find_index( callable $condition ) {
130
-		$index = -1;
131
-
132
-		for ( $i = 0, $count = count( $this->elements ); $i < $count; $i++ ) {
133
-			if ( call_user_func( $condition, ($this->at( $i ) ) ) ) {
134
-				$index = $i;
135
-				break;
136
-			}
137
-		}
138
-
139
-		return $index;
140
-	}
141
-
142
-	/**
143
-	 * Fetches the element at the provided index.
144
-	 *
145
-	 * @param int $index Index to get element from.
146
-	 *
147
-	 * @return mixed
148
-	 *
149
-	 * @throws OutOfRangeException
150
-	 */
151
-	public function at( $index ) {
152
-		$this->validate_index( $index );
153
-
154
-		return $this->elements[ $index ];
155
-	}
156
-
157
-	/**
158
-	 * {@inheritdoc}
159
-	 *
160
-	 * @param  int $index Index to check for existence.
161
-	 *
162
-	 * @return bool
163
-	 *
164
-	 * @throws InvalidArgumentException
165
-	 */
166
-	public function index_exists( $index ) {
167
-		if ( ! is_int( $index ) ) {
168
-			throw new InvalidArgumentException( 'Index must be an integer' );
169
-		}
170
-
171
-		if ( $index < 0 ) {
172
-			throw new InvalidArgumentException( 'Index must be a non-negative integer' );
173
-		}
174
-
175
-		return $index < $this->count();
176
-	}
177
-
178
-	/**
179
-	 * {@inheritdoc}
180
-	 *
181
-	 * @param  callable $condition Condition to satisfy.
182
-	 *
183
-	 * @return mixed
184
-	 */
185
-	public function filter( callable $condition ) {
186
-		$elements = array();
187
-
188
-		foreach ( $this->elements as $element ) {
189
-			if ( call_user_func( $condition, $element ) ) {
190
-				$elements[] = $element;
191
-			}
192
-		}
193
-
194
-		return $this->new_from_trusted( $elements );
195
-	}
196
-	/**
197
-	 * {@inheritdoc}
198
-	 *
199
-	 * @param  callable $condition Condition to satisfy.
200
-	 *
201
-	 * @return mixed
202
-	 */
203
-	public function find_last( callable $condition ) {
204
-		$index = $this->find_last_index( $condition );
205
-
206
-		return -1 === $index ? null : $this->elements[ $index ];
207
-	}
208
-
209
-	/**
210
-	 * {@inheritdoc}
211
-	 *
212
-	 * @param  callable $condition
213
-	 * @return int
214
-	 */
215
-	public function find_last_index( callable $condition ) {
216
-		$index = -1;
217
-
218
-		for ( $i = count( $this->elements ) - 1; $i >= 0; $i-- ) {
219
-			if ( call_user_func( $condition, $this->elements[ $i ] ) ) {
220
-				$index = $i;
221
-				break;
222
-			}
223
-		}
224
-
225
-		return $index;
226
-	}
227
-
228
-	/**
229
-	 * {@inheritdoc}
230
-	 *
231
-	 * @param  int $start Begining index to slice from.
232
-	 * @param  int $end   End index to slice to.
233
-	 *
234
-	 * @return Collection
235
-	 *
236
-	 * @throws InvalidArgumentException
237
-	 */
238
-	public function slice( $start, $end ) {
239
-		if ( $start < 0 || ! is_int( $start ) ) {
240
-			throw new InvalidArgumentException( 'Start must be a non-negative integer' );
241
-		}
242
-
243
-		if ( $end < 0 || ! is_int( $end ) ) {
244
-			throw new InvalidArgumentException( 'End must be a positive integer' );
245
-		}
246
-
247
-		if ( $start > $end ) {
248
-			throw new InvalidArgumentException( 'End must be greater than start' );
249
-		}
250
-
251
-		if ( $end > $this->count() + 1 ) {
252
-			throw new InvalidArgumentException( 'End must be less than the count of the items in the Collection' );
253
-		}
254
-
255
-		$length = $end - $start + 1;
256
-		$subset = array_slice( $this->elements, $start, $length );
257
-
258
-		$collection = new static($this->type);
259
-		$collection->set_from_trusted( $subset );
260
-
261
-		return $collection;
262
-	}
263
-
264
-	/**
265
-	 * {@inheritdoc}
266
-	 *
267
-	 * @param int   $index     Index to start at.
268
-	 * @param mixed $element Element to insert.
269
-	 *
270
-	 * @return Collection
271
-	 *
272
-	 * @throws InvalidArgumentException
273
-	 * @throws OutOfRangeException
274
-	 */
275
-	public function insert( $index, $element ) {
276
-		$this->validate_index( $index );
277
-		$this->type->validate_element( $element );
278
-
279
-		$a = array_slice( $this->elements, 0, $index );
280
-		$b = array_slice( $this->elements, $index, count( $this->elements ) );
281
-
282
-		$a[] = $element;
283
-
284
-		return $this->new_from_trusted( array_merge( $a, $b ) );
285
-	}
286
-
287
-	/**
288
-	 * {@inheritdoc}
289
-	 *
290
-	 * @param int   $index    Index to start insertion at.
291
-	 * @param array $elements Elements in insert.
292
-	 *
293
-	 * @return Collection
294
-	 *
295
-	 * @throws OutOfRangeException
296
-	 */
297
-	public function insert_range( $index, array $elements ) {
298
-		$this->validate_index( $index );
299
-		$this->type->validate_elements( $elements );
300
-
301
-		// To work with negative index, get the positive relation to 0 index
302
-		$index < 0 && $index = $this->count() + $index + 1;
303
-
304
-		$partA = array_slice( $this->elements, 0, $index );
305
-		$partB = array_slice( $this->elements, $index, count( $this->elements ) );
306
-
307
-		$elements1 = array_merge( $partA, $elements );
308
-		$elements1 = array_merge( $elements1, $partB );
309
-
310
-		$col = new static( $this->type );
311
-		$col->set_from_trusted( $elements1 );
312
-
313
-		return $col;
314
-	}
315
-
316
-	/**
317
-	 * {@inheritdoc}
318
-	 *
319
-	 * @param  callable $condition Condition to satisfy.
320
-	 *
321
-	 * @return Collection
322
-	 */
323
-	public function without( callable $condition ) {
324
-		$inverse = function ( $element ) use ( $condition ) {
325
-			return ! call_user_func( $condition, $element );
326
-		};
327
-
328
-		return $this->filter( $inverse );
329
-	}
330
-
331
-	/**
332
-	 * {@inheritdoc}
333
-	 *
334
-	 * @param  int $index Index to remove.
335
-	 *
336
-	 * @return Collection
337
-	 *
338
-	 * @throws OutOfRangeException
339
-	 */
340
-	public function remove_at( $index ) {
341
-		$this->validate_index( $index );
342
-
343
-		$elements = $this->elements;
344
-
345
-		return $this->new_from_trusted(
346
-			array_merge(
347
-				array_slice( $elements, 0, $index ),
348
-				array_slice( $elements, $index + 1, count( $elements ) )
349
-			)
350
-		);
351
-	}
352
-	/**
353
-	 * {@inheritdoc}
354
-	 *
355
-	 * @return Collection
356
-	 */
357
-	public function reverse() {
358
-		return $this->new_from_trusted(
359
-			array_reverse( $this->elements )
360
-		);
361
-	}
362
-
363
-	/**
364
-	 * {@inheritdoc}
365
-	 *
366
-	 * @param callable $callback Sort callback.
367
-	 *
368
-	 * @return Collection
369
-	 */
370
-	public function sort( callable $callback ) {
371
-		$elements = $this->elements;
372
-		usort( $elements, $callback );
373
-		return $this->new_from_trusted( $elements );
374
-	}
375
-
376
-	/**
377
-	 * {@inheritdoc}
378
-	 *
379
-	 * @return array
380
-	 */
381
-	public function to_array() {
382
-		return $this->elements;
383
-	}
384
-
385
-	/**
386
-	 * {@inheritdoc}
387
-	 *
388
-	 * @param callable $callable Reducer function.
389
-	 *
390
-	 * @param null     $initial  Initial reducer value.
391
-	 *
392
-	 * @return mixed
393
-	 */
394
-	public function reduce( callable $callable, $initial = null ) {
395
-		return array_reduce( $this->elements, $callable, $initial );
396
-	}
397
-
398
-	/**
399
-	 * {@inheritdoc}
400
-	 *
401
-	 * @param callable $condition Condition callback.
402
-	 *
403
-	 * @return bool
404
-	 */
405
-	public function every( callable $condition ) {
406
-		$response = true;
407
-
408
-		foreach ( $this->elements as $element ) {
409
-			$result = call_user_func( $condition, $element );
410
-
411
-			if ( false === $result ) {
412
-				$response = false;
413
-				break;
414
-			}
415
-		}
416
-
417
-		return $response;
418
-	}
419
-
420
-	/**
421
-	 * {@inheritdoc}
422
-	 *
423
-	 * @param  int $num Number of elements to drop.
424
-	 *
425
-	 * @return Collection
426
-	 *
427
-	 * @throws InvalidArgumentException
428
-	 */
429
-	public function drop( $num ) {
430
-		return $this->slice( $num, $this->count() );
431
-	}
432
-
433
-	/**
434
-	 * {@inheritdoc}
435
-	 *
436
-	 * @param int $num Number of elements to drop.
437
-	 *
438
-	 * @return Collection
439
-	 *
440
-	 * @throws InvalidArgumentException
441
-	 */
442
-	public function drop_right( $num ) {
443
-		return $num !== $this->count()
444
-			? $this->slice( 0, $this->count() - $num - 1 )
445
-			: $this->clear();
446
-	}
447
-
448
-	/**
449
-	 * {@inheritdoc}
450
-	 *
451
-	 * @param callable $condition Condition callback.
452
-	 *
453
-	 * @return Collection
454
-	 */
455
-	public function drop_while( callable $condition ) {
456
-		$count = $this->count_while_true( $condition );
457
-		return $count ? $this->drop( $count ) : $this;
458
-	}
459
-	/**
460
-	 * {@inheritdoc}
461
-	 *
462
-	 * @return Collection
463
-	 *
464
-	 * @throws InvalidArgumentException
465
-	 */
466
-	public function tail() {
467
-		return $this->slice( 1, $this->count() );
468
-	}
469
-
470
-	/**
471
-	 * {@inheritdoc}
472
-	 *
473
-	 * @param  int $num Number of elements to take.
474
-	 *
475
-	 * @return Collection
476
-	 *
477
-	 * @throws InvalidArgumentException
478
-	 */
479
-	public function take( $num ) {
480
-		return $this->slice( 0, $num - 1 );
481
-	}
482
-
483
-	/**
484
-	 * {@inheritdoc}
485
-	 *
486
-	 * @param int $num Number of elements to take.
487
-	 *
488
-	 * @return Collection
489
-	 *
490
-	 * @throws InvalidArgumentException
491
-	 */
492
-	public function take_right( $num ) {
493
-		return $this->slice( $this->count() - $num, $this->count() );
494
-	}
495
-
496
-	/**
497
-	 * {@inheritdoc}
498
-	 *
499
-	 * @param callable $condition Callback function.
500
-	 *
501
-	 * @return Collection
502
-	 */
503
-	public function take_while( callable $condition ) {
504
-		$count = $this->count_while_true( $condition );
505
-
506
-		return $count ? $this->take( $count ) : $this->clear();
507
-	}
508
-
509
-	/**
510
-	 * {@inheritdoc}
511
-	 *
512
-	 * @param callable $callable Callback function.
513
-	 */
514
-	public function each( callable $callable ) {
515
-		foreach ( $this->elements as $element ) {
516
-			call_user_func( $callable, $element );
517
-		}
518
-	}
519
-
520
-	/**
521
-	 * {@inheritdoc}
522
-	 *
523
-	 * @param callable $callable Callback function.
524
-	 *
525
-	 * @return Collection
526
-	 */
527
-	public function map( callable $callable ) {
528
-		$elements = array();
529
-		$type = null;
530
-		foreach ( $this->elements as $element ) {
531
-			$result = call_user_func( $callable, $element );
532
-
533
-			if ( null === $type ) {
534
-				$type = gettype( $result );
535
-
536
-				if ( 'object' === $type ) {
537
-					$type = get_class( $result );
538
-				}
539
-			}
540
-
541
-			$elements[] = $result;
542
-		}
543
-
544
-		return $this->new_from_trusted( $elements, $type ? : $this->get_type() );
545
-	}
546
-
547
-	/**
548
-	 * {@inheritdoc}
549
-	 *
550
-	 * @param callable $callable Reducer function.
551
-	 * @param null     $initial  Initial value.
552
-	 *
553
-	 * @return mixed
554
-	 */
555
-	public function reduce_right( callable $callable, $initial = null ) {
556
-		return array_reduce(
557
-			array_reverse( $this->elements ),
558
-			$callable,
559
-			$initial
560
-		);
561
-	}
562
-
563
-	/**
564
-	 * {@inheritdoc}
565
-	 *
566
-	 * @return Collection
567
-	 */
568
-	public function shuffle() {
569
-		$elements = $this->elements;
570
-		shuffle( $elements );
571
-
572
-		return $this->new_from_trusted( $elements );
573
-	}
574
-
575
-	/**
576
-	 * {@inheritdoc}
577
-	 *
578
-	 * @param array|Collection $elements Array of elements to merge.
579
-	 *
580
-	 * @return Collection
581
-	 *
582
-	 * @throws InvalidArgumentException
583
-	 */
584
-	public function merge( $elements ) {
585
-		if ( $elements instanceof static ) {
586
-			$elements = $elements->to_array();
587
-		}
588
-
589
-		if ( ! is_array( $elements ) ) {
590
-			throw new InvalidArgumentException( 'Merge must be given array or Collection' );
591
-		}
592
-
593
-		$this->type->validate_elements( $elements );
594
-
595
-		return $this->new_from_trusted(
596
-			array_merge( $this->elements, $elements )
597
-		);
598
-	}
599
-
600
-	/**
601
-	 * {@inheritdoc}
602
-	 *
603
-	 * @return mixed
604
-	 *
605
-	 * @throws OutOfBoundsException
606
-	 */
607
-	public function first() {
608
-		if ( empty( $this->elements ) ) {
609
-			throw new OutOfBoundsException( 'Cannot get first element of empty Collection' );
610
-		}
611
-
612
-		return reset( $this->elements );
613
-	}
614
-
615
-	/**
616
-	 * {@inheritdoc}
617
-	 *
618
-	 * @return mixed
619
-	 *
620
-	 * @throws OutOfBoundsException
621
-	 */
622
-	public function last() {
623
-		if ( empty( $this->elements ) ) {
624
-			throw new OutOfBoundsException( 'Cannot get last element of empty Collection' );
625
-		}
626
-
627
-		return end( $this->elements );
628
-	}
629
-
630
-	/**
631
-	 * {@inheritdoc}
632
-	 *
633
-	 * @return int
634
-	 */
635
-	public function count() {
636
-		return count( $this->elements );
637
-	}
638
-
639
-	/**
640
-	 * {@inheritDoc}
641
-	 *
642
-	 * @return array
643
-	 */
644
-	public function serialize() {
645
-		return $this->map(function( $element ) {
646
-			if ( $element instanceof Serializes ) {
647
-				return $element->serialize();
648
-			}
649
-
650
-			return $element;
651
-		} )->to_array();
652
-	}
653
-
654
-	/**
655
-	 * Return the current element.
656
-	 *
657
-	 * @return mixed
658
-	 */
659
-	public function current() {
660
-		return $this->at( $this->position );
661
-	}
662
-
663
-	/**
664
-	 * Move forward to next element.
665
-	 */
666
-	public function next() {
667
-		$this->position ++;
668
-	}
669
-
670
-	/**
671
-	 * Return the key of the current element.
672
-	 *
673
-	 * @return mixed
674
-	 */
675
-	public function key() {
676
-		return $this->position;
677
-	}
678
-
679
-	/**
680
-	 * Checks if current position is valid.
681
-	 *
682
-	 * @return bool
683
-	 */
684
-	public function valid() {
685
-		return isset( $this->elements[ $this->position ] );
686
-	}
687
-
688
-	/**
689
-	 * Rewind the Iterator to the first element.
690
-	 */
691
-	public function rewind() {
692
-		$this->position = 0;
693
-	}
694
-
695
-	/**
696
-	 * Creates a new instance of the Collection
697
-	 * from a trusted set of elements.
698
-	 *
699
-	 * @param array      $elements Array of elements to pass into new collection.
700
-	 * @param null|mixed $type
701
-	 *
702
-	 * @return static
703
-	 */
704
-	protected function new_from_trusted( array $elements, $type = null ) {
705
-		$collection = new static( null !== $type ? $type : $this->get_type() );
706
-		$collection->set_from_trusted( $elements );
707
-
708
-		return $collection;
709
-	}
710
-
711
-	/**
712
-	 * Sets the elements without validating them.
713
-	 *
714
-	 * @param array $elements Pre-validated elements to set.
715
-	 */
716
-	protected function set_from_trusted( array $elements ) {
717
-		$this->elements = $elements;
718
-	}
719
-
720
-	/**
721
-	 * Number of elements true for the condition.
722
-	 *
723
-	 * @param callable $condition Condition to check.
724
-	 * @return int
725
-	 */
726
-	protected function count_while_true( callable $condition ) {
727
-		$count = 0;
728
-
729
-		foreach ( $this->elements as $element ) {
730
-			if ( ! $condition($element) ) {
731
-				break;
732
-			}
733
-			$count++;
734
-		}
735
-
736
-		return $count;
737
-	}
738
-
739
-	/**
740
-	 * Validates a number to be used as an index.
741
-	 *
742
-	 * @param  integer $index The number to be validated as an index.
743
-	 *
744
-	 * @throws OutOfRangeException
745
-	 */
746
-	protected function validate_index( $index ) {
747
-		$exists = $this->index_exists( $index );
748
-
749
-		if ( ! $exists ) {
750
-			throw new OutOfRangeException( 'Index out of bounds of collection' );
751
-		}
752
-	}
18
+    /**
19
+     * Collection elements.
20
+     *
21
+     * @var array
22
+     */
23
+    protected $elements = array();
24
+
25
+    /**
26
+     * Collection type to enforce.
27
+     *
28
+     * @var Type
29
+     */
30
+    private $type;
31
+
32
+    /**
33
+     * Where Collection is in loop.
34
+     *
35
+     * @var int
36
+     */
37
+    protected $position = 0;
38
+
39
+    /**
40
+     * Collection constructor.
41
+     *
42
+     * @param string $type
43
+     * @param array  $elements
44
+     */
45
+    public function __construct( $type, array $elements = array() ) {
46
+        $this->type = new Type( $type );
47
+
48
+        if ( $elements ) {
49
+            $this->type->validate_elements( $elements );
50
+        }
51
+
52
+        $this->elements = $elements;
53
+    }
54
+
55
+    /**
56
+     * {@inheritdoc}
57
+     *
58
+     * @return string
59
+     */
60
+    public function get_type() {
61
+        return $this->type->get_type();
62
+    }
63
+
64
+    /**
65
+     * {@inheritdoc}
66
+     *
67
+     * @param mixed $element
68
+     *
69
+     * @return Collection
70
+     *
71
+     * @throws InvalidArgumentException
72
+     */
73
+    public function add( $element ) {
74
+        if ( $this->type->is_model() && is_array( $element ) ) {
75
+            $element = $this->type->create_model( $element );
76
+        }
77
+
78
+        $this->type->validate_element( $element );
79
+
80
+        $elements   = $this->elements;
81
+        $elements[] = $element;
82
+
83
+        $collection = new static( $this->get_type() );
84
+        $collection->set_from_trusted( $elements );
85
+
86
+        return $collection;
87
+    }
88
+
89
+    /**
90
+     * {@inheritdoc}
91
+     *
92
+     * @return Collection
93
+     */
94
+    public function clear() {
95
+        return new static( $this->get_type() );
96
+    }
97
+
98
+    /**
99
+     * {@inheritdoc}
100
+     *
101
+     * @param  callable $condition Condition to satisfy.
102
+     *
103
+     * @return bool
104
+     */
105
+    public function contains( callable $condition ) {
106
+        return (bool) $this->find( $condition );
107
+    }
108
+
109
+    /**
110
+     * {@inheritdoc}
111
+     *
112
+     * @param  callable $condition Condition to satisfy.
113
+     *
114
+     * @return mixed
115
+     */
116
+    public function find( callable $condition ) {
117
+        $index = $this->find_index( $condition );
118
+
119
+        return -1 === $index ? false : $this->elements[ $index ];
120
+    }
121
+
122
+    /**
123
+     * {@inheritdoc}
124
+     *
125
+     * @param  callable $condition Condition to satisfy.
126
+     *
127
+     * @return int
128
+     */
129
+    public function find_index( callable $condition ) {
130
+        $index = -1;
131
+
132
+        for ( $i = 0, $count = count( $this->elements ); $i < $count; $i++ ) {
133
+            if ( call_user_func( $condition, ($this->at( $i ) ) ) ) {
134
+                $index = $i;
135
+                break;
136
+            }
137
+        }
138
+
139
+        return $index;
140
+    }
141
+
142
+    /**
143
+     * Fetches the element at the provided index.
144
+     *
145
+     * @param int $index Index to get element from.
146
+     *
147
+     * @return mixed
148
+     *
149
+     * @throws OutOfRangeException
150
+     */
151
+    public function at( $index ) {
152
+        $this->validate_index( $index );
153
+
154
+        return $this->elements[ $index ];
155
+    }
156
+
157
+    /**
158
+     * {@inheritdoc}
159
+     *
160
+     * @param  int $index Index to check for existence.
161
+     *
162
+     * @return bool
163
+     *
164
+     * @throws InvalidArgumentException
165
+     */
166
+    public function index_exists( $index ) {
167
+        if ( ! is_int( $index ) ) {
168
+            throw new InvalidArgumentException( 'Index must be an integer' );
169
+        }
170
+
171
+        if ( $index < 0 ) {
172
+            throw new InvalidArgumentException( 'Index must be a non-negative integer' );
173
+        }
174
+
175
+        return $index < $this->count();
176
+    }
177
+
178
+    /**
179
+     * {@inheritdoc}
180
+     *
181
+     * @param  callable $condition Condition to satisfy.
182
+     *
183
+     * @return mixed
184
+     */
185
+    public function filter( callable $condition ) {
186
+        $elements = array();
187
+
188
+        foreach ( $this->elements as $element ) {
189
+            if ( call_user_func( $condition, $element ) ) {
190
+                $elements[] = $element;
191
+            }
192
+        }
193
+
194
+        return $this->new_from_trusted( $elements );
195
+    }
196
+    /**
197
+     * {@inheritdoc}
198
+     *
199
+     * @param  callable $condition Condition to satisfy.
200
+     *
201
+     * @return mixed
202
+     */
203
+    public function find_last( callable $condition ) {
204
+        $index = $this->find_last_index( $condition );
205
+
206
+        return -1 === $index ? null : $this->elements[ $index ];
207
+    }
208
+
209
+    /**
210
+     * {@inheritdoc}
211
+     *
212
+     * @param  callable $condition
213
+     * @return int
214
+     */
215
+    public function find_last_index( callable $condition ) {
216
+        $index = -1;
217
+
218
+        for ( $i = count( $this->elements ) - 1; $i >= 0; $i-- ) {
219
+            if ( call_user_func( $condition, $this->elements[ $i ] ) ) {
220
+                $index = $i;
221
+                break;
222
+            }
223
+        }
224
+
225
+        return $index;
226
+    }
227
+
228
+    /**
229
+     * {@inheritdoc}
230
+     *
231
+     * @param  int $start Begining index to slice from.
232
+     * @param  int $end   End index to slice to.
233
+     *
234
+     * @return Collection
235
+     *
236
+     * @throws InvalidArgumentException
237
+     */
238
+    public function slice( $start, $end ) {
239
+        if ( $start < 0 || ! is_int( $start ) ) {
240
+            throw new InvalidArgumentException( 'Start must be a non-negative integer' );
241
+        }
242
+
243
+        if ( $end < 0 || ! is_int( $end ) ) {
244
+            throw new InvalidArgumentException( 'End must be a positive integer' );
245
+        }
246
+
247
+        if ( $start > $end ) {
248
+            throw new InvalidArgumentException( 'End must be greater than start' );
249
+        }
250
+
251
+        if ( $end > $this->count() + 1 ) {
252
+            throw new InvalidArgumentException( 'End must be less than the count of the items in the Collection' );
253
+        }
254
+
255
+        $length = $end - $start + 1;
256
+        $subset = array_slice( $this->elements, $start, $length );
257
+
258
+        $collection = new static($this->type);
259
+        $collection->set_from_trusted( $subset );
260
+
261
+        return $collection;
262
+    }
263
+
264
+    /**
265
+     * {@inheritdoc}
266
+     *
267
+     * @param int   $index     Index to start at.
268
+     * @param mixed $element Element to insert.
269
+     *
270
+     * @return Collection
271
+     *
272
+     * @throws InvalidArgumentException
273
+     * @throws OutOfRangeException
274
+     */
275
+    public function insert( $index, $element ) {
276
+        $this->validate_index( $index );
277
+        $this->type->validate_element( $element );
278
+
279
+        $a = array_slice( $this->elements, 0, $index );
280
+        $b = array_slice( $this->elements, $index, count( $this->elements ) );
281
+
282
+        $a[] = $element;
283
+
284
+        return $this->new_from_trusted( array_merge( $a, $b ) );
285
+    }
286
+
287
+    /**
288
+     * {@inheritdoc}
289
+     *
290
+     * @param int   $index    Index to start insertion at.
291
+     * @param array $elements Elements in insert.
292
+     *
293
+     * @return Collection
294
+     *
295
+     * @throws OutOfRangeException
296
+     */
297
+    public function insert_range( $index, array $elements ) {
298
+        $this->validate_index( $index );
299
+        $this->type->validate_elements( $elements );
300
+
301
+        // To work with negative index, get the positive relation to 0 index
302
+        $index < 0 && $index = $this->count() + $index + 1;
303
+
304
+        $partA = array_slice( $this->elements, 0, $index );
305
+        $partB = array_slice( $this->elements, $index, count( $this->elements ) );
306
+
307
+        $elements1 = array_merge( $partA, $elements );
308
+        $elements1 = array_merge( $elements1, $partB );
309
+
310
+        $col = new static( $this->type );
311
+        $col->set_from_trusted( $elements1 );
312
+
313
+        return $col;
314
+    }
315
+
316
+    /**
317
+     * {@inheritdoc}
318
+     *
319
+     * @param  callable $condition Condition to satisfy.
320
+     *
321
+     * @return Collection
322
+     */
323
+    public function without( callable $condition ) {
324
+        $inverse = function ( $element ) use ( $condition ) {
325
+            return ! call_user_func( $condition, $element );
326
+        };
327
+
328
+        return $this->filter( $inverse );
329
+    }
330
+
331
+    /**
332
+     * {@inheritdoc}
333
+     *
334
+     * @param  int $index Index to remove.
335
+     *
336
+     * @return Collection
337
+     *
338
+     * @throws OutOfRangeException
339
+     */
340
+    public function remove_at( $index ) {
341
+        $this->validate_index( $index );
342
+
343
+        $elements = $this->elements;
344
+
345
+        return $this->new_from_trusted(
346
+            array_merge(
347
+                array_slice( $elements, 0, $index ),
348
+                array_slice( $elements, $index + 1, count( $elements ) )
349
+            )
350
+        );
351
+    }
352
+    /**
353
+     * {@inheritdoc}
354
+     *
355
+     * @return Collection
356
+     */
357
+    public function reverse() {
358
+        return $this->new_from_trusted(
359
+            array_reverse( $this->elements )
360
+        );
361
+    }
362
+
363
+    /**
364
+     * {@inheritdoc}
365
+     *
366
+     * @param callable $callback Sort callback.
367
+     *
368
+     * @return Collection
369
+     */
370
+    public function sort( callable $callback ) {
371
+        $elements = $this->elements;
372
+        usort( $elements, $callback );
373
+        return $this->new_from_trusted( $elements );
374
+    }
375
+
376
+    /**
377
+     * {@inheritdoc}
378
+     *
379
+     * @return array
380
+     */
381
+    public function to_array() {
382
+        return $this->elements;
383
+    }
384
+
385
+    /**
386
+     * {@inheritdoc}
387
+     *
388
+     * @param callable $callable Reducer function.
389
+     *
390
+     * @param null     $initial  Initial reducer value.
391
+     *
392
+     * @return mixed
393
+     */
394
+    public function reduce( callable $callable, $initial = null ) {
395
+        return array_reduce( $this->elements, $callable, $initial );
396
+    }
397
+
398
+    /**
399
+     * {@inheritdoc}
400
+     *
401
+     * @param callable $condition Condition callback.
402
+     *
403
+     * @return bool
404
+     */
405
+    public function every( callable $condition ) {
406
+        $response = true;
407
+
408
+        foreach ( $this->elements as $element ) {
409
+            $result = call_user_func( $condition, $element );
410
+
411
+            if ( false === $result ) {
412
+                $response = false;
413
+                break;
414
+            }
415
+        }
416
+
417
+        return $response;
418
+    }
419
+
420
+    /**
421
+     * {@inheritdoc}
422
+     *
423
+     * @param  int $num Number of elements to drop.
424
+     *
425
+     * @return Collection
426
+     *
427
+     * @throws InvalidArgumentException
428
+     */
429
+    public function drop( $num ) {
430
+        return $this->slice( $num, $this->count() );
431
+    }
432
+
433
+    /**
434
+     * {@inheritdoc}
435
+     *
436
+     * @param int $num Number of elements to drop.
437
+     *
438
+     * @return Collection
439
+     *
440
+     * @throws InvalidArgumentException
441
+     */
442
+    public function drop_right( $num ) {
443
+        return $num !== $this->count()
444
+            ? $this->slice( 0, $this->count() - $num - 1 )
445
+            : $this->clear();
446
+    }
447
+
448
+    /**
449
+     * {@inheritdoc}
450
+     *
451
+     * @param callable $condition Condition callback.
452
+     *
453
+     * @return Collection
454
+     */
455
+    public function drop_while( callable $condition ) {
456
+        $count = $this->count_while_true( $condition );
457
+        return $count ? $this->drop( $count ) : $this;
458
+    }
459
+    /**
460
+     * {@inheritdoc}
461
+     *
462
+     * @return Collection
463
+     *
464
+     * @throws InvalidArgumentException
465
+     */
466
+    public function tail() {
467
+        return $this->slice( 1, $this->count() );
468
+    }
469
+
470
+    /**
471
+     * {@inheritdoc}
472
+     *
473
+     * @param  int $num Number of elements to take.
474
+     *
475
+     * @return Collection
476
+     *
477
+     * @throws InvalidArgumentException
478
+     */
479
+    public function take( $num ) {
480
+        return $this->slice( 0, $num - 1 );
481
+    }
482
+
483
+    /**
484
+     * {@inheritdoc}
485
+     *
486
+     * @param int $num Number of elements to take.
487
+     *
488
+     * @return Collection
489
+     *
490
+     * @throws InvalidArgumentException
491
+     */
492
+    public function take_right( $num ) {
493
+        return $this->slice( $this->count() - $num, $this->count() );
494
+    }
495
+
496
+    /**
497
+     * {@inheritdoc}
498
+     *
499
+     * @param callable $condition Callback function.
500
+     *
501
+     * @return Collection
502
+     */
503
+    public function take_while( callable $condition ) {
504
+        $count = $this->count_while_true( $condition );
505
+
506
+        return $count ? $this->take( $count ) : $this->clear();
507
+    }
508
+
509
+    /**
510
+     * {@inheritdoc}
511
+     *
512
+     * @param callable $callable Callback function.
513
+     */
514
+    public function each( callable $callable ) {
515
+        foreach ( $this->elements as $element ) {
516
+            call_user_func( $callable, $element );
517
+        }
518
+    }
519
+
520
+    /**
521
+     * {@inheritdoc}
522
+     *
523
+     * @param callable $callable Callback function.
524
+     *
525
+     * @return Collection
526
+     */
527
+    public function map( callable $callable ) {
528
+        $elements = array();
529
+        $type = null;
530
+        foreach ( $this->elements as $element ) {
531
+            $result = call_user_func( $callable, $element );
532
+
533
+            if ( null === $type ) {
534
+                $type = gettype( $result );
535
+
536
+                if ( 'object' === $type ) {
537
+                    $type = get_class( $result );
538
+                }
539
+            }
540
+
541
+            $elements[] = $result;
542
+        }
543
+
544
+        return $this->new_from_trusted( $elements, $type ? : $this->get_type() );
545
+    }
546
+
547
+    /**
548
+     * {@inheritdoc}
549
+     *
550
+     * @param callable $callable Reducer function.
551
+     * @param null     $initial  Initial value.
552
+     *
553
+     * @return mixed
554
+     */
555
+    public function reduce_right( callable $callable, $initial = null ) {
556
+        return array_reduce(
557
+            array_reverse( $this->elements ),
558
+            $callable,
559
+            $initial
560
+        );
561
+    }
562
+
563
+    /**
564
+     * {@inheritdoc}
565
+     *
566
+     * @return Collection
567
+     */
568
+    public function shuffle() {
569
+        $elements = $this->elements;
570
+        shuffle( $elements );
571
+
572
+        return $this->new_from_trusted( $elements );
573
+    }
574
+
575
+    /**
576
+     * {@inheritdoc}
577
+     *
578
+     * @param array|Collection $elements Array of elements to merge.
579
+     *
580
+     * @return Collection
581
+     *
582
+     * @throws InvalidArgumentException
583
+     */
584
+    public function merge( $elements ) {
585
+        if ( $elements instanceof static ) {
586
+            $elements = $elements->to_array();
587
+        }
588
+
589
+        if ( ! is_array( $elements ) ) {
590
+            throw new InvalidArgumentException( 'Merge must be given array or Collection' );
591
+        }
592
+
593
+        $this->type->validate_elements( $elements );
594
+
595
+        return $this->new_from_trusted(
596
+            array_merge( $this->elements, $elements )
597
+        );
598
+    }
599
+
600
+    /**
601
+     * {@inheritdoc}
602
+     *
603
+     * @return mixed
604
+     *
605
+     * @throws OutOfBoundsException
606
+     */
607
+    public function first() {
608
+        if ( empty( $this->elements ) ) {
609
+            throw new OutOfBoundsException( 'Cannot get first element of empty Collection' );
610
+        }
611
+
612
+        return reset( $this->elements );
613
+    }
614
+
615
+    /**
616
+     * {@inheritdoc}
617
+     *
618
+     * @return mixed
619
+     *
620
+     * @throws OutOfBoundsException
621
+     */
622
+    public function last() {
623
+        if ( empty( $this->elements ) ) {
624
+            throw new OutOfBoundsException( 'Cannot get last element of empty Collection' );
625
+        }
626
+
627
+        return end( $this->elements );
628
+    }
629
+
630
+    /**
631
+     * {@inheritdoc}
632
+     *
633
+     * @return int
634
+     */
635
+    public function count() {
636
+        return count( $this->elements );
637
+    }
638
+
639
+    /**
640
+     * {@inheritDoc}
641
+     *
642
+     * @return array
643
+     */
644
+    public function serialize() {
645
+        return $this->map(function( $element ) {
646
+            if ( $element instanceof Serializes ) {
647
+                return $element->serialize();
648
+            }
649
+
650
+            return $element;
651
+        } )->to_array();
652
+    }
653
+
654
+    /**
655
+     * Return the current element.
656
+     *
657
+     * @return mixed
658
+     */
659
+    public function current() {
660
+        return $this->at( $this->position );
661
+    }
662
+
663
+    /**
664
+     * Move forward to next element.
665
+     */
666
+    public function next() {
667
+        $this->position ++;
668
+    }
669
+
670
+    /**
671
+     * Return the key of the current element.
672
+     *
673
+     * @return mixed
674
+     */
675
+    public function key() {
676
+        return $this->position;
677
+    }
678
+
679
+    /**
680
+     * Checks if current position is valid.
681
+     *
682
+     * @return bool
683
+     */
684
+    public function valid() {
685
+        return isset( $this->elements[ $this->position ] );
686
+    }
687
+
688
+    /**
689
+     * Rewind the Iterator to the first element.
690
+     */
691
+    public function rewind() {
692
+        $this->position = 0;
693
+    }
694
+
695
+    /**
696
+     * Creates a new instance of the Collection
697
+     * from a trusted set of elements.
698
+     *
699
+     * @param array      $elements Array of elements to pass into new collection.
700
+     * @param null|mixed $type
701
+     *
702
+     * @return static
703
+     */
704
+    protected function new_from_trusted( array $elements, $type = null ) {
705
+        $collection = new static( null !== $type ? $type : $this->get_type() );
706
+        $collection->set_from_trusted( $elements );
707
+
708
+        return $collection;
709
+    }
710
+
711
+    /**
712
+     * Sets the elements without validating them.
713
+     *
714
+     * @param array $elements Pre-validated elements to set.
715
+     */
716
+    protected function set_from_trusted( array $elements ) {
717
+        $this->elements = $elements;
718
+    }
719
+
720
+    /**
721
+     * Number of elements true for the condition.
722
+     *
723
+     * @param callable $condition Condition to check.
724
+     * @return int
725
+     */
726
+    protected function count_while_true( callable $condition ) {
727
+        $count = 0;
728
+
729
+        foreach ( $this->elements as $element ) {
730
+            if ( ! $condition($element) ) {
731
+                break;
732
+            }
733
+            $count++;
734
+        }
735
+
736
+        return $count;
737
+    }
738
+
739
+    /**
740
+     * Validates a number to be used as an index.
741
+     *
742
+     * @param  integer $index The number to be validated as an index.
743
+     *
744
+     * @throws OutOfRangeException
745
+     */
746
+    protected function validate_index( $index ) {
747
+        $exists = $this->index_exists( $index );
748
+
749
+        if ( ! $exists ) {
750
+            throw new OutOfRangeException( 'Index out of bounds of collection' );
751
+        }
752
+    }
753 753
 }
Please login to merge, or discard this patch.