Collection   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 187
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
wmc 14
lcom 1
cbo 2
dl 0
loc 187
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A count() 0 8 2
A rewind() 0 8 1
A __construct() 0 10 2
A key() 0 9 2
A valid() 0 8 2
A next() 0 19 3
A current() 0 15 2
1
<?php
2
3
namespace Chadicus\Marvel\Api;
4
5
use DominionEnterprises\Util;
6
7
/**
8
 * Class for iterating index response to the Marvel API. Collections are readonly.
9
 */
10
class Collection implements \Iterator, \Countable
11
{
12
    /**
13
     * API Client.
14
     *
15
     * @var Client
16
     */
17
    private $client;
18
19
    /**
20
     * Limit to give to API.
21
     *
22
     * @var integer
23
     */
24
    private $limit;
25
26
    /**
27
     * Offset to give to API.
28
     *
29
     * @var integer
30
     */
31
    private $offset;
32
33
    /**
34
     * Resource name for collection.
35
     *
36
     * @var string
37
     */
38
    private $resource;
39
40
    /**
41
     * Array of filters to pass to API.
42
     *
43
     * @var array
44
     */
45
    private $filters;
46
47
    /**
48
     * Total number of elements in the collection.
49
     *
50
     * @var integer
51
     */
52
    private $total;
53
54
    /**
55
     * Pointer in the paginated results.
56
     *
57
     * @var integer
58
     */
59
    private $position;
60
61
    /**
62
     * A paginated set of elements from the API.
63
     *
64
     * @var null|array
65
     */
66
    private $results;
67
68
    /**
69
     * A custom callable to return a defined type when iterating over the collection.
70
     *
71
     * @var callable
72
     */
73
    private $loader;
74
75
    /**
76
     * Create a new collection.
77
     *
78
     * @param Client   $client   A client connection to the API.
79
     * @param string   $resource The name of API resource to request.
80
     * @param array    $filters  A key value pair array of search filters.
81
     * @param callable $loader   A custom callable to use when iterating over the collection.
82
     */
83
    final public function __construct(Client $client, string $resource, array $filters = [], callable $loader = null)
84
    {
85
        $this->client = $client;
86
        $this->resource = $resource;
87
        $this->filters = $filters;
88
        $this->loader = $loader ?: function ($input) {
89
            return $input;
90
        };
91
        $this->rewind();
92
    }
93
94
    /**
95
     * Return the count elements in this collection, @see Countable::count().
96
     *
97
     * @return integer
98
     */
99
    final public function count()
100
    {
101
        if ($this->position === -1) {
102
            $this->next();
103
        }
104
105
        return $this->total;
106
    }
107
108
    /**
109
     * Rewind the Iterator to the first element, @see Iterator::rewind().
110
     *
111
     * @return void
112
     */
113
    final public function rewind()
114
    {
115
        $this->results = null;
116
        $this->offset = 0;
117
        $this->total = 0;
118
        $this->limit = 0;
119
        $this->position = -1;
120
    }
121
122
    /**
123
     * Return the key of the current element, @see Iterator::key().
124
     *
125
     * @return integer
126
     */
127
    final public function key()
128
    {
129
        if ($this->position === -1) {
130
            $this->next();
131
        }
132
133
        Util::ensure(false, empty($this->results), '\OutOfBoundsException', ['Collection contains no elements']);
134
        return $this->offset + $this->position;
135
    }
136
137
    /**
138
     * Checks if current position is valid, @see Iterator::valid().
139
     *
140
     * @return boolean
141
     */
142
    final public function valid()
143
    {
144
        if ($this->position === -1) {
145
            $this->next();
146
        }
147
148
        return $this->offset + $this->position < $this->total;
149
    }
150
151
    /**
152
     * Move forward to next element, @see Iterator::next().
153
     *
154
     * @return void
155
     */
156
    final public function next()
157
    {
158
        ++$this->position;
159
160
        if ($this->position < $this->limit) {
161
            return;
162
        }
163
164
        $this->offset += $this->limit;
165
        $this->filters['offset'] = $this->offset;
166
        $this->filters['limit'] = $this->limit === 0 ? 20 : $this->limit;
167
        $dataWrapper = $this->client->search($this->resource, $this->filters);
168
169
        //Limit should be the total number returned, not the specified limit in the query params
170
        $this->limit = $dataWrapper->getData()->getCount();
171
        $this->total = $dataWrapper->getData()->getTotal();
172
        $this->results = $dataWrapper->getData()->getResults();
173
        $this->position = 0;
174
    }
175
176
    /**
177
     * Return the current element, @see Iterator::current().
178
     *
179
     * @return mixed Returns the element in the results array or a custom type defined by $loader.
180
     */
181
    final public function current()
182
    {
183
        if ($this->position === -1) {
184
            $this->next();
185
        }
186
187
        Util::ensure(
188
            true,
189
            array_key_exists($this->position, $this->results),
190
            '\OutOfBoundsException',
191
            ['Collection contains no element at current position']
192
        );
193
194
        return call_user_func_array($this->loader, [$this->results[$this->position]]);
195
    }
196
}
197