BaseCollection::__clone()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 7
rs 9.4285
cc 2
eloc 5
nc 2
nop 0
1
<?php
2
3
  namespace Fiv\Collection;
4
5
  /**
6
   *
7
   * @package Fiv\Spl
8
   */
9
  class BaseCollection implements \Iterator, \ArrayAccess, \Countable {
10
11
    /**
12
     * @var int
13
     */
14
    protected $position = 0;
15
16
    /**
17
     * Array of objects
18
     *
19
     * @var array
20
     */
21
    protected $items = array();
22
23
    /**
24
     * @param array $items
25
     */
26
    public function __construct(array $items = array()) {
27
28
      if (!empty($items)) {
29
        $this->setItems($items);
30
      }
31
32
    }
33
34
    /**
35
     *
36
     */
37
    public function __clone() {
38
      $items = array();
39
      foreach ($this->items as $item) {
40
        $items[] = $item;
41
      }
42
      $this->setItems($items);
43
    }
44
45
    /**
46
     * Return number of items in this collection
47
     *
48
     * @return int
49
     */
50
    public function count() {
51
      return count($this->items);
52
    }
53
54
    /**
55
     * Add one item to begin of collection
56
     * This item is accessible via `$collection->getFirst();`
57
     *
58
     * @param $item
59
     * @return $this
60
     */
61
    public function prepend($item) {
62
      array_unshift($this->items, $item);
63
      return $this;
64
    }
65
66
    /**
67
     * Add one item to the end of collection
68
     * This item is accessible via `$collection->getLast();`
69
     *
70
     * @param $item
71
     * @return $this
72
     */
73
    public function append($item) {
74
      $this->items[] = $item;
75
      return $this;
76
    }
77
78
    /**
79
     * @param int $index
80
     * @param array $items
81
     * @return $this
82
     * @throws \InvalidArgumentException
83
     */
84
    public function addAfter($index, $items) {
85
      if (!is_array($items)) {
86
        throw new \InvalidArgumentException('You can add after only array of items');
87
      }
88
89
      $this->validateIndex($index);
90
91
      $offset = $index + 1;
92
      $firstPart = array_slice($this->items, 0, $offset);
93
      $secondPart = array_slice($this->items, $offset);
94
      $this->items = array_merge($firstPart, $items, $secondPart);
95
      return $this;
96
    }
97
98
    /**
99
     * Truncate current list of items and add new
100
     *
101
     * @param array $items
102
     * @return $this
103
     */
104
    public function setItems($items) {
105
106
      if (!is_array($items)) {
107
        throw new \InvalidArgumentException('You can set only array of items');
108
      }
109
110
      $this->items = $items;
111
      $this->rewind();
112
      return $this;
113
    }
114
115
    /**
116
     * Remove part of items from collection
117
     * Works as array_slice
118
     *
119
     *
120
     * @param $offset
121
     * @param null $length
122
     * @return $this
123
     */
124
    public function slice($offset, $length = null) {
125
      $this->items = array_slice($this->items, $offset, $length);
126
      return $this;
127
    }
128
129
    /**
130
     * Take part of items and return new collection
131
     * Works as array_slice
132
     * At this point items in 2 collection is same
133
     *
134
     * @param int $offset
135
     * @param null $length
136
     * @return self
137
     */
138
    public function extractItems($offset, $length = null) {
139
      $items = array_slice($this->items, $offset, $length);
140
      $className = get_called_class();
141
      $collection = new $className();
142
      /** @var BaseCollection $collection */
143
      $collection->setItems($items);
144
      return $collection;
145
    }
146
147
    /**
148
     * Rewind current collection
149
     */
150
    public function rewind() {
151
      $this->position = 0;
152
      $this->items = array_values($this->items);
153
    }
154
155
    /**
156
     * Return last item from collection
157
     *
158
     * @return mixed
159
     */
160
    public function getLast() {
161
      return end($this->items);
162
    }
163
164
    /**
165
     * Return first item from collection
166
     * @return mixed
167
     */
168
    public function getFirst() {
169
      return reset($this->items);
170
    }
171
172
    /**
173
     * Return next item from current
174
     * Also can return item with position from current + $step
175
     *
176
     * @param int $step
177
     * @return mixed
178
     */
179
    public function getNext($step = 1) {
180
      $position = ($this->position + $step);
181
      return isset($this->items[$position]) ? $this->items[$position] : null;
182
    }
183
184
    /**
185
     * Return previous item
186
     * Also can return previous from current position + $step
187
     *
188
     * @param int $step
189
     * @return mixed
190
     */
191
    public function getPrevious($step = 1) {
192
      $position = ($this->position - $step);
193
      return isset($this->items[$position]) ? $this->items[$position] : null;
194
    }
195
    
196
    /**
197
     * Return current item in collection
198
     *
199
     * @return object
200
     */
201
    public function current() {
202
      return $this->items[$this->position];
203
    }
204
205
    /**
206
     * Return current position
207
     *
208
     * @return int
209
     */
210
    public function key() {
211
      return $this->position;
212
    }
213
214
    /**
215
     * Switch to next position
216
     */
217
    public function next() {
218
      ++$this->position;
219
    }
220
221
    /**
222
     * Check if item exist in current position
223
     *
224
     * @return bool
225
     */
226
    public function valid() {
227
      return isset($this->items[$this->position]);
228
    }
229
230
    /**
231
     * Add item to the end or modify item with given key
232
     *
233
     * @param int|null $offset
234
     * @param object $item
235
     * @return $this
236
     */
237
    public function offsetSet($offset, $item) {
238
239
      if (is_null($offset)) {
240
        $this->append($item);
241
      } else {
242
        $this->validateIndex($offset);
243
        $this->items[$offset] = $item;
244
      }
245
246
      return $this;
247
    }
248
249
    /**
250
     * Check if item with given offset exists
251
     *
252
     * @param mixed $offset
253
     * @return bool
254
     */
255
    public function offsetExists($offset) {
256
      return isset($this->items[$offset]);
257
    }
258
259
    /**
260
     * Remove item from collection
261
     *
262
     * @param int $offset
263
     */
264
    public function offsetUnset($offset) {
265
      unset($this->items[$offset]);
266
    }
267
268
    /**
269
     * Get item from collection
270
     *
271
     * @param int $offset
272
     * @return object
273
     */
274
    public function offsetGet($offset) {
275
      return isset($this->items[$offset]) ? $this->items[$offset] : null;
276
    }
277
278
    /**
279
     * Return array of items connected to this collection
280
     *
281
     * Rewrite this method in you class
282
     *
283
     * <code>
284
     * foreach($collection->getItems() as $item){
285
     *  echo get_class($item)."\n;
286
     * }
287
     * </code>
288
     * @return object[]
289
     */
290
    public function getItems() {
291
      return $this->items;
292
    }
293
294
    /**
295
     * Iterate over objects in collection
296
     *
297
     * <code>
298
     * $collection->map(function($item, $index, $collection){
299
     *    if ( $index > 0 ) {
300
     *      $item->remove();
301
     *    }
302
     * })
303
     * </code>
304
     *
305
     * @param callback $callback
306
     * @return $this
307
     * @throws \InvalidArgumentException
308
     */
309
    public function map($callback) {
310
311
      if (!is_callable($callback)) {
312
        throw new \InvalidArgumentException('Invalid callback function');
313
      }
314
315
      foreach ($this->getItems() as $index => $item) {
316
        call_user_func_array($callback, array($item, $index, $this));
317
      }
318
319
      $this->rewind();
320
321
      return $this;
322
    }
323
324
    /**
325
     * @param int $index
326
     */
327
    protected function validateIndex($index) {
328
      if (!is_int($index)) {
329
        throw new \InvalidArgumentException('Invalid type of index. Must be integer');
330
      }
331
    }
332
333
  }