-
-
Notifications
You must be signed in to change notification settings - Fork 598
Add a ResultPager object to support pagination of all Api's #61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
383346b
07138eb
3683986
bf81101
09e76f3
52ac68b
5783325
76c1b46
0cc862b
09b147d
336f50a
c94daa8
496bd03
84b76eb
5541dec
3e0ffa2
74210a4
7fd1cb1
99ed0c7
c8f5738
470b8ac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
## Result Pager | ||
[Back to the navigation](index.md) | ||
|
||
### Usage examples | ||
|
||
Get all repositories of a organization | ||
|
||
```php | ||
$client = new Github\Client(); | ||
|
||
$organizationApi = $client->api('organization'); | ||
|
||
$paginator = new Github\ResultPager($client); | ||
$parameters = array('github'); | ||
$result = $paginator->fetchAll($organizationApi, 'repositories', $parameters); | ||
``` | ||
|
||
Get the first page | ||
```php | ||
$client = new Github\Client(); | ||
|
||
$organizationApi = $client->api('organization'); | ||
|
||
$paginator = new Github\ResultPager( $client ); | ||
$parameters = array('github'); | ||
$result = $paginator->fetch($organizationApi, 'repositories', $parameters); | ||
``` | ||
|
||
Check for a next page: | ||
```php | ||
$paginator->hasNext(); | ||
``` | ||
|
||
Get next page: | ||
```php | ||
$paginator->fetchNext(); | ||
``` | ||
|
||
Check for pervious page: | ||
```php | ||
$paginator->hasPrevious(); | ||
``` | ||
|
||
Get prevrious page: | ||
```php | ||
$paginator->fetchPrevious(); | ||
``` | ||
|
||
If you want to retrieve the pagination links (available after the call to fetch): | ||
```php | ||
$paginator->getPagination(); | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
<?php | ||
|
||
namespace Github; | ||
|
||
use Github\Api\ApiInterface; | ||
use Github\Exception\InvalidArgumentException; | ||
use Github\HttpClient\HttpClient; | ||
use Github\HttpClient\HttpClientInterface; | ||
|
||
/** | ||
* Pager class for supporting pagination in github classes | ||
* | ||
* @author Ramon de la Fuente <ramon@future500.nl> | ||
* @author Mitchel Verschoof <mitchel@future500.nl> | ||
*/ | ||
class ResultPager implements ResultPagerInterface | ||
{ | ||
/** | ||
* @var Github\Client client | ||
*/ | ||
protected $client; | ||
|
||
/** | ||
* @var array pagination | ||
* Comes from pagination headers in Github API results | ||
*/ | ||
protected $pagination; | ||
|
||
|
||
/** | ||
* The Github client to use for pagination. This must be the same | ||
* instance that you got the Api instance from, i.e.: | ||
* | ||
* $client = new \Github\Client(); | ||
* $api = $client->api('someApi'); | ||
* $pager = new \Github\ResultPager($client); | ||
* | ||
* @param \Github\Client $client | ||
* | ||
*/ | ||
public function __construct(Client $client) | ||
{ | ||
$this->client = $client; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getPagination() | ||
{ | ||
return $this->pagination; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function fetch(ApiInterface $api, $method, array $parameters = array()) | ||
{ | ||
$result = call_user_func_array(array($api, $method), $parameters); | ||
$this->postFetch(); | ||
|
||
return $result; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function fetchAll(ApiInterface $api, $method, array $parameters = array()) | ||
{ | ||
// get the perPage from the api | ||
$perPage = $api->getPerPage(); | ||
|
||
// Set parameters per_page to GitHub max to minimize number of requests | ||
$api->setPerPage(100); | ||
|
||
$result = array(); | ||
$result = call_user_func_array(array($api, $method), $parameters); | ||
$this->postFetch(); | ||
|
||
while ($this->hasNext()) { | ||
$result = array_merge($result, $this->fetchNext()); | ||
} | ||
|
||
// restore the perPage | ||
$api->setPerPage($perPage); | ||
|
||
return $result; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function postFetch() | ||
{ | ||
$this->pagination = $this->client->getHttpClient()->getLastResponse()->getPagination(); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function hasNext() | ||
{ | ||
return $this->has('next'); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function fetchNext() | ||
{ | ||
return $this->get('next'); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function hasPrevious() | ||
{ | ||
return $this->has('prev'); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function fetchPrevious() | ||
{ | ||
return $this->get('prev'); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function fetchFirst() | ||
{ | ||
return $this->get('first'); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function fetchLast() | ||
{ | ||
return $this->get('last'); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
protected function has($key) | ||
{ | ||
return !empty($this->pagination) && isset($this->pagination[$key]); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
protected function get($key) | ||
{ | ||
if ($this->has($key)) { | ||
$result = $this->client->getHttpClient()->get($this->pagination[$key]); | ||
$this->postFetch(); | ||
|
||
return $result->getContent(); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
<?php | ||
|
||
namespace Github; | ||
|
||
use Github\Api\ApiInterface; | ||
|
||
/** | ||
* Pager interface | ||
* | ||
* @author Ramon de la Fuente <ramon@future500.nl> | ||
* @author Mitchel Verschoof <mitchel@future500.nl> | ||
*/ | ||
interface ResultPagerInterface | ||
{ | ||
|
||
/** | ||
* @return null|array pagination result of last request | ||
*/ | ||
public function getPagination(); | ||
|
||
/** | ||
* Fetch a single result (page) from an api call | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you should document the return value in the methods |
||
* | ||
* @param ApiInterface $api the Api instance | ||
* @param string $method the method name to call on the Api instance | ||
* @param array $parameters the method parameters in an array | ||
* | ||
* @return array returns the result of the Api::$method() call | ||
*/ | ||
public function fetch(ApiInterface $api, $method, array $parameters = array()); | ||
|
||
/** | ||
* Fetch all results (pages) from an api call | ||
* Use with care - there is no maximum | ||
* | ||
* @param ApiInterface $api the Api instance | ||
* @param string $method the method name to call on the Api instance | ||
* @param array $parameters the method parameters in an array | ||
* | ||
* @return array returns a merge of the results of the Api::$method() call | ||
*/ | ||
public function fetchAll(ApiInterface $api, $method, array $parameters = array()); | ||
|
||
/** | ||
* Method that performs the actual work to refresh the pagination property | ||
*/ | ||
public function postFetch(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should it really be a public method ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @stof It wasn't - but thinking about how people would interact with the resultPager across requests makes is necesary at this point. If you request the pagination information from the pager i.e. getPagination() you could use a "next" button on your own interface. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps a public setPagination() that gets called by protected postFetch()? |
||
|
||
/** | ||
* Check to determine the availability of a next page | ||
* @return bool | ||
*/ | ||
public function hasNext(); | ||
|
||
/** | ||
* Check to determine the availability of a previous page | ||
* @return bool | ||
*/ | ||
public function hasPrevious(); | ||
|
||
/** | ||
* Fetch the next page | ||
* @return array | ||
*/ | ||
public function fetchNext(); | ||
|
||
/** | ||
* Fetch the previous page | ||
* @return array | ||
*/ | ||
public function fetchPrevious(); | ||
|
||
/** | ||
* Fetch the first page | ||
* @return array | ||
*/ | ||
public function fetchFirst(); | ||
|
||
/** | ||
* Fetch the last page | ||
* @return array | ||
*/ | ||
public function fetchLast(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't you reset it to its current value at the end to avoid side effects ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@stof Good point. I decided to raise the parameter because it did not make sense to do more api calls than needed. But we'd like to add a resultLimit() to allow fetchAll to be used even when you don't literally want "all". And in that case you might want to keep control over the per_page count as well.