Skip to content

Commit 458b59b

Browse files
authored
Merge pull request #310 from Art4/improve-retrieve-all
Improve retrieveAll()
2 parents 7d262d6 + 183f02c commit 458b59b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+991
-227
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Allow unassign user from an issue
1313

14+
### Added
15+
16+
- 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).
17+
- New exception `Redmine\Client\SerializerException` for JSON/XML serializer related exceptions
18+
19+
### Deprecated
20+
21+
- `Redmine\Api\AbstractApi::retrieveAll()` is deprecated, use `Redmine\Api\AbstractApi::retrieveData()` instead
22+
1423
## [v2.1.1](https://github.com/kbsali/php-redmine-api/compare/v2.1.0...v2.1.1) - 2022-01-15
1524

1625
### Fixed

src/Redmine/Api/AbstractApi.php

Lines changed: 83 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
use JsonException;
66
use Redmine\Api;
77
use Redmine\Client\Client;
8+
use Redmine\Exception\SerializerException;
9+
use Redmine\Serializer\JsonSerializer;
10+
use Redmine\Serializer\PathSerializer;
11+
use Redmine\Serializer\XmlSerializer;
812
use SimpleXMLElement;
913

1014
/**
@@ -51,7 +55,7 @@ public function lastCallFailed()
5155
*/
5256
protected function get($path, $decodeIfJson = true)
5357
{
54-
$this->client->requestGet($path);
58+
$this->client->requestGet(strval($path));
5559

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

6468
if (true === $decodeIfJson && '' !== $body && 0 === strpos($contentType, 'application/json')) {
6569
try {
66-
return json_decode($body, true, 512, \JSON_THROW_ON_ERROR);
67-
} catch (JsonException $e) {
68-
return 'Error decoding body as JSON: '.$e->getMessage();
70+
return JsonSerializer::createFromString($body)->getNormalized();
71+
} catch (SerializerException $e) {
72+
return 'Error decoding body as JSON: '.$e->getPrevious()->getMessage();
6973
}
7074
}
7175

@@ -161,23 +165,54 @@ protected function sanitizeParams(array $defaults, array $params)
161165
* Retrieves all the elements of a given endpoint (even if the
162166
* total number of elements is greater than 100).
163167
*
168+
* @deprecated the `retrieveAll()` method is deprecated, use `retrieveData()` instead.
169+
*
164170
* @param string $endpoint API end point
165171
* @param array $params optional parameters to be passed to the api (offset, limit, ...)
166172
*
167-
* @return array elements found
173+
* @return array|false elements found
168174
*/
169175
protected function retrieveAll($endpoint, array $params = [])
176+
{
177+
@trigger_error('The '.__METHOD__.' method is deprecated, use `retrieveData()` instead.', E_USER_DEPRECATED);
178+
179+
try {
180+
$data = $this->retrieveData(strval($endpoint), $params);
181+
} catch (SerializerException $e) {
182+
$data = false;
183+
}
184+
185+
return $data;
186+
}
187+
188+
/**
189+
* Retrieves all the elements of a given endpoint (even if the
190+
* total number of elements is greater than 100).
191+
*
192+
* @param string $endpoint API end point
193+
* @param array $params optional query parameters to be passed to the api (offset, limit, ...)
194+
*
195+
* @throws SerializerException if response body could not be converted into array
196+
*
197+
* @return array elements found
198+
*/
199+
protected function retrieveData(string $endpoint, array $params = []): array
170200
{
171201
if (empty($params)) {
172-
return $this->get($endpoint);
202+
$this->client->requestGet($endpoint);
203+
204+
return $this->getLastResponseBodyAsArray();
173205
}
174-
$defaults = [
175-
'limit' => 25,
176-
'offset' => 0,
177-
];
178-
$params = $this->sanitizeParams($defaults, $params);
179206

180-
$ret = [];
207+
$params = $this->sanitizeParams(
208+
[
209+
'limit' => 25,
210+
'offset' => 0,
211+
],
212+
$params
213+
);
214+
215+
$returnData = [];
181216

182217
$limit = $params['limit'];
183218
$offset = $params['offset'];
@@ -193,10 +228,16 @@ protected function retrieveAll($endpoint, array $params = [])
193228
$params['limit'] = $_limit;
194229
$params['offset'] = $offset;
195230

196-
$newDataSet = (array) $this->get($endpoint.'?'.preg_replace('/%5B[0-9]+%5D/simU', '%5B%5D', http_build_query($params)));
197-
$ret = array_merge_recursive($ret, $newDataSet);
231+
$this->client->requestGet(
232+
PathSerializer::create($endpoint, $params)->getPath()
233+
);
234+
235+
$newDataSet = $this->getLastResponseBodyAsArray();
236+
237+
$returnData = array_merge_recursive($returnData, $newDataSet);
198238

199239
$offset += $_limit;
240+
200241
if (empty($newDataSet) || !isset($newDataSet['limit']) || (
201242
isset($newDataSet['offset']) &&
202243
isset($newDataSet['total_count']) &&
@@ -207,7 +248,7 @@ protected function retrieveAll($endpoint, array $params = [])
207248
}
208249
}
209250

210-
return $ret;
251+
return $returnData;
211252
}
212253

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

255296
return $xml;
256297
}
298+
299+
/**
300+
* returns the last response body as array
301+
*
302+
* @throws SerializerException if response body could not be converted into array
303+
*/
304+
private function getLastResponseBodyAsArray(): array
305+
{
306+
$body = $this->client->getLastResponseBody();
307+
$contentType = $this->client->getLastResponseContentType();
308+
$returnData = null;
309+
310+
// parse XML
311+
if (0 === strpos($contentType, 'application/xml')) {
312+
$returnData = XmlSerializer::createFromString($body)->getNormalized();
313+
} else if (0 === strpos($contentType, 'application/json')) {
314+
$returnData = JsonSerializer::createFromString($body)->getNormalized();
315+
}
316+
317+
if (! is_array($returnData)) {
318+
throw new SerializerException(
319+
'Could not convert response body into array: ' . $body
320+
);
321+
}
322+
323+
return $returnData;
324+
}
257325
}

src/Redmine/Api/Attachment.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Redmine\Api;
44

5+
use Redmine\Serializer\PathSerializer;
6+
57
/**
68
* Attachment details.
79
*
@@ -51,7 +53,10 @@ public function download($id)
5153
*/
5254
public function upload($attachment, $params = [])
5355
{
54-
return $this->post('/uploads.json?'.http_build_query($params), $attachment);
56+
return $this->post(
57+
PathSerializer::create('/uploads.json', $params)->getPath(),
58+
$attachment
59+
);
5560
}
5661

5762
/**

src/Redmine/Api/CustomField.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class CustomField extends AbstractApi
2424
*/
2525
public function all(array $params = [])
2626
{
27-
$this->customFields = $this->retrieveAll('/custom_fields.json', $params);
27+
$this->customFields = $this->retrieveData('/custom_fields.json', $params);
2828

2929
return $this->customFields;
3030
}

src/Redmine/Api/Group.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Exception;
66
use Redmine\Exception\MissingParameterException;
7+
use Redmine\Serializer\PathSerializer;
78

89
/**
910
* Handling of groups.
@@ -27,7 +28,7 @@ class Group extends AbstractApi
2728
*/
2829
public function all(array $params = [])
2930
{
30-
$this->groups = $this->retrieveAll('/groups.json', $params);
31+
$this->groups = $this->retrieveData('/groups.json', $params);
3132

3233
return $this->groups;
3334
}
@@ -110,7 +111,9 @@ public function update($id, array $params = [])
110111
*/
111112
public function show($id, array $params = [])
112113
{
113-
return $this->get('/groups/'.urlencode($id).'.json?'.http_build_query($params));
114+
return $this->get(
115+
PathSerializer::create('/groups/'.urlencode($id).'.json', $params)->getPath()
116+
);
114117
}
115118

116119
/**

src/Redmine/Api/Issue.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Redmine\Api;
44

5+
use Redmine\Serializer\PathSerializer;
6+
57
/**
68
* Listing issues, searching, editing and closing your projects issues.
79
*
@@ -38,7 +40,7 @@ class Issue extends AbstractApi
3840
*/
3941
public function all(array $params = [])
4042
{
41-
return $this->retrieveAll('/issues.json', $params);
43+
return $this->retrieveData('/issues.json', $params);
4244
}
4345

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

62-
return $this->get('/issues/'.urlencode($id).'.json?'.http_build_query($params));
64+
return $this->get(
65+
PathSerializer::create('/issues/'.urlencode($id).'.json', $params)->getPath()
66+
);
6367
}
6468

6569
/**

src/Redmine/Api/IssueCategory.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Redmine\Api;
44

55
use Redmine\Exception\MissingParameterException;
6+
use Redmine\Serializer\PathSerializer;
67

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

3233
return $this->issueCategories;
3334
}
@@ -158,6 +159,8 @@ public function update($id, array $params)
158159
*/
159160
public function remove($id, array $params = [])
160161
{
161-
return $this->delete('/issue_categories/'.$id.'.xml?'.http_build_query($params));
162+
return $this->delete(
163+
PathSerializer::create('/issue_categories/'.$id.'.xml', $params)->getPath()
164+
);
162165
}
163166
}

src/Redmine/Api/IssuePriority.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class IssuePriority extends AbstractApi
2424
*/
2525
public function all(array $params = [])
2626
{
27-
$this->issuePriorities = $this->retrieveAll('/enumerations/issue_priorities.json', $params);
27+
$this->issuePriorities = $this->retrieveData('/enumerations/issue_priorities.json', $params);
2828

2929
return $this->issuePriorities;
3030
}

src/Redmine/Api/IssueRelation.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Redmine\Api;
44

5+
use Redmine\Serializer\JsonSerializer;
6+
57
/**
68
* Handling issue relations.
79
*
@@ -25,7 +27,7 @@ class IssueRelation extends AbstractApi
2527
*/
2628
public function all($issueId, array $params = [])
2729
{
28-
$this->relations = $this->retrieveAll('/issues/'.urlencode($issueId).'/relations.json', $params);
30+
$this->relations = $this->retrieveData('/issues/'.urlencode($issueId).'/relations.json', $params);
2931

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

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

88-
return json_decode($this->post('/issues/'.urlencode($issueId).'/relations.json', $params), true);
90+
$response = $this->post('/issues/'.urlencode($issueId).'/relations.json', $params);
91+
92+
return JsonSerializer::createFromString($response)->getNormalized();
8993
}
9094
}

src/Redmine/Api/IssueStatus.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class IssueStatus extends AbstractApi
2424
*/
2525
public function all(array $params = [])
2626
{
27-
$this->issueStatuses = $this->retrieveAll('/issue_statuses.json', $params);
27+
$this->issueStatuses = $this->retrieveData('/issue_statuses.json', $params);
2828

2929
return $this->issueStatuses;
3030
}

src/Redmine/Api/Membership.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class Membership extends AbstractApi
2727
*/
2828
public function all($project, array $params = [])
2929
{
30-
$this->memberships = $this->retrieveAll('/projects/'.$project.'/memberships.json', $params);
30+
$this->memberships = $this->retrieveData('/projects/'.$project.'/memberships.json', $params);
3131

3232
return $this->memberships;
3333
}

src/Redmine/Api/News.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class News extends AbstractApi
2424
public function all($project = null, array $params = [])
2525
{
2626
$path = null === $project ? '/news.json' : '/projects/'.$project.'/news.json';
27-
$this->news = $this->retrieveAll($path, $params);
27+
$this->news = $this->retrieveData($path, $params);
2828

2929
return $this->news;
3030
}

src/Redmine/Api/Project.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Redmine\Api;
44

55
use Redmine\Exception\MissingParameterException;
6+
use Redmine\Serializer\PathSerializer;
67

78
/**
89
* Listing projects, creating, editing.
@@ -26,7 +27,7 @@ class Project extends AbstractApi
2627
*/
2728
public function all(array $params = [])
2829
{
29-
$this->projects = $this->retrieveAll('/projects.json', $params);
30+
$this->projects = $this->retrieveData('/projects.json', $params);
3031

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

93-
return $this->get('/projects/'.urlencode($id).'.json?'.http_build_query($params));
94+
return $this->get(
95+
PathSerializer::create('/projects/'.urlencode($id).'.json', $params)->getPath()
96+
);
9497
}
9598

9699
/**

src/Redmine/Api/Query.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class Query extends AbstractApi
2424
*/
2525
public function all(array $params = [])
2626
{
27-
$this->query = $this->retrieveAll('/queries.json', $params);
27+
$this->query = $this->retrieveData('/queries.json', $params);
2828

2929
return $this->query;
3030
}

src/Redmine/Api/Role.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class Role extends AbstractApi
2424
*/
2525
public function all(array $params = [])
2626
{
27-
$this->roles = $this->retrieveAll('/roles.json', $params);
27+
$this->roles = $this->retrieveData('/roles.json', $params);
2828

2929
return $this->roles;
3030
}

0 commit comments

Comments
 (0)