Skip to content

Commit 2b7cfcd

Browse files
authored
Merge pull request #324 from Art4/documentation-for-low-level-api
Introducing the low-level API
2 parents 8665629 + bcabc70 commit 2b7cfcd

13 files changed

+219
-84
lines changed

CHANGELOG.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12+
- New class `Redmine\Serializer\PathSerializer` to build an URL path with query parameters.
13+
- New class `Redmine\Serializer\JsonSerializer` to encode or normalize JSON data.
14+
- New class `Redmine\Serializer\XmlSerializer` to encode or normalize XML data.
1215
- Allow `Psr\Http\Message\RequestFactoryInterface` as Argument #2 ($requestFactory) in `Redmine\Client\Psr18Client::__construct()`
1316
- Added support for PHP 8.2
1417

1518
### Deprecated
1619

1720
- 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
18-
- `Redmine\Api\AbstractApi::attachCustomFieldXML()` is deprecated
19-
- `Redmine\Api\Project::prepareParamsXml()` is deprecated
21+
- `Redmine\Api\AbstractApi::attachCustomFieldXML()` is deprecated, use `Redmine\Serializer\XmlSerializer::createFromArray()` instead
22+
- `Redmine\Api\Project::prepareParamsXml()` is deprecated, use `Redmine\Serializer\XmlSerializer::createFromArray()` instead
2023

2124
## [v2.2.0](https://github.com/kbsali/php-redmine-api/compare/v2.1.1...v2.2.0) - 2022-03-01
2225

README.md

Lines changed: 16 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,41 +15,8 @@ Uses [Redmine API](http://www.redmine.org/projects/redmine/wiki/Rest_api/).
1515
* Choose between using native `cURL` function or any
1616
[PSR-18](https://www.php-fig.org/psr/psr-18/) http client like
1717
[Guzzle](https://github.com/guzzle/guzzle) for handling http connections
18-
* API entry points implementation state:
19-
* :heavy_check_mark: Attachments
20-
* :heavy_check_mark: Groups
21-
* :heavy_check_mark: Custom Fields
22-
* :heavy_check_mark: Issues
23-
* :heavy_check_mark: Issue Categories
24-
* :heavy_check_mark: Issue Priorities
25-
* :x: *Issue Relations - only partially implemented*
26-
* :heavy_check_mark: Issue Statuses
27-
* :heavy_check_mark: News
28-
* :heavy_check_mark: Projects
29-
* :heavy_check_mark: Project Memberships
30-
* :heavy_check_mark: Queries
31-
* :heavy_check_mark: Roles
32-
* :heavy_check_mark: Time Entries
33-
* :heavy_check_mark: Time Entry Activities
34-
* :heavy_check_mark: Trackers
35-
* :heavy_check_mark: Users
36-
* :heavy_check_mark: Versions
37-
* :heavy_check_mark: Wiki
38-
39-
## Todo
40-
41-
* Check header's response code (especially for POST/PUT/DELETE requests)
42-
* See http://stackoverflow.com/questions/9183178/php-curl-retrieving-response-headers-and-body-in-a-single-request/9183272#9183272
43-
44-
## Limitations / Missing Redmine-API
45-
46-
Redmine is missing some APIs for a full remote management of the data:
47-
* List of activities & roles: http://www.redmine.org/issues/11464
48-
* Closing a project: https://www.redmine.org/issues/13725
49-
50-
A possible solution to this would be to create an extra APIs implementing the
51-
missing entry points. See existing effort in doing so:
52-
https://github.com/rschobbert/redmine-miss-api
18+
* [mid-level API](docs/usage.md#mid-level-api) e.g. `$client->getApi('issue')->create($data)`
19+
* [low-level API](docs/usage.md#low-level-api) e.g. `$client->requestPost('/issues.json', $data)`
5320

5421
## Requirements
5522

@@ -65,6 +32,20 @@ https://github.com/rschobbert/redmine-miss-api
6532
* The PHP [cURL](http://php.net/manual/en/book.curl.php) extension if you want to use the native `cURL` functions.
6633
* [PHPUnit](https://phpunit.de/) >= 9.0 (optional) to run the test suite
6734

35+
## Todo
36+
37+
* Check header's response code (especially for POST/PUT/DELETE requests)
38+
* See http://stackoverflow.com/questions/9183178/php-curl-retrieving-response-headers-and-body-in-a-single-request/9183272#9183272
39+
40+
## Limitations / Missing Redmine-API
41+
42+
Redmine is missing some APIs for a full remote management of the data:
43+
* List of activities & roles: http://www.redmine.org/issues/11464
44+
45+
A possible solution to this would be to create an extra APIs implementing the
46+
missing entry points. See existing effort in doing so:
47+
https://github.com/rschobbert/redmine-miss-api
48+
6849
## Install
6950

7051
### Composer

docs/usage.md

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,9 @@ try {
217217

218218
## API
219219

220-
You can now use the `getApi()` method to create and get a specific Redmine API.
220+
### Mid-level API
221+
222+
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.
221223

222224
To check for failed requests you can afterwards check the status code via `$client->getLastResponseStatusCode()`.
223225

@@ -553,3 +555,101 @@ Array
553555
// Search
554556
$client->getApi('search')->search('Myproject', ['limit' => 100]);
555557
```
558+
559+
#### API entry points implementation state:
560+
561+
* :heavy_check_mark: Attachments
562+
* :heavy_check_mark: Groups
563+
* :heavy_check_mark: Custom Fields
564+
* :heavy_check_mark: Issues
565+
* :heavy_check_mark: Issue Categories
566+
* :heavy_check_mark: Issue Priorities
567+
* :x: *Issue Relations - only partially implemented*
568+
* :heavy_check_mark: Issue Statuses
569+
* :heavy_check_mark: News
570+
* :heavy_check_mark: Projects
571+
* :heavy_check_mark: Project Memberships
572+
* :heavy_check_mark: Queries
573+
* :heavy_check_mark: Roles
574+
* :heavy_check_mark: Time Entries
575+
* :heavy_check_mark: Time Entry Activities
576+
* :heavy_check_mark: Trackers
577+
* :heavy_check_mark: Users
578+
* :heavy_check_mark: Versions
579+
* :heavy_check_mark: Wiki
580+
581+
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.
582+
583+
### Low-level API
584+
585+
The low-level API allows you to send highly customized requests to the Redmine server.
586+
587+
> :bulb: See the [Redmine REST-API docs](https://www.redmine.org/projects/redmine/wiki/Rest_api) for available endpoints and required parameters.
588+
589+
The client has 4 methods for requests:
590+
591+
- `requestGet()`
592+
- `requestPost()`
593+
- `requestPut()`
594+
- `requestDelete()`
595+
596+
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`.
597+
598+
```php
599+
$client->requestPut(
600+
'/projects/1.xml',
601+
(string) \Redmine\Serializer\XmlSerializer::createFromArray([
602+
'project' => [
603+
'name' => 'renamed project',
604+
'custom_fields' => [
605+
[
606+
'id' => 123,
607+
'name' => 'cf_name',
608+
'field_format' => 'string',
609+
'value' => [1, 2, 3],
610+
],
611+
],
612+
]
613+
])
614+
);
615+
```
616+
617+
> :bulb: Use `\Redmine\Serializer\JsonSerializer` if you want to use the JSON endpoint.
618+
619+
Or to fetch data with complex query parameters you can use `requestGet()` with the `PathSerializer`:
620+
621+
```php
622+
$client->requestGet(
623+
(string) \Redmine\Serializer\PathSerializer::create(
624+
'/time_entries.json',
625+
[
626+
'f' => ['spent_on'],
627+
'op' => ['spent_on' => '><'],
628+
'v' => [
629+
'spent_on' => [
630+
'2016-01-18',
631+
'2016-01-22',
632+
],
633+
],
634+
],
635+
)
636+
);
637+
```
638+
639+
After the request you can use these 3 methods to work with the response:
640+
641+
- `getLastResponseStatusCode()`
642+
- `getLastResponseContentType()`
643+
- `getLastResponseBody()`
644+
645+
To parse the response body from the last example to an array you can use `XmlSerializer`:
646+
647+
```php
648+
if ($client->getLastResponseStatusCode() === 200) {
649+
$responseAsArray = \Redmine\Serializer\XmlSerializer::createFromString(
650+
$client->getLastResponseBody()
651+
)->getNormalized();
652+
}
653+
```
654+
655+
> :bulb: Use `\Redmine\Serializer\JsonSerializer` if you have send the request as JSON.

src/Redmine/Api/AbstractApi.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ public function __construct(Client $client)
3232
*
3333
* @return bool
3434
*
35-
* @deprecated This method does not correctly handle 2xx codes that are not 200 or 201, use \Redmine\Client\Client::getLastResponseStatusCode() instead
35+
* @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
3636
* @see Client::getLastResponseStatusCode() for checking the status code directly
3737
*/
3838
public function lastCallFailed()
3939
{
40-
@trigger_error('The '.__METHOD__.' method is deprecated, use \Redmine\Client\Client::getLastResponseStatusCode() instead.', E_USER_DEPRECATED);
40+
@trigger_error('`'.__METHOD__.'()` is deprecated since v2.1.0, use \Redmine\Client\Client::getLastResponseStatusCode() instead.', E_USER_DEPRECATED);
4141

4242
$code = $this->client->getLastResponseStatusCode();
4343

@@ -164,7 +164,7 @@ protected function sanitizeParams(array $defaults, array $params)
164164
* Retrieves all the elements of a given endpoint (even if the
165165
* total number of elements is greater than 100).
166166
*
167-
* @deprecated the `retrieveAll()` method is deprecated, use `retrieveData()` instead
167+
* @deprecated since v2.2.0, use `retrieveData()` instead
168168
*
169169
* @param string $endpoint API end point
170170
* @param array $params optional parameters to be passed to the api (offset, limit, ...)
@@ -173,7 +173,7 @@ protected function sanitizeParams(array $defaults, array $params)
173173
*/
174174
protected function retrieveAll($endpoint, array $params = [])
175175
{
176-
@trigger_error('The '.__METHOD__.' method is deprecated, use `retrieveData()` instead.', E_USER_DEPRECATED);
176+
@trigger_error('`'.__METHOD__.'()` is deprecated since v2.2.0, use `retrieveData()` instead.', E_USER_DEPRECATED);
177177

178178
try {
179179
$data = $this->retrieveData(strval($endpoint), $params);
@@ -253,7 +253,7 @@ protected function retrieveData(string $endpoint, array $params = []): array
253253
/**
254254
* Attaches Custom Fields to a create/update query.
255255
*
256-
* @deprecated the `attachCustomFieldXML()` method is deprecated.
256+
* @deprecated since v2.3.0, use `\Redmine\Serializer\XmlSerializer::createFromArray()` instead
257257
*
258258
* @param SimpleXMLElement $xml XML Element the custom fields are attached to
259259
* @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
264264
*/
265265
protected function attachCustomFieldXML(SimpleXMLElement $xml, array $fields)
266266
{
267-
@trigger_error('The '.__METHOD__.' method is deprecated.', E_USER_DEPRECATED);
267+
@trigger_error('`'.__METHOD__.'()` is deprecated since v2.3.0, use `\Redmine\Serializer\XmlSerializer::createFromArray()` instead.', E_USER_DEPRECATED);
268268

269269
$_fields = $xml->addChild('custom_fields');
270270
$_fields->addAttribute('type', 'array');

src/Redmine/Api/Project.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,15 +156,15 @@ public function update($id, array $params)
156156
}
157157

158158
/**
159-
* @deprecated the `prepareParamsXml()` method is deprecated, use `\Redmine\Serializer\XmlSerializer::createFromArray()` instead.
159+
* @deprecated since v2.3.0, use `\Redmine\Serializer\XmlSerializer::createFromArray()` instead.
160160
*
161161
* @param array $params
162162
*
163163
* @return \SimpleXMLElement
164164
*/
165165
protected function prepareParamsXml($params)
166166
{
167-
@trigger_error('The '.__METHOD__.' method is deprecated, use `\Redmine\Serializer\XmlSerializer::createFromArray()` instead.', E_USER_DEPRECATED);
167+
@trigger_error('`'.__METHOD__.'()` is deprecated since v2.3.0, use `\Redmine\Serializer\XmlSerializer::createFromArray()` instead.', E_USER_DEPRECATED);
168168

169169
return new \SimpleXMLElement(
170170
XmlSerializer::createFromArray(['project' => $params])->getEncoded()

src/Redmine/Serializer/JsonSerializer.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@
44

55
use JsonException;
66
use Redmine\Exception\SerializerException;
7+
use Stringable;
78

89
/**
910
* JsonSerializer.
10-
*
11-
* @internal
1211
*/
13-
final class JsonSerializer
12+
final class JsonSerializer implements Stringable
1413
{
1514
/**
1615
* @throws SerializerException if $data is not valid JSON
@@ -57,6 +56,11 @@ public function getEncoded(): string
5756
return $this->encoded;
5857
}
5958

59+
public function __toString(): string
60+
{
61+
return $this->getEncoded();
62+
}
63+
6064
private function decode(string $encoded): void
6165
{
6266
$this->encoded = $encoded;

src/Redmine/Serializer/PathSerializer.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22

33
namespace Redmine\Serializer;
44

5+
use Stringable;
6+
57
/**
6-
* PathSerializer.
7-
*
8-
* @internal
8+
* PathSerializer to handle query parameters.
99
*/
10-
final class PathSerializer
10+
final class PathSerializer implements Stringable
1111
{
1212
public static function create(string $path, array $queryParams = []): self
1313
{
@@ -40,4 +40,9 @@ public function getPath(): string
4040

4141
return $this->path.$queryString;
4242
}
43+
44+
public function __toString(): string
45+
{
46+
return $this->getPath();
47+
}
4348
}

src/Redmine/Serializer/XmlSerializer.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55
use JsonException;
66
use Redmine\Exception\SerializerException;
77
use SimpleXMLElement;
8+
use Stringable;
89
use Throwable;
910

1011
/**
1112
* XmlSerializer.
12-
*
13-
* @internal
1413
*/
15-
final class XmlSerializer
14+
final class XmlSerializer implements Stringable
1615
{
1716
/**
1817
* @throws SerializerException if $data is not valid XML
@@ -61,6 +60,11 @@ public function getEncoded(): string
6160
return $this->encoded;
6261
}
6362

63+
public function __toString(): string
64+
{
65+
return $this->getEncoded();
66+
}
67+
6468
private function deserialize(string $encoded): void
6569
{
6670
$this->encoded = $encoded;

0 commit comments

Comments
 (0)