Completed
Push — master ( 95e445...ca4763 )
by Joschi
03:42 queued 01:06
created

ItemList::offsetGet()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
/**
4
 * micrometa
5
 *
6
 * @category   Jkphl
7
 * @package    Jkphl\Micrometa
8
 * @subpackage Jkphl\Micrometa\Ports\Item
9
 * @author     Joschi Kuphal <[email protected]> / @jkphl
10
 * @copyright  Copyright © 2018 Joschi Kuphal <[email protected]> / @jkphl
11
 * @license    http://opensource.org/licenses/MIT The MIT License (MIT)
12
 */
13
14
/***********************************************************************************
15
 *  The MIT License (MIT)
16
 *
17
 *  Copyright © 2018 Joschi Kuphal <[email protected]> / @jkphl
18
 *
19
 *  Permission is hereby granted, free of charge, to any person obtaining a copy of
20
 *  this software and associated documentation files (the "Software"), to deal in
21
 *  the Software without restriction, including without limitation the rights to
22
 *  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
23
 *  the Software, and to permit persons to whom the Software is furnished to do so,
24
 *  subject to the following conditions:
25
 *
26
 *  The above copyright notice and this permission notice shall be included in all
27
 *  copies or substantial portions of the Software.
28
 *
29
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
31
 *  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
32
 *  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
33
 *  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34
 *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35
 ***********************************************************************************/
36
37
namespace Jkphl\Micrometa\Ports\Item;
38
39
use Jkphl\Micrometa\Ports\Exceptions\InvalidArgumentException;
40
use Jkphl\Micrometa\Ports\Exceptions\OutOfBoundsException;
41
use Jkphl\Micrometa\Ports\Exceptions\RuntimeException;
42
43
/**
44
 * Abstract item list
45
 *
46
 * @package    Jkphl\Micrometa
47
 * @subpackage Jkphl\Micrometa\Ports
48
 */
49
class ItemList implements ItemListInterface
50
{
51
    /**
52
     * Items
53
     *
54
     * @var ItemInterface[]
55
     */
56
    protected $items;
57
58
    /**
59
     * Internal pointer
60
     *
61
     * @var int
62
     */
63
    protected $pointer;
64
65
    /**
66
     * ItemList constructor
67
     *
68
     * @param ItemInterface[] $items Items
69
     *
70
     * @api
71
     */
72 16
    public function __construct(array $items = [])
73
    {
74 16
        $this->items   = array_values($items);
75 16
        $this->pointer = 0;
76 16
    }
77
78
    /**
79
     * Return the current item
80
     *
81
     * @return ItemInterface Item
82
     * @api
83
     */
84 2
    public function current()
85
    {
86 2
        return $this->items[$this->pointer];
87
    }
88
89
    /**
90
     * Move forward to next element
91
     *
92
     * @return void
93
     * @api
94
     */
95 2
    public function next()
96
    {
97 2
        ++$this->pointer;
98 2
    }
99
100
    /**
101
     * Return the position of the current element
102
     *
103
     * @return int Position of the current element
104
     * @api
105
     */
106 1
    public function key()
107
    {
108 1
        return $this->pointer;
109
    }
110
111
    /**
112
     * Checks if current position is valid
113
     *
114
     * @return boolean The current position is valid
115
     * @api
116
     */
117 2
    public function valid()
118
    {
119 2
        return isset($this->items[$this->pointer]);
120
    }
121
122
    /**
123
     * Rewind the item list to the first element
124
     *
125
     * @return void
126
     * @api
127
     */
128 2
    public function rewind()
129
    {
130 2
        $this->pointer = 0;
131 2
    }
132
133
    /**
134
     * Test if an offset exists
135
     *
136
     * @param int $offset Offset
137
     *
138
     * @return boolean Offset exists
139
     * @api
140
     */
141
    public function offsetExists($offset)
142
    {
143
        return isset($this->items[$offset]);
144
    }
145
146
    /**
147
     * Return the item at a particular offset
148
     *
149
     * @param int $offset Offset
150
     *
151
     * @return ItemInterface Item
152
     * @api
153
     */
154 3
    public function offsetGet($offset)
155
    {
156 3
        return $this->items[$offset];
157
    }
158
159
    /**
160
     * Set an item at a particular offset
161
     *
162
     * @param int $offset          Offset
163
     * @param ItemInterface $value Item
164
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
165
     *
166
     * @api
167
     */
168 1
    public function offsetSet($offset, $value)
169
    {
170 1
        throw new RuntimeException(RuntimeException::IMMUTABLE_ITEM_LIST_STR, RuntimeException::IMMUTABLE_ITEM_LIST);
171
    }
172
173
    /**
174
     * Delete an item at a particular offset
175
     *
176
     * @param int $offset Offset
177
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
178
     */
179 1
    public function offsetUnset($offset)
180
    {
181 1
        throw new RuntimeException(RuntimeException::IMMUTABLE_ITEM_LIST_STR, RuntimeException::IMMUTABLE_ITEM_LIST);
182
    }
183
184
    /**
185
     * Return an object representation of the item list
186
     *
187
     * @return \stdClass Micro information items
188
     */
189 1
    public function toObject()
190
    {
191
        return (object)[
192 1
            'items' => array_map(
193
                function (ItemInterface $item) {
194 1
                    return $item->toObject();
195 1
                },
196 1
                $this->items
197
            )
198
        ];
199
    }
200
201
    /**
202
     * Return the first item, optionally of particular types
203
     *
204
     * @param array ...$types Item types
205
     *
206
     * @return ItemInterface Item
207
     * @throws OutOfBoundsException If there are no matching items
208
     * @api
209
     */
210 2
    public function getFirstItem(...$types)
211
    {
212 2
        $items = $this->getItems(...$types);
213
214
        // If there are no matching items
215 2
        if (!count($items)) {
216 1
            throw new OutOfBoundsException(
217 1
                OutOfBoundsException::NO_MATCHING_ITEMS_STR,
218 1
                OutOfBoundsException::NO_MATCHING_ITEMS
219
            );
220
        }
221
222 1
        return $items[0];
223
    }
224
225
    /**
226
     * Return all items as an array, optionally filtered by item type(s)
227
     *
228
     * @param array ...$types Item types
229
     *
230
     * @return ItemInterface[] Items matching the requested types
231
     * @api
232
     */
233 6
    public function getItems(...$types)
234
    {
235
        // If particular item types should be filtered
236 6
        if (count($types)) {
237 4
            return array_filter(
238 4
                $this->items,
239
                function (ItemInterface $item) use ($types) {
240 4
                    return $item->isOfType(...$types);
241 4
                }
242
            );
243
        }
244
245 4
        return $this->items;
246
    }
247
248
    /**
249
     * Return the number of items in this list
250
     *
251
     * @return int Number of items
252
     * @api
253
     */
254 2
    public function count()
255
    {
256 2
        return count($this->items);
257
    }
258
259
    /**
260
     * Generic item getter
261
     *
262
     * @param string $type     Item type
263
     * @param array $arguments Arguments
264
     *
265
     * @return ItemInterface Item
266
     * @throws InvalidArgumentException If the item index is invalid
267
     * @api
268
     */
269 2
    public function __call($type, $arguments)
270
    {
271 2
        $index = 0;
272 2
        if (count($arguments)) {
273
            // If the item index is invalid
274 2
            if (!is_int($arguments[0]) || ($arguments[0] < 0)) {
275 1
                throw new InvalidArgumentException(
276 1
                    sprintf(InvalidArgumentException::INVALID_ITEM_INDEX_STR, $arguments[0]),
277 1
                    InvalidArgumentException::INVALID_ITEM_INDEX
278
                );
279
            }
280
281 2
            $index = $arguments[0];
282
        }
283
284
        // Return the item by type and index
285 2
        return $this->getItemByTypeAndIndex($type, $index);
286
    }
287
288
    /**
289
     * Return an item by type and index
290
     *
291
     * @param string $type Item type
292
     * @param int $index   Item index
293
     *
294
     * @return ItemInterface Item
295
     * @throws OutOfBoundsException If the item index is out of bounds
296
     */
297 2
    protected function getItemByTypeAndIndex($type, $index)
298
    {
299 2
        $typeItems = $this->getItems($type);
300
301
        // If the item index is out of bounds
302 2
        if (count($typeItems) <= $index) {
303 1
            throw new OutOfBoundsException(
304 1
                sprintf(OutOfBoundsException::INVALID_ITEM_INDEX_STR, $index),
305 1
                OutOfBoundsException::INVALID_ITEM_INDEX
306
            );
307
        }
308
309 2
        return $typeItems[$index];
310
    }
311
}
312