diff --git a/CHANGELOG.md b/CHANGELOG.md index b694b5d2..d75c3fa5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - New method `Redmine\Api\IssueCategory::listNamesByProject()` for listing the ids and names of all issue categories of a project. - New method `Redmine\Api\IssueStatus::listNames()` for listing the ids and names of all issue statuses. - New method `Redmine\Api\Project::listNames()` for listing the ids and names of all projects. +- New method `Redmine\Api\Role::listNames()` for listing the ids and names of all roles. ### Deprecated @@ -22,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `Redmine\Api\IssueCategory::listing()` is deprecated, use `\Redmine\Api\IssueCategory::listNamesByProject()` instead. - `Redmine\Api\IssueStatus::listing()` is deprecated, use `\Redmine\Api\IssueStatus::listNamesByProject()` instead. - `Redmine\Api\Project::listing()` is deprecated, use `\Redmine\Api\Project::listNamesByProject()` instead. +- `Redmine\Api\Role::listing()` is deprecated, use `\Redmine\Api\Role::listNamesByProject()` instead. ## [v2.6.0](https://github.com/kbsali/php-redmine-api/compare/v2.5.0...v2.6.0) - 2024-03-25 diff --git a/src/Redmine/Api/Role.php b/src/Redmine/Api/Role.php index b70c1e53..57ae428f 100644 --- a/src/Redmine/Api/Role.php +++ b/src/Redmine/Api/Role.php @@ -19,6 +19,8 @@ class Role extends AbstractApi { private $roles = []; + private $roleNames = null; + /** * List roles. * @@ -39,6 +41,29 @@ final public function list(array $params = []): array } } + /** + * Returns an array of all roles with id/name pairs. + * + * @return array list of roles (id => name) + */ + final public function listNames(): array + { + if ($this->roleNames !== null) { + return $this->roleNames; + } + + $this->roleNames = []; + $list = $this->list(); + + if (array_key_exists('roles', $list)) { + foreach ($list['roles'] as $role) { + $this->roleNames[(int) $role['id']] = $role['name']; + } + } + + return $this->roleNames; + } + /** * List roles. * @@ -75,12 +100,17 @@ public function all(array $params = []) /** * Returns an array of roles with name/id pairs. * + * @deprecated v2.7.0 Use listNames() instead. + * @see Role::listNames() + * * @param bool $forceUpdate to force the update of the roles var * * @return array list of roles (id => name) */ public function listing($forceUpdate = false) { + @trigger_error('`' . __METHOD__ . '()` is deprecated since v2.7.0, use `' . __CLASS__ . '::listNames()` instead.', E_USER_DEPRECATED); + if (empty($this->roles) || $forceUpdate) { $this->roles = $this->list(); } diff --git a/tests/Behat/Bootstrap/RoleContextTrait.php b/tests/Behat/Bootstrap/RoleContextTrait.php index 3980a6e5..c320dcbf 100644 --- a/tests/Behat/Bootstrap/RoleContextTrait.php +++ b/tests/Behat/Bootstrap/RoleContextTrait.php @@ -4,6 +4,8 @@ namespace Redmine\Tests\Behat\Bootstrap; +use Redmine\Api\Role; + trait RoleContextTrait { /** @@ -28,4 +30,32 @@ public function iHaveARoleWithTheName($name) ], ); } + + /** + * @When I list all roles + */ + public function iListAllRoles() + { + /** @var Role */ + $api = $this->getNativeCurlClient()->getApi('role'); + + $this->registerClientResponse( + $api->list(), + $api->getLastResponse(), + ); + } + + /** + * @When I list all role names + */ + public function iListAllRoleNames() + { + /** @var Role */ + $api = $this->getNativeCurlClient()->getApi('role'); + + $this->registerClientResponse( + $api->listNames(), + $api->getLastResponse(), + ); + } } diff --git a/tests/Behat/features/role.feature b/tests/Behat/features/role.feature new file mode 100644 index 00000000..533f767f --- /dev/null +++ b/tests/Behat/features/role.feature @@ -0,0 +1,55 @@ +@role +Feature: Interacting with the REST API for roles + In order to interact with REST API for roles + As a user + I want to make sure the Redmine server replies with the correct response + + Scenario: Listing of zero roles + Given I have a "NativeCurlClient" client + When I list all roles + Then the response has the status code "200" + And the response has the content type "application/json" + And the returned data has only the following properties + """ + roles + """ + And the returned data "roles" property is an array + And the returned data "roles" property contains "0" items + + Scenario: Listing of multiple roles + Given I have a "NativeCurlClient" client + And I have a role with the name "Reporter" + And I have a role with the name "Developer" + When I list all roles + Then the response has the status code "200" + And the response has the content type "application/json" + And the returned data has only the following properties + """ + roles + """ + And the returned data "roles" property is an array + And the returned data "roles" property contains "2" items + And the returned data "roles.0" property contains "2" items + And the returned data "roles.0" property contains the following data + | property | value | + | id | 3 | + | name | Reporter | + And the returned data "roles.1" property contains "2" items + And the returned data "roles.1" property contains the following data + | property | value | + | id | 4 | + | name | Developer | + + Scenario: Listing of multiple role names + Given I have a "NativeCurlClient" client + And I have a role with the name "Reporter" + And I have a role with the name "Developer" + When I list all role names + Then the response has the status code "200" + And the response has the content type "application/json" + And the returned data is an array + And the returned data contains "2" items + And the returned data contains the following data + | property | value | + | 3 | Reporter | + | 4 | Developer | diff --git a/tests/Unit/Api/Role/ListNamesTest.php b/tests/Unit/Api/Role/ListNamesTest.php new file mode 100644 index 00000000..769671c3 --- /dev/null +++ b/tests/Unit/Api/Role/ListNamesTest.php @@ -0,0 +1,108 @@ +assertSame($expectedResponse, $api->listNames()); + } + + public static function getListNamesData(): array + { + return [ + 'test without roles' => [ + '/roles.json', + 201, + << [ + '/roles.json', + 201, + << "Role 3", + 8 => "Role 2", + 9 => "Role 1", + ], + ], + ]; + } + + public function testListNamesCallsHttpClientOnlyOnce() + { + $client = AssertingHttpClient::create( + $this, + [ + 'GET', + '/roles.json', + 'application/json', + '', + 200, + 'application/json', + <<assertSame([1 => 'Role 1'], $api->listNames()); + $this->assertSame([1 => 'Role 1'], $api->listNames()); + $this->assertSame([1 => 'Role 1'], $api->listNames()); + } +} diff --git a/tests/Unit/Api/RoleTest.php b/tests/Unit/Api/RoleTest.php index 53bebefc..208b3c5d 100644 --- a/tests/Unit/Api/RoleTest.php +++ b/tests/Unit/Api/RoleTest.php @@ -214,4 +214,36 @@ public function testListingCallsGetEveryTimeWithForceUpdate() $this->assertSame($expectedReturn, $api->listing(true)); $this->assertSame($expectedReturn, $api->listing(true)); } + + /** + * Test listing(). + */ + public function testListingTriggersDeprecationWarning() + { + $client = $this->createMock(Client::class); + $client->method('requestGet') + ->willReturn(true); + $client->method('getLastResponseBody') + ->willReturn('{"roles":[{"id":1,"name":"Role 1"},{"id":5,"name":"Role 5"}]}'); + $client->method('getLastResponseContentType') + ->willReturn('application/json'); + + $api = new Role($client); + + // PHPUnit 10 compatible way to test trigger_error(). + set_error_handler( + function ($errno, $errstr): bool { + $this->assertSame( + '`Redmine\Api\Role::listing()` is deprecated since v2.7.0, use `Redmine\Api\Role::listNames()` instead.', + $errstr, + ); + + restore_error_handler(); + return true; + }, + E_USER_DEPRECATED, + ); + + $api->listing(); + } }