Paginator::loadedMaxResults()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
rs 9.4286
cc 2
eloc 4
nc 2
nop 0
1
<?php
2
/**
3
 * Paginator.php
4
 *
5
 * @copyright	More in license.md
6
 * @license		http://www.ipublikuj.eu
7
 * @author		Adam Kadlec http://www.ipublikuj.eu
8
 * @package		iPublikuj:500px!
9
 * @subpackage	common
10
 * @since		5.0
11
 *
12
 * @date		07.03.15
13
 */
14
15
namespace IPub\FiveHundredPixel;
16
17
use Nette;
18
19
use IPub;
20
21
/**
22
 * Response paginator
23
 *
24
 * @package		iPublikuj:500px!
25
 * @subpackage	common
26
 *
27
 * @author Adam Kadlec <[email protected]>
28
 * @author Filip Procházka <[email protected]>
29
 */
30
class Paginator extends Nette\Object implements \Iterator
31
{
32
	const PER_PAGE_MAX = 100;
33
34
	/**
35
	 * @var ApiCall
36
	 */
37
	private $client;
38
39
	/**
40
	 * @var IPub\OAuth\HttpClient
41
	 */
42
	private $httpClient;
43
44
	/**
45
	 * @var int
46
	 */
47
	private $firstPage;
48
49
	/**
50
	 * @var int
51
	 */
52
	private $perPage;
53
54
	/**
55
	 * @var int|NULL
56
	 */
57
	private $maxResults;
58
59
	/**
60
	 * @var array
61
	 */
62
	private $resources = [];
63
64
	/**
65
	 * @var IPub\OAuth\Api\Response[]
66
	 */
67
	private $responses = [];
68
69
	/**
70
	 * @var int
71
	 */
72
	private $itemCursor;
73
74
	/**
75
	 * @var int
76
	 */
77
	private $pageCursor;
78
79
	/**
80
	 * @param ApiCall $client
81
	 * @param IPub\OAuth\Api\Response $response
82
	 */
83
	public function __construct(ApiCall $client, IPub\OAuth\Api\Response $response)
84
	{
85
		$this->client = $client;
86
87
		$this->httpClient = $client->getHttpClient();
88
		$resource = $response->toArray();
89
		$resource = $this->findCollection(current($resource));
90
91
		$params = $response->request->getParameters();
92
		$this->firstPage = isset($params['page']) ? (int) max($params['page'], 1) : 1;
93
		$this->perPage = isset($params['per_page']) ? (int) $params['per_page'] : count($resource);
94
95
		$this->responses[$this->firstPage] = $response;
96
		$this->resources[$this->firstPage] = $resource;
97
	}
98
99
	/**
100
	 * If you setup maximum number of results, the pagination will stop after fetching the desired number.
101
	 * If you have per_page=50 and wan't to fetch 200 results, it will make 4 requests in total.
102
	 *
103
	 * @param int $maxResults
104
	 *
105
	 * @return $this
106
	 */
107
	public function limitResults($maxResults)
108
	{
109
		$this->maxResults = (int)$maxResults;
110
111
		return $this;
112
	}
113
114
	public function rewind()
115
	{
116
		$this->itemCursor = 0;
117
		$this->pageCursor = $this->firstPage;
118
	}
119
120
	public function valid()
121
	{
122
		return isset($this->resources[$this->pageCursor][$this->itemCursor])
123
			&& ! $this->loadedMaxResults();
124
	}
125
126
	/**
127
	 * @return bool
128
	 */
129
	public function loadedMaxResults()
130
	{
131
		if ($this->maxResults === NULL) {
132
			return FALSE;
133
		}
134
135
		return $this->maxResults <= ($this->itemCursor + ($this->pageCursor - $this->firstPage) * $this->perPage);
136
	}
137
138
	public function current()
139
	{
140
		if (!$this->valid()) {
141
			return NULL;
142
		}
143
144
		return Nette\Utils\ArrayHash::from($this->resources[$this->pageCursor][$this->itemCursor]);
145
	}
146
147
	public function next()
148
	{
149
		$this->itemCursor++;
150
151
		// if cursor points at result of next page, try to load it
152
		if ($this->itemCursor < $this->perPage || $this->itemCursor % $this->perPage !== 0) {
153
			return;
154
		}
155
156
		if (isset($this->resources[$this->pageCursor + 1])) { // already loaded
157
			$this->itemCursor = 0;
158
			$this->pageCursor++;
159
160
			return;
161
		}
162
163
		if ($this->loadedMaxResults()) {
164
			return;
165
		}
166
167
		try {
168
			$prevRequest = $this->responses[$this->pageCursor]->getRequest();
169
170
			$params = $this->responses[$this->pageCursor]->request->getParameters();
171
			$params['page'] = isset($params['page']) ? (int) max($params['page'], 1) + 1 : 1;
172
173
			$response = $this->httpClient->makeRequest(
174
				$prevRequest->copyWithUrl($this->client->getConfig()->createUrl('api', 'rest', $params)),
175
				'HMAC-SHA1'
176
			);
177
178
			$resource = $response->toArray();
179
			$resource = $this->findCollection(current($resource));
180
181
			$this->itemCursor = 0;
182
			$this->pageCursor++;
183
			$this->responses[$this->pageCursor] = $response;
184
			$this->resources[$this->pageCursor] = $resource;
185
186
		} catch (\Exception $e) {
187
			$this->itemCursor--; // revert back so the user can continue if needed
188
		}
189
	}
190
191
	public function key()
192
	{
193
		return $this->itemCursor + ($this->pageCursor - 1) * $this->perPage;
194
	}
195
196
	/**
197
	 * @param array $response
198
	 *
199
	 * @return array
200
	 */
201
	private function findCollection(array $response)
202
	{
203
		foreach($response as $item) {
204
			if (is_array($item)) {
205
				return $item;
206
			}
207
		}
208
	}
209
}