Skip to content

Commit ae384f0

Browse files
authored
Merge pull request #398 from Art4/338-replace-listing-methods-with-consistent-solution
Add `Group::listNames()` method as replacement for `Group::listing()`
2 parents ece897d + 4764543 commit ae384f0

File tree

7 files changed

+293
-48
lines changed

7 files changed

+293
-48
lines changed

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

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

10+
### Added
11+
12+
- New method `Redmine\Api\Group::listNames()` for listing the ids and names of all groups.
13+
14+
### Deprecated
15+
16+
- `Redmine\Api\Group::listing()` is deprecated, use `\Redmine\Api\Group::listNames()` instead.
17+
1018
## [v2.6.0](https://github.com/kbsali/php-redmine-api/compare/v2.5.0...v2.6.0) - 2024-03-25
1119

1220
### Added

src/Redmine/Api/Group.php

+27
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ class Group extends AbstractApi
2323
{
2424
private $groups = [];
2525

26+
private $groupNames = null;
27+
2628
/**
2729
* List groups.
2830
*
@@ -43,6 +45,26 @@ final public function list(array $params = []): array
4345
}
4446
}
4547

48+
/**
49+
* Returns an array of all groups with id/name pairs.
50+
*
51+
* @return array<int,string> list of groups (id => name)
52+
*/
53+
final public function listNames(): array
54+
{
55+
if ($this->groupNames !== null) {
56+
return $this->groupNames;
57+
}
58+
59+
$this->groupNames = [];
60+
61+
foreach ($this->list()['groups'] as $group) {
62+
$this->groupNames[(int) $group['id']] = $group['name'];
63+
}
64+
65+
return $this->groupNames;
66+
}
67+
4668
/**
4769
* List groups.
4870
*
@@ -79,12 +101,17 @@ public function all(array $params = [])
79101
/**
80102
* Returns an array of groups with name/id pairs.
81103
*
104+
* @deprecated v2.7.0 Use listNames() instead.
105+
* @see Group::listNames()
106+
*
82107
* @param bool $forceUpdate to force the update of the groups var
83108
*
84109
* @return array list of groups (id => name)
85110
*/
86111
public function listing($forceUpdate = false)
87112
{
113+
@trigger_error('`' . __METHOD__ . '()` is deprecated since v2.7.0, use `' . __CLASS__ . '::listNames()` instead.', E_USER_DEPRECATED);
114+
88115
if (empty($this->groups) || $forceUpdate) {
89116
$this->groups = $this->list();
90117
}

tests/Behat/Bootstrap/FeatureContext.php

+83-48
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,36 @@ public function theReturnedDataIsAnInstanceOf(string $className)
205205
$this->assertInstanceOf($className, $this->lastReturn);
206206
}
207207

208+
/**
209+
* @Then the returned data is an array
210+
*/
211+
public function theReturnedDataIsAnArray()
212+
{
213+
$this->assertIsArray($this->lastReturn);
214+
}
215+
216+
/**
217+
* @Then the returned data contains :count items
218+
*/
219+
public function theReturnedDataContainsItems(int $count)
220+
{
221+
$this->assertCount($count, $this->lastReturn);
222+
}
223+
224+
/**
225+
* @Then the returned data contains the following data
226+
*/
227+
public function theReturnedDataContainsTheFollowingData(TableNode $table)
228+
{
229+
$returnData = $this->lastReturn;
230+
231+
if (! is_array($returnData)) {
232+
throw new RuntimeException('The returned data is not an array.');
233+
}
234+
235+
$this->assertTableNodeIsSameAsArray($table, $returnData);
236+
}
237+
208238
/**
209239
* @Then the returned data has only the following properties
210240
*/
@@ -257,54 +287,7 @@ public function theReturnedDataPropertyContainsTheFollowingData($property, Table
257287
throw new RuntimeException('The returned data on property "' . $property . '" is not an array.');
258288
}
259289

260-
foreach ($table as $row) {
261-
$this->assertArrayHasKey($row['property'], $returnData);
262-
263-
$value = $returnData[$row['property']];
264-
265-
if ($value instanceof SimpleXMLElement) {
266-
$value = strval($value);
267-
}
268-
269-
$expected = $row['value'];
270-
271-
// Handle expected empty array
272-
if ($value === [] && $expected === '[]') {
273-
$expected = [];
274-
}
275-
276-
// Handle expected int values
277-
if (is_int($value) && ctype_digit($expected)) {
278-
$expected = intval($expected);
279-
}
280-
281-
// Handle expected float values
282-
if (is_float($value) && is_numeric($expected)) {
283-
$expected = floatval($expected);
284-
}
285-
286-
// Handle expected null value
287-
if ($value === null && $expected === 'null') {
288-
$expected = null;
289-
}
290-
291-
// Handle expected true value
292-
if ($value === true && $expected === 'true') {
293-
$expected = true;
294-
}
295-
296-
// Handle expected false value
297-
if ($value === false && $expected === 'false') {
298-
$expected = false;
299-
}
300-
301-
// Handle placeholder %redmine_id%
302-
if (is_string($expected)) {
303-
$expected = str_replace('%redmine_id%', strval($this->redmine->getVersionId()), $expected);
304-
}
305-
306-
$this->assertSame($expected, $value, 'Error with property "' . $row['property'] . '"');
307-
}
290+
$this->assertTableNodeIsSameAsArray($table, $returnData);
308291
}
309292

310293
/**
@@ -384,4 +367,56 @@ private function getItemFromArray(array $array, $key): mixed
384367

385368
return $array;
386369
}
370+
371+
private function assertTableNodeIsSameAsArray(TableNode $table, array $data)
372+
{
373+
foreach ($table as $row) {
374+
$this->assertArrayHasKey($row['property'], $data, 'Possible keys are: ' . implode(', ', array_keys($data)));
375+
376+
$value = $data[$row['property']];
377+
378+
if ($value instanceof SimpleXMLElement) {
379+
$value = strval($value);
380+
}
381+
382+
$expected = $row['value'];
383+
384+
// Handle expected empty array
385+
if ($value === [] && $expected === '[]') {
386+
$expected = [];
387+
}
388+
389+
// Handle expected int values
390+
if (is_int($value) && ctype_digit($expected)) {
391+
$expected = intval($expected);
392+
}
393+
394+
// Handle expected float values
395+
if (is_float($value) && is_numeric($expected)) {
396+
$expected = floatval($expected);
397+
}
398+
399+
// Handle expected null value
400+
if ($value === null && $expected === 'null') {
401+
$expected = null;
402+
}
403+
404+
// Handle expected true value
405+
if ($value === true && $expected === 'true') {
406+
$expected = true;
407+
}
408+
409+
// Handle expected false value
410+
if ($value === false && $expected === 'false') {
411+
$expected = false;
412+
}
413+
414+
// Handle placeholder %redmine_id%
415+
if (is_string($expected)) {
416+
$expected = str_replace('%redmine_id%', strval($this->redmine->getVersionId()), $expected);
417+
}
418+
419+
$this->assertSame($expected, $value, 'Error with property "' . $row['property'] . '"');
420+
}
421+
}
387422
}

tests/Behat/Bootstrap/GroupContextTrait.php

+14
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,20 @@ public function iListAllGroups()
5757
);
5858
}
5959

60+
/**
61+
* @When I list the names of all groups
62+
*/
63+
public function iListTheNamesOfAllGroups()
64+
{
65+
/** @var Group */
66+
$api = $this->getNativeCurlClient()->getApi('group');
67+
68+
$this->registerClientResponse(
69+
$api->listNames(),
70+
$api->getLastResponse()
71+
);
72+
}
73+
6074
/**
6175
* @When I show the group with id :groupId
6276
*/

tests/Behat/features/groups.feature

+21
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,27 @@ Feature: Interacting with the REST API for groups
5757
| id | 4 |
5858
| name | Test Group |
5959

60+
@group
61+
Scenario: Listing names of all groups
62+
Given I have a "NativeCurlClient" client
63+
And I create a group with name "Test Group 1"
64+
And I create a group with name "Test Group 2"
65+
And I create a group with name "Test Group 3"
66+
And I create a group with name "Test Group 4"
67+
And I create a group with name "Test Group 5"
68+
When I list the names of all groups
69+
Then the response has the status code "200"
70+
And the response has the content type "application/json"
71+
And the returned data is an array
72+
And the returned data contains "5" items
73+
And the returned data contains the following data
74+
| property | value |
75+
| 4 | Test Group 1 |
76+
| 5 | Test Group 2 |
77+
| 6 | Test Group 3 |
78+
| 7 | Test Group 4 |
79+
| 8 | Test Group 5 |
80+
6081
@group
6182
Scenario: Showing a specific group
6283
Given I have a "NativeCurlClient" client
+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Redmine\Tests\Unit\Api\Group;
6+
7+
use PHPUnit\Framework\Attributes\CoversClass;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use PHPUnit\Framework\TestCase;
10+
use Redmine\Api\Group;
11+
use Redmine\Tests\Fixtures\AssertingHttpClient;
12+
13+
#[CoversClass(Group::class)]
14+
class ListNamesTest extends TestCase
15+
{
16+
/**
17+
* @dataProvider getListNamesData
18+
*/
19+
#[DataProvider('getListNamesData')]
20+
public function testListNamesReturnsCorrectResponse($expectedPath, $responseCode, $response, $expectedResponse)
21+
{
22+
$client = AssertingHttpClient::create(
23+
$this,
24+
[
25+
'GET',
26+
$expectedPath,
27+
'application/json',
28+
'',
29+
$responseCode,
30+
'application/json',
31+
$response,
32+
]
33+
);
34+
35+
// Create the object under test
36+
$api = new Group($client);
37+
38+
// Perform the tests
39+
$this->assertSame($expectedResponse, $api->listNames());
40+
}
41+
42+
public static function getListNamesData(): array
43+
{
44+
return [
45+
'test without groups' => [
46+
'/groups.json',
47+
201,
48+
<<<JSON
49+
{
50+
"groups": []
51+
}
52+
JSON,
53+
[]
54+
],
55+
'test with multiple groups' => [
56+
'/groups.json',
57+
201,
58+
<<<JSON
59+
{
60+
"groups": [
61+
{"id": 9, "name": "Group 1"},
62+
{"id": 8, "name": "Group 2"},
63+
{"id": 7, "name": "Group 3"}
64+
]
65+
}
66+
JSON,
67+
[
68+
9 => "Group 1",
69+
8 => "Group 2",
70+
7 => "Group 3",
71+
]
72+
],
73+
];
74+
}
75+
76+
public function testListNamesCallsHttpClientOnlyOnce()
77+
{
78+
$client = AssertingHttpClient::create(
79+
$this,
80+
[
81+
'GET',
82+
'/groups.json',
83+
'application/json',
84+
'',
85+
200,
86+
'application/json',
87+
<<<JSON
88+
{
89+
"groups": [
90+
{
91+
"id": 1,
92+
"name": "Group 1"
93+
}
94+
]
95+
}
96+
JSON,
97+
]
98+
);
99+
100+
// Create the object under test
101+
$api = new Group($client);
102+
103+
// Perform the tests
104+
$this->assertSame([1 => 'Group 1'], $api->listNames());
105+
$this->assertSame([1 => 'Group 1'], $api->listNames());
106+
$this->assertSame([1 => 'Group 1'], $api->listNames());
107+
}
108+
}

0 commit comments

Comments
 (0)