Skip to content

Commit 8574a92

Browse files
authored
Typed properties and bump to PHP 7.4 (#261) @Art4
* bump min PHP version tp 7.4 so we can use typed properties * Use typed properties in Psr18Client * Use typed properties in Client * Fix line ending test on windows machine * Improve AbstractApi * Update CHANGELOG.md * Update README.md * Fix date in CHANGELOG.md
1 parent 39285b0 commit 8574a92

22 files changed

+103
-177
lines changed

.travis.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
language: php
22

33
php:
4-
- 7.3
54
- 7.4
65
- 8.0
76

CHANGELOG.md

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

1212
- This `CHANGELOG.md` file
1313

14+
### Changed
15+
16+
- Better type checking thanks to typed properties
17+
- Move `example.php` into new `docs` folder
18+
19+
### Removed
20+
21+
- Drop support for PHP 7.3
22+
23+
### Fixed
24+
25+
- `Redmine\Client::getCheckSslHost()` always returns as boolean
26+
1427
## [v1.7.0](https://github.com/kbsali/php-redmine-api/compare/v1.6.0...v1.7.0) - 2021-03-22
1528

1629
### Added
@@ -49,7 +62,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4962

5063
- Removed support for PHP 5.6, 7.0, 7.1 and 7.2
5164

52-
## [v1.5.22](https://github.com/kbsali/php-redmine-api/compare/v1.5.21...v1.5.22) - 2021-01-02
65+
## [v1.5.22](https://github.com/kbsali/php-redmine-api/compare/v1.5.21...v1.5.22) - 2020-08-07
5366

5467
### Added
5568

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ A possible solution to this would be to create an extra APIs implementing the mi
4545

4646
## Requirements
4747

48-
* PHP ^7.3 || ^8.0
48+
* PHP ^7.4 || ^8.0
4949
* The PHP [cURL](http://php.net/manual/en/book.curl.php) extension
5050
* The PHP [SimpleXML](http://php.net/manual/en/book.simplexml.php) extension
5151
* The PHP [JSON](http://php.net/manual/en/book.json.php) extension

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
}
1717
],
1818
"require": {
19-
"php": "^7.3 || ^8.0",
19+
"php": "^7.4 || ^8.0",
2020
"ext-curl": "*",
2121
"ext-simplexml": "*",
2222
"ext-json": "*",

src/Redmine/Api/AbstractApi.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,14 @@ protected function get($path, $decodeIfJson = true)
4949
$this->client->requestGet($path);
5050

5151
$body = $this->client->getLastResponseBody();
52+
$contentType = $this->client->getLastResponseContentType();
5253

5354
// if response is XML, return a SimpleXMLElement object
54-
if ($body !== '' && 0 === strpos($this->client->getLastResponseContentType(), 'application/xml')) {
55+
if ($body !== '' && 0 === strpos($contentType, 'application/xml')) {
5556
return new SimpleXMLElement($body);
5657
}
5758

58-
if ($decodeIfJson === true && $body !== '' && 0 === strpos($this->client->getLastResponseContentType(), 'application/json')) {
59+
if ($decodeIfJson === true && $body !== '' && 0 === strpos($contentType, 'application/json')) {
5960
try {
6061
return json_decode($body, true, 512, \JSON_THROW_ON_ERROR);
6162
} catch (JsonException $e) {

src/Redmine/Client.php

Lines changed: 20 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -42,53 +42,23 @@ class Client implements ClientInterface
4242
*/
4343
const SSL_VERIFYHOST = 2;
4444

45-
/**
46-
* @var array
47-
*/
48-
private static $defaultPorts = [
45+
private static array $defaultPorts = [
4946
'http' => 80,
5047
'https' => 443,
5148
];
5249

53-
/**
54-
* @var int
55-
*/
56-
private $port;
57-
58-
/**
59-
* @var string
60-
*/
61-
private $url;
62-
63-
/**
64-
* @var string
65-
*/
66-
private $apikeyOrUsername;
67-
68-
/**
69-
* @var string|null
70-
*/
71-
private $pass;
72-
73-
/**
74-
* @var bool
75-
*/
76-
private $checkSslCertificate = false;
77-
78-
/**
79-
* @var bool
80-
*/
81-
private $checkSslHost = false;
82-
83-
/**
84-
* @var int
85-
*/
86-
private $sslVersion = 0;
87-
88-
/**
89-
* @var bool Flag to determine authentication method
90-
*/
91-
private $useHttpAuth = true;
50+
private ?int $port = null;
51+
private string $url;
52+
private string $apikeyOrUsername;
53+
private ?string $pass;
54+
private bool $checkSslCertificate = false;
55+
private bool $checkSslHost = false;
56+
private int $sslVersion = 0;
57+
private bool $useHttpAuth = true;
58+
private int $responseCode = 0;
59+
private string $responseContentType = '';
60+
private string $responseBody = '';
61+
private array $curlOptions = [];
9262

9363
/**
9464
* @var string|null username for impersonating API calls
@@ -100,30 +70,10 @@ class Client implements ClientInterface
10070
*/
10171
protected $customHost = null;
10272

103-
/**
104-
* @var int|null Redmine response code, null if request is not still completed
105-
*/
106-
private $responseCode = null;
107-
108-
/**
109-
* @var string Redmine response content type
110-
*/
111-
private $responseContentType = '';
112-
113-
/**
114-
* @var string Redmine response body
115-
*/
116-
private $responseBody = '';
117-
118-
/**
119-
* @var array cURL options
120-
*/
121-
private $curlOptions = [];
122-
12373
/**
12474
* Error strings if json is invalid.
12575
*/
126-
private static $jsonErrors = [
76+
private static array $jsonErrors = [
12777
JSON_ERROR_NONE => 'No error has occurred',
12878
JSON_ERROR_DEPTH => 'The maximum stack depth has been exceeded',
12979
JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded',
@@ -142,7 +92,7 @@ public function __construct($url, $apikeyOrUsername, $pass = null)
14292
{
14393
$this->url = $url;
14494
$this->getPort();
145-
$this->apikeyOrUsername = $apikeyOrUsername;
95+
$this->apikeyOrUsername = strval($apikeyOrUsername);
14696
$this->pass = $pass;
14797
}
14898

@@ -364,12 +314,7 @@ public function getCheckSslCertificate()
364314
*/
365315
public function setCheckSslHost($check = false)
366316
{
367-
// Make sure verify value is set to "2" for boolean argument
368-
// @see http://curl.haxx.se/libcurl/c/CURLOPT_SSL_VERIFYHOST.html
369-
if (true === $check) {
370-
$check = self::SSL_VERIFYHOST;
371-
}
372-
$this->checkSslHost = $check;
317+
$this->checkSslHost = (bool) $check;
373318

374319
return $this;
375320
}
@@ -599,7 +544,7 @@ public function getCurlOptions()
599544
*/
600545
public function prepareRequest($path, $method = 'GET', $data = '')
601546
{
602-
$this->responseCode = null;
547+
$this->responseCode = 0;
603548
$this->responseContentType = '';
604549
$this->responseBody = '';
605550
$curl = curl_init();
@@ -624,7 +569,9 @@ public function prepareRequest($path, $method = 'GET', $data = '')
624569
$this->setCurlOption(CURLOPT_PORT, $this->getPort());
625570
if (80 !== $this->getPort()) {
626571
$this->setCurlOption(CURLOPT_SSL_VERIFYPEER, (int) $this->checkSslCertificate);
627-
$this->setCurlOption(CURLOPT_SSL_VERIFYHOST, (int) $this->checkSslHost);
572+
// Make sure verify value is set to "2" for boolean argument
573+
// @see http://curl.haxx.se/libcurl/c/CURLOPT_SSL_VERIFYHOST.html
574+
$this->setCurlOption(CURLOPT_SSL_VERIFYHOST, ($this->checkSslHost === true) ? self::SSL_VERIFYHOST : 0);
628575
$this->setCurlOption(CURLOPT_SSLVERSION, $this->sslVersion);
629576
}
630577

src/Redmine/Client/Client.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
interface Client
1212
{
1313
/**
14-
* @throws InvalidArgumentException
14+
* @throws InvalidArgumentException if $name is not a valid api name
1515
*/
1616
public function getApi(string $name): Api;
1717

src/Redmine/Client/ClientApiTrait.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,9 @@
1212
*/
1313
trait ClientApiTrait
1414
{
15-
/**
16-
* @var array Api[]
17-
*/
18-
private $apiInstances = [];
15+
private array $apiInstances = [];
1916

20-
private $apiClassnames = [
17+
private array $apiClassnames = [
2118
'attachment' => 'Attachment',
2219
'group' => 'Group',
2320
'custom_fields' => 'CustomField',

src/Redmine/Client/Psr18Client.php

Lines changed: 13 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -19,64 +19,33 @@ final class Psr18Client implements Client
1919
{
2020
use ClientApiTrait;
2121

22-
/**
23-
* @var string
24-
*/
25-
private $url;
26-
27-
/**
28-
* @var string
29-
*/
30-
private $apikeyOrUsername;
31-
32-
/**
33-
* @var string|null
34-
*/
35-
private $pass;
36-
37-
/**
38-
* @var string|null
39-
*/
40-
private $impersonateUser;
41-
42-
/**
43-
* @var ClientInterface
44-
*/
45-
private $httpClient;
46-
47-
/**
48-
* @var ServerRequestFactoryInterface
49-
*/
50-
private $requestFactory;
51-
52-
/**
53-
* @var StreamFactoryInterface
54-
*/
55-
private $streamFactory;
56-
57-
/**
58-
* @var ResponseInterface|null
59-
*/
60-
private $lastResponse;
22+
private string $url;
23+
private string $apikeyOrUsername;
24+
private ?string $password;
25+
private ?string $impersonateUser = null;
26+
private ClientInterface $httpClient;
27+
private ServerRequestFactoryInterface $requestFactory;
28+
private StreamFactoryInterface $streamFactory;
29+
private ?ResponseInterface $lastResponse = null;
6130

6231
/**
6332
* $apikeyOrUsername should be your ApiKey, but it could also be your username.
64-
* $pass needs to be set if a username is given (not recommended).
33+
* $password needs to be set if a username is given (not recommended).
6534
*/
6635
public function __construct(
6736
ClientInterface $httpClient,
6837
ServerRequestFactoryInterface $requestFactory,
6938
StreamFactoryInterface $streamFactory,
7039
string $url,
7140
string $apikeyOrUsername,
72-
string $pass = null
41+
string $password = null
7342
) {
7443
$this->httpClient = $httpClient;
7544
$this->requestFactory = $requestFactory;
7645
$this->streamFactory = $streamFactory;
7746
$this->url = $url;
7847
$this->apikeyOrUsername = $apikeyOrUsername;
79-
$this->pass = $pass;
48+
$this->password = $password;
8049
}
8150

8251
/**
@@ -195,10 +164,10 @@ private function createRequest(string $method, string $path, string $body = ''):
195164

196165
// Set Authentication header
197166
// @see https://www.redmine.org/projects/redmine/wiki/Rest_api#Authentication
198-
if ($this->pass !== null) {
167+
if ($this->password !== null) {
199168
$request = $request->withHeader(
200169
'Authorization',
201-
'Basic ' . base64_encode($this->apikeyOrUsername . ':' . $this->pass)
170+
'Basic ' . base64_encode($this->apikeyOrUsername . ':' . $this->password)
202171
);
203172
} else {
204173
$request = $request->withHeader('X-Redmine-API-Key', $this->apikeyOrUsername);

tests/Integration/Psr18ClientRequestGenerationTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,8 @@ public function createdGetRequestsData()
172172
'X-Redmine-API-Key: access_token'.\PHP_EOL.
173173
'Content-Type: application/octet-stream'.\PHP_EOL.
174174
\PHP_EOL.
175-
'This is a test file.'.\PHP_EOL.
176-
'It will be needed for testing file uploads.'.\PHP_EOL
175+
'This is a test file.'."\n".
176+
'It will be needed for testing file uploads.'."\n"
177177
],
178178
[
179179
// Test fileupload with file path to image

0 commit comments

Comments
 (0)