Skip to content

Commit 86d58f6

Browse files
committed
Merge pull request #61 from Future500BV/resultpager
Add a ResultPager object to support pagination of all Api's
2 parents 8bedcf3 + 470b8ac commit 86d58f6

File tree

8 files changed

+627
-1
lines changed

8 files changed

+627
-1
lines changed

doc/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ APIs:
1818

1919
Additional features:
2020

21+
* [Pagination support](result_pager.md)
2122
* [Authentication & Security](security.md)
2223
* [Request any Route](request_any_route.md)
2324
* [Customize `php-github-api` and testing](customize.md)

doc/result_pager.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
## Result Pager
2+
[Back to the navigation](index.md)
3+
4+
### Usage examples
5+
6+
Get all repositories of a organization
7+
8+
```php
9+
$client = new Github\Client();
10+
11+
$organizationApi = $client->api('organization');
12+
13+
$paginator = new Github\ResultPager($client);
14+
$parameters = array('github');
15+
$result = $paginator->fetchAll($organizationApi, 'repositories', $parameters);
16+
```
17+
18+
Get the first page
19+
```php
20+
$client = new Github\Client();
21+
22+
$organizationApi = $client->api('organization');
23+
24+
$paginator = new Github\ResultPager( $client );
25+
$parameters = array('github');
26+
$result = $paginator->fetch($organizationApi, 'repositories', $parameters);
27+
```
28+
29+
Check for a next page:
30+
```php
31+
$paginator->hasNext();
32+
```
33+
34+
Get next page:
35+
```php
36+
$paginator->fetchNext();
37+
```
38+
39+
Check for pervious page:
40+
```php
41+
$paginator->hasPrevious();
42+
```
43+
44+
Get prevrious page:
45+
```php
46+
$paginator->fetchPrevious();
47+
```
48+
49+
If you want to retrieve the pagination links (available after the call to fetch):
50+
```php
51+
$paginator->getPagination();
52+
```

lib/Github/Api/AbstractApi.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ abstract class AbstractApi implements ApiInterface
1818
*/
1919
protected $client;
2020

21+
/**
22+
* number of items per page (GitHub pagination)
23+
*
24+
* @var null|int
25+
*/
26+
protected $perPage;
27+
2128
/**
2229
* @param Client $client
2330
*/
@@ -30,11 +37,32 @@ public function configure()
3037
{
3138
}
3239

40+
/**
41+
* @return null|int
42+
*/
43+
public function getPerPage()
44+
{
45+
return $this->perPage;
46+
}
47+
48+
/**
49+
* @param null|int $perPage
50+
*/
51+
public function setPerPage($perPage)
52+
{
53+
$this->perPage = (null === $perPage ? $perPage : (int) $perPage);
54+
55+
return $this;
56+
}
57+
3358
/**
3459
* {@inheritDoc}
3560
*/
3661
protected function get($path, array $parameters = array(), $requestHeaders = array())
3762
{
63+
if (null !== $this->perPage && !isset($parameters['per_page'])) {
64+
$parameters['per_page'] = $this->perPage;
65+
}
3866
$response = $this->client->getHttpClient()->get($path, $parameters, $requestHeaders);
3967

4068
return $response->getContent();

lib/Github/HttpClient/HttpClient.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,9 @@ public function put($path, array $parameters = array(), array $headers = array()
163163
*/
164164
public function request($path, array $parameters = array(), $httpMethod = 'GET', array $headers = array())
165165
{
166-
$path = trim($this->options['base_url'].$path, '/');
166+
if (!empty($this->options['base_url']) && 0 !== strpos($path, $this->options['base_url'])) {
167+
$path = trim($this->options['base_url'].$path, '/');
168+
}
167169

168170
$request = $this->createRequest($httpMethod, $path);
169171
$request->addHeaders($headers);

lib/Github/ResultPager.php

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
<?php
2+
3+
namespace Github;
4+
5+
use Github\Api\ApiInterface;
6+
use Github\Exception\InvalidArgumentException;
7+
use Github\HttpClient\HttpClient;
8+
use Github\HttpClient\HttpClientInterface;
9+
10+
/**
11+
* Pager class for supporting pagination in github classes
12+
*
13+
* @author Ramon de la Fuente <[email protected]>
14+
* @author Mitchel Verschoof <[email protected]>
15+
*/
16+
class ResultPager implements ResultPagerInterface
17+
{
18+
/**
19+
* @var Github\Client client
20+
*/
21+
protected $client;
22+
23+
/**
24+
* @var array pagination
25+
* Comes from pagination headers in Github API results
26+
*/
27+
protected $pagination;
28+
29+
30+
/**
31+
* The Github client to use for pagination. This must be the same
32+
* instance that you got the Api instance from, i.e.:
33+
*
34+
* $client = new \Github\Client();
35+
* $api = $client->api('someApi');
36+
* $pager = new \Github\ResultPager($client);
37+
*
38+
* @param \Github\Client $client
39+
*
40+
*/
41+
public function __construct(Client $client)
42+
{
43+
$this->client = $client;
44+
}
45+
46+
/**
47+
* {@inheritdoc}
48+
*/
49+
public function getPagination()
50+
{
51+
return $this->pagination;
52+
}
53+
54+
/**
55+
* {@inheritdoc}
56+
*/
57+
public function fetch(ApiInterface $api, $method, array $parameters = array())
58+
{
59+
$result = call_user_func_array(array($api, $method), $parameters);
60+
$this->postFetch();
61+
62+
return $result;
63+
}
64+
65+
/**
66+
* {@inheritdoc}
67+
*/
68+
public function fetchAll(ApiInterface $api, $method, array $parameters = array())
69+
{
70+
// get the perPage from the api
71+
$perPage = $api->getPerPage();
72+
73+
// Set parameters per_page to GitHub max to minimize number of requests
74+
$api->setPerPage(100);
75+
76+
$result = array();
77+
$result = call_user_func_array(array($api, $method), $parameters);
78+
$this->postFetch();
79+
80+
while ($this->hasNext()) {
81+
$result = array_merge($result, $this->fetchNext());
82+
}
83+
84+
// restore the perPage
85+
$api->setPerPage($perPage);
86+
87+
return $result;
88+
}
89+
90+
/**
91+
* {@inheritdoc}
92+
*/
93+
public function postFetch()
94+
{
95+
$this->pagination = $this->client->getHttpClient()->getLastResponse()->getPagination();
96+
}
97+
98+
/**
99+
* {@inheritdoc}
100+
*/
101+
public function hasNext()
102+
{
103+
return $this->has('next');
104+
}
105+
106+
/**
107+
* {@inheritdoc}
108+
*/
109+
public function fetchNext()
110+
{
111+
return $this->get('next');
112+
}
113+
114+
/**
115+
* {@inheritdoc}
116+
*/
117+
public function hasPrevious()
118+
{
119+
return $this->has('prev');
120+
}
121+
122+
/**
123+
* {@inheritdoc}
124+
*/
125+
public function fetchPrevious()
126+
{
127+
return $this->get('prev');
128+
}
129+
130+
/**
131+
* {@inheritdoc}
132+
*/
133+
public function fetchFirst()
134+
{
135+
return $this->get('first');
136+
}
137+
138+
/**
139+
* {@inheritdoc}
140+
*/
141+
public function fetchLast()
142+
{
143+
return $this->get('last');
144+
}
145+
146+
/**
147+
* {@inheritdoc}
148+
*/
149+
protected function has($key)
150+
{
151+
return !empty($this->pagination) && isset($this->pagination[$key]);
152+
}
153+
154+
/**
155+
* {@inheritdoc}
156+
*/
157+
protected function get($key)
158+
{
159+
if ($this->has($key)) {
160+
$result = $this->client->getHttpClient()->get($this->pagination[$key]);
161+
$this->postFetch();
162+
163+
return $result->getContent();
164+
}
165+
}
166+
}

lib/Github/ResultPagerInterface.php

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
namespace Github;
4+
5+
use Github\Api\ApiInterface;
6+
7+
/**
8+
* Pager interface
9+
*
10+
* @author Ramon de la Fuente <[email protected]>
11+
* @author Mitchel Verschoof <[email protected]>
12+
*/
13+
interface ResultPagerInterface
14+
{
15+
16+
/**
17+
* @return null|array pagination result of last request
18+
*/
19+
public function getPagination();
20+
21+
/**
22+
* Fetch a single result (page) from an api call
23+
*
24+
* @param ApiInterface $api the Api instance
25+
* @param string $method the method name to call on the Api instance
26+
* @param array $parameters the method parameters in an array
27+
*
28+
* @return array returns the result of the Api::$method() call
29+
*/
30+
public function fetch(ApiInterface $api, $method, array $parameters = array());
31+
32+
/**
33+
* Fetch all results (pages) from an api call
34+
* Use with care - there is no maximum
35+
*
36+
* @param ApiInterface $api the Api instance
37+
* @param string $method the method name to call on the Api instance
38+
* @param array $parameters the method parameters in an array
39+
*
40+
* @return array returns a merge of the results of the Api::$method() call
41+
*/
42+
public function fetchAll(ApiInterface $api, $method, array $parameters = array());
43+
44+
/**
45+
* Method that performs the actual work to refresh the pagination property
46+
*/
47+
public function postFetch();
48+
49+
/**
50+
* Check to determine the availability of a next page
51+
* @return bool
52+
*/
53+
public function hasNext();
54+
55+
/**
56+
* Check to determine the availability of a previous page
57+
* @return bool
58+
*/
59+
public function hasPrevious();
60+
61+
/**
62+
* Fetch the next page
63+
* @return array
64+
*/
65+
public function fetchNext();
66+
67+
/**
68+
* Fetch the previous page
69+
* @return array
70+
*/
71+
public function fetchPrevious();
72+
73+
/**
74+
* Fetch the first page
75+
* @return array
76+
*/
77+
public function fetchFirst();
78+
79+
/**
80+
* Fetch the last page
81+
* @return array
82+
*/
83+
public function fetchLast();
84+
}

0 commit comments

Comments
 (0)