Skip to content

Improve retrieveAll() #310

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

Merged
merged 16 commits into from
Mar 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased](https://github.com/kbsali/php-redmine-api/compare/v2.1.0...v2.x)

### Added

- New method `Redmine\Client\AbstractApi::retrieveData()` to retrieve as many elements as you want as array (even if the total number of elements is greater than 100).
- New exception `Redmine\Client\SerializerException` for JSON/XML serializer related exceptions

### Deprecated

- `Redmine\Api\AbstractApi::retrieveAll()` is deprecated, use `Redmine\Api\AbstractApi::retrieveData()` instead

## [v2.1.1](https://github.com/kbsali/php-redmine-api/compare/v2.1.0...v2.1.1) - 2022-01-15

### Fixed
Expand Down
98 changes: 83 additions & 15 deletions src/Redmine/Api/AbstractApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
use JsonException;
use Redmine\Api;
use Redmine\Client\Client;
use Redmine\Exception\SerializerException;
use Redmine\Serializer\JsonSerializer;
use Redmine\Serializer\PathSerializer;
use Redmine\Serializer\XmlSerializer;
use SimpleXMLElement;

/**
Expand Down Expand Up @@ -51,7 +55,7 @@ public function lastCallFailed()
*/
protected function get($path, $decodeIfJson = true)
{
$this->client->requestGet($path);
$this->client->requestGet(strval($path));

$body = $this->client->getLastResponseBody();
$contentType = $this->client->getLastResponseContentType();
Expand All @@ -63,9 +67,9 @@ protected function get($path, $decodeIfJson = true)

if (true === $decodeIfJson && '' !== $body && 0 === strpos($contentType, 'application/json')) {
try {
return json_decode($body, true, 512, \JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
return 'Error decoding body as JSON: '.$e->getMessage();
return JsonSerializer::createFromString($body)->getNormalized();
} catch (SerializerException $e) {
return 'Error decoding body as JSON: '.$e->getPrevious()->getMessage();
}
}

Expand Down Expand Up @@ -161,23 +165,54 @@ protected function sanitizeParams(array $defaults, array $params)
* Retrieves all the elements of a given endpoint (even if the
* total number of elements is greater than 100).
*
* @deprecated the `retrieveAll()` method is deprecated, use `retrieveData()` instead.
*
* @param string $endpoint API end point
* @param array $params optional parameters to be passed to the api (offset, limit, ...)
*
* @return array elements found
* @return array|false elements found
*/
protected function retrieveAll($endpoint, array $params = [])
{
@trigger_error('The '.__METHOD__.' method is deprecated, use `retrieveData()` instead.', E_USER_DEPRECATED);

try {
$data = $this->retrieveData(strval($endpoint), $params);
} catch (SerializerException $e) {
$data = false;
}

return $data;
}

/**
* Retrieves all the elements of a given endpoint (even if the
* total number of elements is greater than 100).
*
* @param string $endpoint API end point
* @param array $params optional query parameters to be passed to the api (offset, limit, ...)
*
* @throws SerializerException if response body could not be converted into array
*
* @return array elements found
*/
protected function retrieveData(string $endpoint, array $params = []): array
{
if (empty($params)) {
return $this->get($endpoint);
$this->client->requestGet($endpoint);

return $this->getLastResponseBodyAsArray();
}
$defaults = [
'limit' => 25,
'offset' => 0,
];
$params = $this->sanitizeParams($defaults, $params);

$ret = [];
$params = $this->sanitizeParams(
[
'limit' => 25,
'offset' => 0,
],
$params
);

$returnData = [];

$limit = $params['limit'];
$offset = $params['offset'];
Expand All @@ -193,10 +228,16 @@ protected function retrieveAll($endpoint, array $params = [])
$params['limit'] = $_limit;
$params['offset'] = $offset;

$newDataSet = (array) $this->get($endpoint.'?'.preg_replace('/%5B[0-9]+%5D/simU', '%5B%5D', http_build_query($params)));
$ret = array_merge_recursive($ret, $newDataSet);
$this->client->requestGet(
PathSerializer::create($endpoint, $params)->getPath()
);

$newDataSet = $this->getLastResponseBodyAsArray();

$returnData = array_merge_recursive($returnData, $newDataSet);

$offset += $_limit;

if (empty($newDataSet) || !isset($newDataSet['limit']) || (
isset($newDataSet['offset']) &&
isset($newDataSet['total_count']) &&
Expand All @@ -207,7 +248,7 @@ protected function retrieveAll($endpoint, array $params = [])
}
}

return $ret;
return $returnData;
}

/**
Expand Down Expand Up @@ -254,4 +295,31 @@ protected function attachCustomFieldXML(SimpleXMLElement $xml, array $fields)

return $xml;
}

/**
* returns the last response body as array
*
* @throws SerializerException if response body could not be converted into array
*/
private function getLastResponseBodyAsArray(): array
{
$body = $this->client->getLastResponseBody();
$contentType = $this->client->getLastResponseContentType();
$returnData = null;

// parse XML
if (0 === strpos($contentType, 'application/xml')) {
$returnData = XmlSerializer::createFromString($body)->getNormalized();
} else if (0 === strpos($contentType, 'application/json')) {
$returnData = JsonSerializer::createFromString($body)->getNormalized();
}

if (! is_array($returnData)) {
throw new SerializerException(
'Could not convert response body into array: ' . $body
);
}

return $returnData;
}
}
7 changes: 6 additions & 1 deletion src/Redmine/Api/Attachment.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Redmine\Api;

use Redmine\Serializer\PathSerializer;

/**
* Attachment details.
*
Expand Down Expand Up @@ -51,7 +53,10 @@ public function download($id)
*/
public function upload($attachment, $params = [])
{
return $this->post('/uploads.json?'.http_build_query($params), $attachment);
return $this->post(
PathSerializer::create('/uploads.json', $params)->getPath(),
$attachment
);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Redmine/Api/CustomField.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class CustomField extends AbstractApi
*/
public function all(array $params = [])
{
$this->customFields = $this->retrieveAll('/custom_fields.json', $params);
$this->customFields = $this->retrieveData('/custom_fields.json', $params);

return $this->customFields;
}
Expand Down
7 changes: 5 additions & 2 deletions src/Redmine/Api/Group.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Exception;
use Redmine\Exception\MissingParameterException;
use Redmine\Serializer\PathSerializer;

/**
* Handling of groups.
Expand All @@ -27,7 +28,7 @@ class Group extends AbstractApi
*/
public function all(array $params = [])
{
$this->groups = $this->retrieveAll('/groups.json', $params);
$this->groups = $this->retrieveData('/groups.json', $params);

return $this->groups;
}
Expand Down Expand Up @@ -110,7 +111,9 @@ public function update($id, array $params = [])
*/
public function show($id, array $params = [])
{
return $this->get('/groups/'.urlencode($id).'.json?'.http_build_query($params));
return $this->get(
PathSerializer::create('/groups/'.urlencode($id).'.json', $params)->getPath()
);
}

/**
Expand Down
8 changes: 6 additions & 2 deletions src/Redmine/Api/Issue.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Redmine\Api;

use Redmine\Serializer\PathSerializer;

/**
* Listing issues, searching, editing and closing your projects issues.
*
Expand Down Expand Up @@ -38,7 +40,7 @@ class Issue extends AbstractApi
*/
public function all(array $params = [])
{
return $this->retrieveAll('/issues.json', $params);
return $this->retrieveData('/issues.json', $params);
}

/**
Expand All @@ -59,7 +61,9 @@ public function show($id, array $params = [])
$params['include'] = implode(',', $params['include']);
}

return $this->get('/issues/'.urlencode($id).'.json?'.http_build_query($params));
return $this->get(
PathSerializer::create('/issues/'.urlencode($id).'.json', $params)->getPath()
);
}

/**
Expand Down
7 changes: 5 additions & 2 deletions src/Redmine/Api/IssueCategory.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Redmine\Api;

use Redmine\Exception\MissingParameterException;
use Redmine\Serializer\PathSerializer;

/**
* Listing issue categories, creating, editing.
Expand All @@ -27,7 +28,7 @@ class IssueCategory extends AbstractApi
*/
public function all($project, array $params = [])
{
$this->issueCategories = $this->retrieveAll('/projects/'.$project.'/issue_categories.json', $params);
$this->issueCategories = $this->retrieveData('/projects/'.$project.'/issue_categories.json', $params);

return $this->issueCategories;
}
Expand Down Expand Up @@ -158,6 +159,8 @@ public function update($id, array $params)
*/
public function remove($id, array $params = [])
{
return $this->delete('/issue_categories/'.$id.'.xml?'.http_build_query($params));
return $this->delete(
PathSerializer::create('/issue_categories/'.$id.'.xml', $params)->getPath()
);
}
}
2 changes: 1 addition & 1 deletion src/Redmine/Api/IssuePriority.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class IssuePriority extends AbstractApi
*/
public function all(array $params = [])
{
$this->issuePriorities = $this->retrieveAll('/enumerations/issue_priorities.json', $params);
$this->issuePriorities = $this->retrieveData('/enumerations/issue_priorities.json', $params);

return $this->issuePriorities;
}
Expand Down
8 changes: 6 additions & 2 deletions src/Redmine/Api/IssueRelation.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Redmine\Api;

use Redmine\Serializer\JsonSerializer;

/**
* Handling issue relations.
*
Expand All @@ -25,7 +27,7 @@ class IssueRelation extends AbstractApi
*/
public function all($issueId, array $params = [])
{
$this->relations = $this->retrieveAll('/issues/'.urlencode($issueId).'/relations.json', $params);
$this->relations = $this->retrieveData('/issues/'.urlencode($issueId).'/relations.json', $params);

return $this->relations;
}
Expand Down Expand Up @@ -85,6 +87,8 @@ public function create($issueId, array $params = [])

$params = json_encode(['relation' => $params]);

return json_decode($this->post('/issues/'.urlencode($issueId).'/relations.json', $params), true);
$response = $this->post('/issues/'.urlencode($issueId).'/relations.json', $params);

return JsonSerializer::createFromString($response)->getNormalized();
}
}
2 changes: 1 addition & 1 deletion src/Redmine/Api/IssueStatus.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class IssueStatus extends AbstractApi
*/
public function all(array $params = [])
{
$this->issueStatuses = $this->retrieveAll('/issue_statuses.json', $params);
$this->issueStatuses = $this->retrieveData('/issue_statuses.json', $params);

return $this->issueStatuses;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Redmine/Api/Membership.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class Membership extends AbstractApi
*/
public function all($project, array $params = [])
{
$this->memberships = $this->retrieveAll('/projects/'.$project.'/memberships.json', $params);
$this->memberships = $this->retrieveData('/projects/'.$project.'/memberships.json', $params);

return $this->memberships;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Redmine/Api/News.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class News extends AbstractApi
public function all($project = null, array $params = [])
{
$path = null === $project ? '/news.json' : '/projects/'.$project.'/news.json';
$this->news = $this->retrieveAll($path, $params);
$this->news = $this->retrieveData($path, $params);

return $this->news;
}
Expand Down
7 changes: 5 additions & 2 deletions src/Redmine/Api/Project.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Redmine\Api;

use Redmine\Exception\MissingParameterException;
use Redmine\Serializer\PathSerializer;

/**
* Listing projects, creating, editing.
Expand All @@ -26,7 +27,7 @@ class Project extends AbstractApi
*/
public function all(array $params = [])
{
$this->projects = $this->retrieveAll('/projects.json', $params);
$this->projects = $this->retrieveData('/projects.json', $params);

return $this->projects;
}
Expand Down Expand Up @@ -90,7 +91,9 @@ public function show($id, array $params = [])
$params['include'] = 'trackers,issue_categories,attachments,relations';
}

return $this->get('/projects/'.urlencode($id).'.json?'.http_build_query($params));
return $this->get(
PathSerializer::create('/projects/'.urlencode($id).'.json', $params)->getPath()
);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Redmine/Api/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class Query extends AbstractApi
*/
public function all(array $params = [])
{
$this->query = $this->retrieveAll('/queries.json', $params);
$this->query = $this->retrieveData('/queries.json', $params);

return $this->query;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Redmine/Api/Role.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class Role extends AbstractApi
*/
public function all(array $params = [])
{
$this->roles = $this->retrieveAll('/roles.json', $params);
$this->roles = $this->retrieveData('/roles.json', $params);

return $this->roles;
}
Expand Down
Loading