-
-
Notifications
You must be signed in to change notification settings - Fork 600
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
ResultPager doesn't merge data correctly for all API's #912
Comments
@GrahamCampbell This could effect #907 as well. Let me know what you think! |
I think we should report this as a bug to GitHub actually. It looks like the developer who implemented the installations API was not aware of their conventions. |
Inline hack that I used to get Mileage may vary. $pager = new class($client) extends ResultPager {
protected function callApi(ApiInterface $api, $method, array $parameters)
{
return parent::callApi($api, $method, $parameters)['repositories'];
}
public function fetchNext()
{
return parent::fetchNext()['repositories'];
}
}; |
Right on. I did the following since I have one call that needs <?php
namespace App\Api\GitHub;
use Github\Api\ApiInterface;
use Github\Api\Search;
use Github\ResultPager as BaseResultPager;
class ResultPager extends BaseResultPager
{
protected $resultKey;
/**
* @param $key
* @return $this
*/
public function setResultKey($key)
{
$this->resultKey = $key;
return $this;
}
/**
* {@inheritdoc}
*/
public function fetchAll(ApiInterface $api, $method, array $parameters = [])
{
$isSearch = $api instanceof Search;
// get the perPage from the api
$perPage = $api->getPerPage();
// set parameters per_page to GitHub max to minimize number of requests
$api->setPerPage(100);
try {
$result = $this->callApi($api, $method, $parameters);
$this->postFetch();
if ($this->resultKey) {
$result = $result[$this->resultKey];
}
if ($isSearch) {
$result = isset($result['items']) ? $result['items'] : $result;
}
while ($this->hasNext()) {
$next = $this->fetchNext();
if ($isSearch) {
$result = array_merge($result, $next['items']);
} elseif ($this->resultKey) {
$result = array_merge($result, $next[$this->resultKey]);
} else {
$result = array_merge($result, $next);
}
}
} finally {
// restore the perPage
$api->setPerPage($perPage);
}
return $result;
}
} Example call to this result fetcher: $github = new Client(new Builder, 'machine-man-preview');
$github->authenticate($oAuthToken, Client::AUTH_HTTP_TOKEN);
$resultFetcher = new GitHubResultPager($github);
$resultFetcher
->setResultKey('installations')
->fetchAll($github->currentUser(), 'installations'); |
@GrahamCampbell I opened a ticket with GitHub but haven't heard a thing back :D |
From GitHub:
|
Just updated this library and found that the previous solution posted by @fideloper doesn't work anymore. Here is an updated class for version 3.2.0 in case somebody will need it too: <?php
namespace App\Api\Github;
use Github\Api\AbstractApi;
use Github\ResultPager as BaseResultPager;
class ResultPager extends BaseResultPager
{
private $resultKey;
public function setResultKey($key)
{
$this->resultKey = $key;
return $this;
}
public function fetch(AbstractApi $api, string $method, array $parameters = []): array
{
return $this->prepareResult(parent::fetch($api, $method, $parameters));
}
protected function get(string $key): array
{
return $this->prepareResult(parent::get($key));
}
private function prepareResult(array $result): array
{
if ($this->resultKey && $result) {
$result['items'] = $result[$this->resultKey] ?? [];
}
return $result;
}
} Usage: $repositories = (new ResultPager($client))
->setResultKey('repositories')
->fetchAll($client->apps(), 'listRepositories'); |
Thank you! it works like a charm. |
This is still an "issue" as of tag
|
Hello!
The Problem (Description)
This is technically a duplicate of #597 from 2017, but I wanted to add in details and present some possible solutions.
We're using this library on ChipperCI, some customers noted that we aren't correctly listing all of the repositories our GitHub App is installed into when they have a large number of repositories.
Digging in, we realized only the last page of results were being returned back when using the
ResultPager::fetchAll()
method on results that had more than one page.This only happens on certain API calls (I've only seen it on the Apps API so far - listed below).
The Issue
This is due to the use of
array_merge()
to merge resulting arrays back:https://github.com/KnpLabs/php-github-api/blob/2.x/lib/Github/ResultPager.php#L92-L96:
Here's an example call into the App's api that results in the issue:
A result object from one API call is (I set it to
1
per page to test this out, but it happens when there are more than 100 results for any API with results like this) - converted from JSON to PHP:If you
array_merge()
these, PHP will over-write the the first array with the second, as their associative keys match!Possible Solutions
A first idea I had:
The solution may be API class extending
AbstractAPI
to know if there is a key to be used there.So far I can only find examples from the App's api, and from searching the source of that page, only these 3 endpoints appear to use
total_count
(and the other key forrepositories
/installations
) in the returned results:GET /user/installations/{installation_id}/repositories
GET /installation/repositories
GET /user/installations
The keys in the
$result
/$next
array arerepositories
orinstallations
.So perhaps something like this:
And then in
ResultPager
:This would likely need to be used not just for certain API's (e.g. the App's api) but the specific endpoints that need it 😅
Hopefully these extra details can help pin-point the issue! In the meantime, I'll do a similar work-around as the others in this (duplicate but less detailed) issue.
Let me know if I can clarify anything!
The text was updated successfully, but these errors were encountered: