From 5316ab6f525ceba939ab32bbb406e46c40ab0efe Mon Sep 17 00:00:00 2001 From: Art4 Date: Wed, 20 Sep 2023 13:22:03 +0200 Subject: [PATCH 01/10] serializer are not internal anymore --- CHANGELOG.md | 3 +++ src/Redmine/Serializer/JsonSerializer.php | 2 -- src/Redmine/Serializer/PathSerializer.php | 2 -- src/Redmine/Serializer/XmlSerializer.php | 2 -- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a36c4a0..6a9bd10a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- New class `Redmine\Serializer\PathSerializer` to build an URL path with query parameters. +- New class `Redmine\Serializer\JsonSerializer` to encode or normalize JSON data. +- New class `Redmine\Serializer\XmlSerializer` to encode or normalize XML data. - Allow `Psr\Http\Message\ServerRequestFactoryInterface` as Argument #2 ($requestFactory) in `Redmine\Client\Psr18Client::__construct()` - Added support for PHP 8.2 diff --git a/src/Redmine/Serializer/JsonSerializer.php b/src/Redmine/Serializer/JsonSerializer.php index e8310997..348640eb 100644 --- a/src/Redmine/Serializer/JsonSerializer.php +++ b/src/Redmine/Serializer/JsonSerializer.php @@ -7,8 +7,6 @@ /** * JsonSerializer. - * - * @internal */ final class JsonSerializer { diff --git a/src/Redmine/Serializer/PathSerializer.php b/src/Redmine/Serializer/PathSerializer.php index 96320544..1f92fb82 100644 --- a/src/Redmine/Serializer/PathSerializer.php +++ b/src/Redmine/Serializer/PathSerializer.php @@ -4,8 +4,6 @@ /** * PathSerializer. - * - * @internal */ final class PathSerializer { diff --git a/src/Redmine/Serializer/XmlSerializer.php b/src/Redmine/Serializer/XmlSerializer.php index 1b130407..58a2cdf0 100644 --- a/src/Redmine/Serializer/XmlSerializer.php +++ b/src/Redmine/Serializer/XmlSerializer.php @@ -9,8 +9,6 @@ /** * XmlSerializer. - * - * @internal */ final class XmlSerializer { From 3165def687098c9bb41a8433a291d6d137532158 Mon Sep 17 00:00:00 2001 From: Art4 Date: Wed, 20 Sep 2023 13:32:05 +0200 Subject: [PATCH 02/10] add docs about mid-level und low-level API --- README.md | 22 +---------- docs/usage.md | 102 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 103 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 9a9a7866..1c3f98f8 100644 --- a/README.md +++ b/README.md @@ -15,26 +15,8 @@ Uses [Redmine API](http://www.redmine.org/projects/redmine/wiki/Rest_api/). * Choose between using native `cURL` function or any [PSR-18](https://www.php-fig.org/psr/psr-18/) http client like [Guzzle](https://github.com/guzzle/guzzle) for handling http connections -* API entry points implementation state: - * :heavy_check_mark: Attachments - * :heavy_check_mark: Groups - * :heavy_check_mark: Custom Fields - * :heavy_check_mark: Issues - * :heavy_check_mark: Issue Categories - * :heavy_check_mark: Issue Priorities - * :x: *Issue Relations - only partially implemented* - * :heavy_check_mark: Issue Statuses - * :heavy_check_mark: News - * :heavy_check_mark: Projects - * :heavy_check_mark: Project Memberships - * :heavy_check_mark: Queries - * :heavy_check_mark: Roles - * :heavy_check_mark: Time Entries - * :heavy_check_mark: Time Entry Activities - * :heavy_check_mark: Trackers - * :heavy_check_mark: Users - * :heavy_check_mark: Versions - * :heavy_check_mark: Wiki +* [mid-level API](https://github.com/kbsali/php-redmine-api/blob/v2.x/docs/usage.md#mid-level-api) e.g. `$client->getApi('issue')->create($data)` +* [low-level API](https://github.com/kbsali/php-redmine-api/blob/v2.x/docs/usage.md#low-level-api) e.g. `$client->requestPost('/issues.json', $data)` ## Todo diff --git a/docs/usage.md b/docs/usage.md index 6e41609d..64b0a1c1 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -217,7 +217,9 @@ try { ## API -You can now use the `getApi()` method to create and get a specific Redmine API. +### Mid-level API + +You can now use the `getApi()` method to create and get a specific Redmine API. This simplifies common use-cases and gives you some features like caching and assigning a user to an issue by username instead of the user ID. To check for failed requests you can afterwards check the status code via `$client->getLastResponseStatusCode()`. @@ -553,3 +555,101 @@ Array // Search $client->getApi('search')->search('Myproject', ['limit' => 100]); ``` + +#### API entry points implementation state: + +* :heavy_check_mark: Attachments +* :heavy_check_mark: Groups +* :heavy_check_mark: Custom Fields +* :heavy_check_mark: Issues +* :heavy_check_mark: Issue Categories +* :heavy_check_mark: Issue Priorities +* :x: *Issue Relations - only partially implemented* +* :heavy_check_mark: Issue Statuses +* :heavy_check_mark: News +* :heavy_check_mark: Projects +* :heavy_check_mark: Project Memberships +* :heavy_check_mark: Queries +* :heavy_check_mark: Roles +* :heavy_check_mark: Time Entries +* :heavy_check_mark: Time Entry Activities +* :heavy_check_mark: Trackers +* :heavy_check_mark: Users +* :heavy_check_mark: Versions +* :heavy_check_mark: Wiki + +If some features are missing in `getApi()` you are welcome to create a PR. Besides, it is always possible to use the low-level API. + +### Low-level API + +The low-level API allows you to send highly customized requests to the Redmine server. + +> :bulb: See the [Redmine REST-API docs](https://www.redmine.org/projects/redmine/wiki/Rest_api) for available endpoints and required parameters. + +The client has 4 methods for requests: + +- `requestGet()` +- `requestPost()` +- `requestPut()` +- `requestDelete()` + +Using this methods you can use every Redmine API endpoint. The following example shows you how to rename a project and add a custom field. To build the XML body you can use the `XmlSerializer`. + +```php +$client->requestPut( + '/projects/1.xml', + \Redmine\Serializer\XmlSerializer::createFromArray([ + 'project' => [ + 'name' => 'renamed project', + 'custom_fields' => [ + [ + 'id' => 123, + 'name' => 'cf_name', + 'field_format' => 'string', + 'value' => [1, 2, 3], + ], + ], + ] + ])->getEncoded() +); +``` + +> :bulb: Use `\Redmine\Serializer\JsonSerializer` if you want to use the JSON endpoint. + +Or to fetch data with complex query parameters you can use `requestGet()` with the `PathSerializer`: + +```php +$client->requestGet( + \Redmine\Serializer\PathSerializer::create( + '/time_entries.json', + [ + 'f' => ['spent_on'], + 'op' => ['spent_on' => '><'], + 'v' => [ + 'spent_on' => [ + '2016-01-18', + '2016-01-22', + ], + ], + ], + )->getPath() +); +``` + +After the request you can use these 3 methods to work with the response: + +- `getLastResponseStatusCode()` +- `getLastResponseContentType()` +- `getLastResponseBody()` + +To parse the response body from the last example to an array you can use `XmlSerializer`: + +```php +if ($client->getLastResponseStatusCode() === 200) { + $responseAsArray = \Redmine\Serializer\XmlSerializer::createFromString( + $client->getLastResponseBody() + )->getNormalized(); +} +``` + +> :bulb: Use `\Redmine\Serializer\JsonSerializer` if you have send the request as JSON. From 6d0a0596e8e1cbe979b4e82a48ae121e6f2353d4 Mon Sep 17 00:00:00 2001 From: Art4 Date: Wed, 20 Sep 2023 13:33:25 +0200 Subject: [PATCH 03/10] closing a project is possible since Redmine 5.0 --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 1c3f98f8..99f0bae8 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,6 @@ Uses [Redmine API](http://www.redmine.org/projects/redmine/wiki/Rest_api/). Redmine is missing some APIs for a full remote management of the data: * List of activities & roles: http://www.redmine.org/issues/11464 -* Closing a project: https://www.redmine.org/issues/13725 A possible solution to this would be to create an extra APIs implementing the missing entry points. See existing effort in doing so: From 50ad3d0bbbb587d5dd4f78bc9b58bddc5b33e546 Mon Sep 17 00:00:00 2001 From: Art4 Date: Wed, 20 Sep 2023 13:40:33 +0200 Subject: [PATCH 04/10] let serializer implements Stringable --- docs/usage.md | 8 ++++---- src/Redmine/Serializer/JsonSerializer.php | 8 +++++++- src/Redmine/Serializer/PathSerializer.php | 11 +++++++++-- src/Redmine/Serializer/XmlSerializer.php | 8 +++++++- 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index 64b0a1c1..bce2a34f 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -598,7 +598,7 @@ Using this methods you can use every Redmine API endpoint. The following example ```php $client->requestPut( '/projects/1.xml', - \Redmine\Serializer\XmlSerializer::createFromArray([ + (string) \Redmine\Serializer\XmlSerializer::createFromArray([ 'project' => [ 'name' => 'renamed project', 'custom_fields' => [ @@ -610,7 +610,7 @@ $client->requestPut( ], ], ] - ])->getEncoded() + ]) ); ``` @@ -620,7 +620,7 @@ Or to fetch data with complex query parameters you can use `requestGet()` with t ```php $client->requestGet( - \Redmine\Serializer\PathSerializer::create( + (string) \Redmine\Serializer\PathSerializer::create( '/time_entries.json', [ 'f' => ['spent_on'], @@ -632,7 +632,7 @@ $client->requestGet( ], ], ], - )->getPath() + ) ); ``` diff --git a/src/Redmine/Serializer/JsonSerializer.php b/src/Redmine/Serializer/JsonSerializer.php index 348640eb..eec287a4 100644 --- a/src/Redmine/Serializer/JsonSerializer.php +++ b/src/Redmine/Serializer/JsonSerializer.php @@ -4,11 +4,12 @@ use JsonException; use Redmine\Exception\SerializerException; +use Stringable; /** * JsonSerializer. */ -final class JsonSerializer +final class JsonSerializer implements Stringable { /** * @throws SerializerException if $data is not valid JSON @@ -55,6 +56,11 @@ public function getEncoded(): string return $this->encoded; } + public function __toString(): string + { + return $this->getEncoded(); + } + private function decode(string $encoded): void { $this->encoded = $encoded; diff --git a/src/Redmine/Serializer/PathSerializer.php b/src/Redmine/Serializer/PathSerializer.php index 1f92fb82..74df2f5b 100644 --- a/src/Redmine/Serializer/PathSerializer.php +++ b/src/Redmine/Serializer/PathSerializer.php @@ -2,10 +2,12 @@ namespace Redmine\Serializer; +use Stringable; + /** - * PathSerializer. + * PathSerializer to handle query parameters. */ -final class PathSerializer +final class PathSerializer implements Stringable { public static function create(string $path, array $queryParams = []): self { @@ -38,4 +40,9 @@ public function getPath(): string return $this->path.$queryString; } + + public function __toString(): string + { + return $this->getPath(); + } } diff --git a/src/Redmine/Serializer/XmlSerializer.php b/src/Redmine/Serializer/XmlSerializer.php index 58a2cdf0..c67bc3b8 100644 --- a/src/Redmine/Serializer/XmlSerializer.php +++ b/src/Redmine/Serializer/XmlSerializer.php @@ -5,12 +5,13 @@ use JsonException; use Redmine\Exception\SerializerException; use SimpleXMLElement; +use Stringable; use Throwable; /** * XmlSerializer. */ -final class XmlSerializer +final class XmlSerializer implements Stringable { /** * @throws SerializerException if $data is not valid XML @@ -59,6 +60,11 @@ public function getEncoded(): string return $this->encoded; } + public function __toString(): string + { + return $this->getEncoded(); + } + private function deserialize(string $encoded): void { $this->encoded = $encoded; From 225b50f0d429e7a60478ea2ab4d7a7251b80df9d Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 22 Sep 2023 13:44:17 +0200 Subject: [PATCH 05/10] update deprecation warnings --- CHANGELOG.md | 4 ++-- src/Redmine/Api/AbstractApi.php | 12 ++++++------ src/Redmine/Api/Project.php | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 266b4b71..163ff6b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,8 +18,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Deprecated - Providing Argument #2 ($requestFactory) in `Redmine\Client\Psr18Client::__construct()` as type `Psr\Http\Message\ServerRequestFactoryInterface` is deprecated, provide as type `Psr\Http\Message\RequestFactoryInterface` instead -- `Redmine\Api\AbstractApi::attachCustomFieldXML()` is deprecated -- `Redmine\Api\Project::prepareParamsXml()` is deprecated +- `Redmine\Api\AbstractApi::attachCustomFieldXML()` is deprecated, use `Redmine\Serializer\XmlSerializer::createFromArray()` instead +- `Redmine\Api\Project::prepareParamsXml()` is deprecated, use `Redmine\Serializer\XmlSerializer::createFromArray()` instead ## [v2.2.0](https://github.com/kbsali/php-redmine-api/compare/v2.1.1...v2.2.0) - 2022-03-01 diff --git a/src/Redmine/Api/AbstractApi.php b/src/Redmine/Api/AbstractApi.php index fc9cdde3..3a15ddf9 100644 --- a/src/Redmine/Api/AbstractApi.php +++ b/src/Redmine/Api/AbstractApi.php @@ -32,12 +32,12 @@ public function __construct(Client $client) * * @return bool * - * @deprecated This method does not correctly handle 2xx codes that are not 200 or 201, use \Redmine\Client\Client::getLastResponseStatusCode() instead + * @deprecated since v2.1.0, because it does not correctly handle 2xx codes that are not 200 or 201, use \Redmine\Client\Client::getLastResponseStatusCode() instead * @see Client::getLastResponseStatusCode() for checking the status code directly */ public function lastCallFailed() { - @trigger_error('The '.__METHOD__.' method is deprecated, use \Redmine\Client\Client::getLastResponseStatusCode() instead.', E_USER_DEPRECATED); + @trigger_error('`'.__METHOD__.'()` is deprecated since v2.1.0, use \Redmine\Client\Client::getLastResponseStatusCode() instead.', E_USER_DEPRECATED); $code = $this->client->getLastResponseStatusCode(); @@ -164,7 +164,7 @@ 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 + * @deprecated since v2.2.0, use `retrieveData()` instead * * @param string $endpoint API end point * @param array $params optional parameters to be passed to the api (offset, limit, ...) @@ -173,7 +173,7 @@ protected function sanitizeParams(array $defaults, array $params) */ protected function retrieveAll($endpoint, array $params = []) { - @trigger_error('The '.__METHOD__.' method is deprecated, use `retrieveData()` instead.', E_USER_DEPRECATED); + @trigger_error('`'.__METHOD__.'()` is deprecated since v2.2.0, use `retrieveData()` instead.', E_USER_DEPRECATED); try { $data = $this->retrieveData(strval($endpoint), $params); @@ -253,7 +253,7 @@ protected function retrieveData(string $endpoint, array $params = []): array /** * Attaches Custom Fields to a create/update query. * - * @deprecated the `attachCustomFieldXML()` method is deprecated. + * @deprecated since v2.3.0, use `\Redmine\Serializer\XmlSerializer::createFromArray()` instead * * @param SimpleXMLElement $xml XML Element the custom fields are attached to * @param array $fields array of fields to attach, each field needs name, id and value set @@ -264,7 +264,7 @@ protected function retrieveData(string $endpoint, array $params = []): array */ protected function attachCustomFieldXML(SimpleXMLElement $xml, array $fields) { - @trigger_error('The '.__METHOD__.' method is deprecated.', E_USER_DEPRECATED); + @trigger_error('`'.__METHOD__.'()` is deprecated since v2.3.0, use `\Redmine\Serializer\XmlSerializer::createFromArray()` instead.', E_USER_DEPRECATED); $_fields = $xml->addChild('custom_fields'); $_fields->addAttribute('type', 'array'); diff --git a/src/Redmine/Api/Project.php b/src/Redmine/Api/Project.php index 9b702343..e01000df 100755 --- a/src/Redmine/Api/Project.php +++ b/src/Redmine/Api/Project.php @@ -156,7 +156,7 @@ public function update($id, array $params) } /** - * @deprecated the `prepareParamsXml()` method is deprecated, use `\Redmine\Serializer\XmlSerializer::createFromArray()` instead. + * @deprecated since v2.3.0, use `\Redmine\Serializer\XmlSerializer::createFromArray()` instead. * * @param array $params * @@ -164,7 +164,7 @@ public function update($id, array $params) */ protected function prepareParamsXml($params) { - @trigger_error('The '.__METHOD__.' method is deprecated, use `\Redmine\Serializer\XmlSerializer::createFromArray()` instead.', E_USER_DEPRECATED); + @trigger_error('`'.__METHOD__.'()` is deprecated since v2.3.0, use `\Redmine\Serializer\XmlSerializer::createFromArray()` instead.', E_USER_DEPRECATED); return new \SimpleXMLElement( XmlSerializer::createFromArray(['project' => $params])->getEncoded() From e5d620fc81857c34a8752d544d91c2c5c4e7fb3e Mon Sep 17 00:00:00 2001 From: Art4 Date: Fri, 22 Sep 2023 14:45:15 +0200 Subject: [PATCH 06/10] Rearrange README.md --- README.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 99f0bae8..f0ac412d 100644 --- a/README.md +++ b/README.md @@ -15,22 +15,8 @@ Uses [Redmine API](http://www.redmine.org/projects/redmine/wiki/Rest_api/). * Choose between using native `cURL` function or any [PSR-18](https://www.php-fig.org/psr/psr-18/) http client like [Guzzle](https://github.com/guzzle/guzzle) for handling http connections -* [mid-level API](https://github.com/kbsali/php-redmine-api/blob/v2.x/docs/usage.md#mid-level-api) e.g. `$client->getApi('issue')->create($data)` -* [low-level API](https://github.com/kbsali/php-redmine-api/blob/v2.x/docs/usage.md#low-level-api) e.g. `$client->requestPost('/issues.json', $data)` - -## Todo - -* Check header's response code (especially for POST/PUT/DELETE requests) -* See http://stackoverflow.com/questions/9183178/php-curl-retrieving-response-headers-and-body-in-a-single-request/9183272#9183272 - -## Limitations / Missing Redmine-API - -Redmine is missing some APIs for a full remote management of the data: -* List of activities & roles: http://www.redmine.org/issues/11464 - -A possible solution to this would be to create an extra APIs implementing the -missing entry points. See existing effort in doing so: -https://github.com/rschobbert/redmine-miss-api +* [mid-level API](docs/usage.md#mid-level-api) e.g. `$client->getApi('issue')->create($data)` +* [low-level API](docs/usage.md#low-level-api) e.g. `$client->requestPost('/issues.json', $data)` ## Requirements @@ -46,6 +32,20 @@ https://github.com/rschobbert/redmine-miss-api * The PHP [cURL](http://php.net/manual/en/book.curl.php) extension if you want to use the native `cURL` functions. * [PHPUnit](https://phpunit.de/) >= 9.0 (optional) to run the test suite +## Todo + +* Check header's response code (especially for POST/PUT/DELETE requests) +* See http://stackoverflow.com/questions/9183178/php-curl-retrieving-response-headers-and-body-in-a-single-request/9183272#9183272 + +## Limitations / Missing Redmine-API + +Redmine is missing some APIs for a full remote management of the data: +* List of activities & roles: http://www.redmine.org/issues/11464 + +A possible solution to this would be to create an extra APIs implementing the +missing entry points. See existing effort in doing so: +https://github.com/rschobbert/redmine-miss-api + ## Install ### Composer From dd977254fc23e6c2843c3c3c789bd287b38653af Mon Sep 17 00:00:00 2001 From: Art4 Date: Wed, 27 Sep 2023 11:38:58 +0200 Subject: [PATCH 07/10] Add tests for Stringable implementation in Serializers --- tests/Unit/Serializer/JsonSerializerTest.php | 12 ++++-------- tests/Unit/Serializer/PathSerializerTest.php | 4 +++- tests/Unit/Serializer/XmlSerializerTest.php | 10 ++++------ 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/tests/Unit/Serializer/JsonSerializerTest.php b/tests/Unit/Serializer/JsonSerializerTest.php index 29e65fad..de9a2307 100644 --- a/tests/Unit/Serializer/JsonSerializerTest.php +++ b/tests/Unit/Serializer/JsonSerializerTest.php @@ -180,21 +180,17 @@ public static function getNormalizedToEncodedData(): array } /** + * @covers \Redmine\Serializer\JsonSerializer::getEncoded + * @covers \Redmine\Serializer\JsonSerializer::__toString * @test * * @dataProvider getNormalizedToEncodedData */ - public function createFromArrayDecodesToExpectedString(array $data, $expected) + public function createFromArrayEncodesToExpectedString(array $data, $expected) { $serializer = JsonSerializer::createFromArray($data); - // decode the result, so we encode again with JSON_PRETTY_PRINT to compare the formated output - $encoded = json_encode( - json_decode($serializer->getEncoded(), true, 512, \JSON_THROW_ON_ERROR), - \JSON_THROW_ON_ERROR | \JSON_PRETTY_PRINT - ); - - $this->assertSame($expected, $encoded); + $this->assertJsonStringEqualsJsonString($expected, $serializer->__toString()); } public static function getInvalidSerializedData(): array diff --git a/tests/Unit/Serializer/PathSerializerTest.php b/tests/Unit/Serializer/PathSerializerTest.php index 444403dc..439a4e84 100644 --- a/tests/Unit/Serializer/PathSerializerTest.php +++ b/tests/Unit/Serializer/PathSerializerTest.php @@ -48,6 +48,8 @@ public static function getPathData(): array } /** + * @covers \Redmine\Serializer\PathSerializer::getPath + * @covers \Redmine\Serializer\PathSerializer::__toString * @test * * @dataProvider getPathData @@ -56,6 +58,6 @@ public function getPathShouldReturnExpectedString(string $path, array $params, s { $serializer = PathSerializer::create($path, $params); - $this->assertSame($expected, $serializer->getPath()); + $this->assertSame($expected, $serializer->__toString()); } } diff --git a/tests/Unit/Serializer/XmlSerializerTest.php b/tests/Unit/Serializer/XmlSerializerTest.php index 3e547955..1fbdf49b 100644 --- a/tests/Unit/Serializer/XmlSerializerTest.php +++ b/tests/Unit/Serializer/XmlSerializerTest.php @@ -186,19 +186,17 @@ public static function getNormalizedToEncodedData(): array } /** + * @covers \Redmine\Serializer\XmlSerializer::getEncoded + * @covers \Redmine\Serializer\XmlSerializer::__toString * @test * * @dataProvider getNormalizedToEncodedData */ - public function createFromArrayDecodesToExpectedString(array $data, $expected) + public function createFromArrayEncodesToExpectedString(array $data, $expected) { $serializer = XmlSerializer::createFromArray($data); - // Load the encoded string into a DOMDocument, so we can compare the formated output - $dom = dom_import_simplexml(new \SimpleXMLElement($serializer->getEncoded()))->ownerDocument; - $dom->formatOutput = true; - - $this->assertSame($expected, trim($dom->saveXML())); + $this->assertXmlStringEqualsXmlString($expected, $serializer->__toString()); } public static function getInvalidSerializedData(): array From 63504c1bbe7dae09128f74d1b81f6177de1983fc Mon Sep 17 00:00:00 2001 From: Art4 Date: Wed, 27 Sep 2023 12:43:26 +0200 Subject: [PATCH 08/10] Add tests for deprecated retrieveAll method --- tests/Unit/Api/AbstractApiTest.php | 34 ++++++++++++++++++------------ 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/tests/Unit/Api/AbstractApiTest.php b/tests/Unit/Api/AbstractApiTest.php index d959e1e3..785c74b0 100644 --- a/tests/Unit/Api/AbstractApiTest.php +++ b/tests/Unit/Api/AbstractApiTest.php @@ -2,7 +2,6 @@ namespace Redmine\Tests\Unit\Api; -use DOMDocument; use PHPUnit\Framework\TestCase; use Redmine\Api\AbstractApi; use Redmine\Client\Client; @@ -180,16 +179,6 @@ public static function getJsonDecodingFromGetMethodData(): array */ public function testXmlDecodingFromRequestMethods($methodName, $response, $decode, $expected) { - $xmlToString = function (SimpleXMLElement $xmlElement) { - $dom = new DOMDocument('1.0'); - $dom->preserveWhiteSpace = false; - $dom->formatOutput = false; - $dom->loadXML($xmlElement->asXML()); - - // Remove line breaks - return preg_replace("/\r|\n/", '', $dom->saveXML()); - }; - $client = $this->createMock(Client::class); $client->method('getLastResponseBody')->willReturn($response); $client->method('getLastResponseContentType')->willReturn('application/xml'); @@ -204,7 +193,7 @@ public function testXmlDecodingFromRequestMethods($methodName, $response, $decod $return = $method->invoke($api, 'path', $decode); $this->assertInstanceOf(SimpleXMLElement::class, $return); - $this->assertSame($expected, $xmlToString($return)); + $this->assertXmlStringEqualsXmlString($expected, $return->asXML()); } elseif ('delete' === $methodName) { $return = $method->invoke($api, 'path'); @@ -213,7 +202,7 @@ public function testXmlDecodingFromRequestMethods($methodName, $response, $decod $return = $method->invoke($api, 'path', ''); $this->assertInstanceOf(SimpleXMLElement::class, $return); - $this->assertSame($expected, $xmlToString($return)); + $this->assertXmlStringEqualsXmlString($expected, $return->asXML()); } } @@ -228,4 +217,23 @@ public static function getXmlDecodingFromGetMethodData(): array ['delete', '', null, ''], ]; } + + /** + * @covers \Redmine\Api\AbstractApi::retrieveAll + */ + public function testDeprecatedRetrieveAll() + { + $client = $this->createMock(Client::class); + $client->method('requestGet')->willReturn(true); + $client->method('getLastResponseBody')->willReturn(''); + $client->method('getLastResponseContentType')->willReturn('application/xml'); + + $api = $this->getMockForAbstractClass(AbstractApi::class, [$client]); + + $method = new ReflectionMethod($api, 'retrieveAll'); + $method->setAccessible(true); + + $this->assertSame([], $method->invoke($api, '/issues.xml')); + + } } From c1f682318930ec9e9b812fad2595c4e0187f3a4c Mon Sep 17 00:00:00 2001 From: Art4 Date: Wed, 27 Sep 2023 12:53:14 +0200 Subject: [PATCH 09/10] Add test for deprecated attachCustomFieldXML method --- tests/Unit/Api/AbstractApiTest.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/Unit/Api/AbstractApiTest.php b/tests/Unit/Api/AbstractApiTest.php index 785c74b0..0c186115 100644 --- a/tests/Unit/Api/AbstractApiTest.php +++ b/tests/Unit/Api/AbstractApiTest.php @@ -236,4 +236,21 @@ public function testDeprecatedRetrieveAll() $this->assertSame([], $method->invoke($api, '/issues.xml')); } + + /** + * @covers \Redmine\Api\AbstractApi::attachCustomFieldXML + */ + public function testDeprecatedAttachCustomFieldXML() + { + $client = $this->createMock(Client::class); + + $api = $this->getMockForAbstractClass(AbstractApi::class, [$client]); + + $method = new ReflectionMethod($api, 'attachCustomFieldXML'); + $method->setAccessible(true); + + $xml = new SimpleXMLElement(''); + + $this->assertInstanceOf(SimpleXMLElement::class, $method->invoke($api, $xml, [])); + } } From bcabc7044f86485eabfa579b9a06901e000d0ef7 Mon Sep 17 00:00:00 2001 From: Art4 Date: Wed, 27 Sep 2023 13:00:49 +0200 Subject: [PATCH 10/10] Add test for Project::prepareParamsXml() --- tests/Unit/Api/ProjectTest.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/Unit/Api/ProjectTest.php b/tests/Unit/Api/ProjectTest.php index afd51803..0180c80d 100644 --- a/tests/Unit/Api/ProjectTest.php +++ b/tests/Unit/Api/ProjectTest.php @@ -6,6 +6,8 @@ use Redmine\Api\Project; use Redmine\Client\Client; use Redmine\Exception\MissingParameterException; +use ReflectionMethod; +use SimpleXMLElement; /** * @coversDefaultClass \Redmine\Api\Project @@ -534,4 +536,19 @@ public function testUpdateCallsPut() // Perform the tests $this->assertSame($response, $api->update(5, $parameters)); } + + /** + * @covers \Redmine\Api\Project::prepareParamsXml + */ + public function testDeprecatedPrepareParamsXml() + { + $client = $this->createMock(Client::class); + + $api = new Project($client); + + $method = new ReflectionMethod($api, 'prepareParamsXml'); + $method->setAccessible(true); + + $this->assertInstanceOf(SimpleXMLElement::class, $method->invoke($api, ['id' => 1])); + } }