Skip to content

Commit b792ebe

Browse files
committed
feat: create Attachment::fromHttpClient()
1 parent 806ae63 commit b792ebe

File tree

10 files changed

+135
-13
lines changed

10 files changed

+135
-13
lines changed

CHANGELOG.md

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

1010
### Added
1111

12+
- New method `Redmine\Api\Attachment::fromHttpClient()` for creating the class.
13+
- New method `Redmine\Api\Issue::fromHttpClient()` for creating the class.
1214
- Add support for PHP 8.5
1315
- Add support for Redmine 6.1.
1416

1517
### Changed
1618

1719
- Behaviour-driven tests are run against Redmine 6.1.0, 6.0.7, 5.1.10.
1820

21+
### Deprecated
22+
23+
- `Redmine\Api\Attachment::__construct()` is deprecated and will be set to private in future, use `\Redmine\Api\Attachment::fromHttpClient()` instead.
24+
- Extending `Redmine\Api\Attachment` is deprecated and will be set to final in future, create a wrapper class instead.
25+
- `Redmine\Api\Issue::__construct()` is deprecated and will be set to private in future, use `\Redmine\Api\Issue::fromHttpClient()` instead.
26+
- Extending `Redmine\Api\Issue` is deprecated and will be set to final in future, create a wrapper class instead.
27+
1928
### Removed
2029

2130
- Drop support for Redmine 5.0.x.

src/Redmine/Api/Attachment.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
namespace Redmine\Api;
44

5+
use Redmine\Client\Client;
56
use Redmine\Exception\SerializerException;
67
use Redmine\Exception\UnexpectedResponseException;
8+
use Redmine\Http\HttpClient;
79
use Redmine\Http\HttpFactory;
810
use Redmine\Serializer\JsonSerializer;
911
use Redmine\Serializer\PathSerializer;
@@ -17,6 +19,37 @@
1719
*/
1820
class Attachment extends AbstractApi
1921
{
22+
final public static function fromHttpClient(HttpClient $httpClient): self
23+
{
24+
return new self($httpClient, true);
25+
}
26+
27+
/**
28+
* @deprecated v2.9.0 Use fromHttpClient() instead.
29+
* @see Attachment::fromHttpClient()
30+
*
31+
* @param Client|HttpClient $client
32+
*/
33+
public function __construct($client/*, bool $privatelyCalled = false*/)
34+
{
35+
$privatelyCalled = (func_num_args() > 1) ? func_get_arg(1) : false;
36+
37+
if ($privatelyCalled === true) {
38+
parent::__construct($client);
39+
40+
return;
41+
}
42+
43+
if (static::class !== self::class) {
44+
$className = (new \ReflectionClass($this))->isAnonymous() ? '' : ' in `' . static::class . '`';
45+
@trigger_error('Class `' . self::class . '` will declared as final in v3.0.0, stop extending it' . $className . '.', E_USER_DEPRECATED);
46+
} else {
47+
@trigger_error('Method `' . __METHOD__ . '()` is deprecated since v2.9.0 and will declared as private in v3.0.0, use `' . self::class . '::fromHttpClient()` instead.', E_USER_DEPRECATED);
48+
}
49+
50+
parent::__construct($client);
51+
}
52+
2053
/**
2154
* Get extended information about an attachment.
2255
*

src/Redmine/Api/Issue.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Redmine\Api;
44

5+
use Redmine\Client\Client;
56
use Redmine\Client\NativeCurlClient;
67
use Redmine\Client\Psr18Client;
78
use Redmine\Exception;
@@ -81,6 +82,8 @@ final public static function fromHttpClient(HttpClient $httpClient): self
8182
/**
8283
* @deprecated v2.9.0 Use fromHttpClient() instead.
8384
* @see Issue::fromHttpClient()
85+
*
86+
* @param Client|HttpClient $client
8487
*/
8588
public function __construct($client/*, bool $privatelyCalled = false*/)
8689
{

tests/Unit/Api/Attachment/DownloadTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public function testDownloadReturnsCorrectResponse($id, string $expectedPath, in
3131
);
3232

3333
// Create the object under test
34-
$api = new Attachment($client);
34+
$api = Attachment::fromHttpClient($client);
3535

3636
// Perform the tests
3737
$this->assertSame($expectedReturn, $api->download($id));
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace Redmine\Tests\Unit\Api\Attachment;
4+
5+
use PHPUnit\Framework\Attributes\CoversClass;
6+
use PHPUnit\Framework\TestCase;
7+
use Redmine\Api\Attachment;
8+
use Redmine\Http\HttpClient;
9+
10+
#[CoversClass(Attachment::class)]
11+
class FromHttpClientTest extends TestCase
12+
{
13+
public function testReturnsCorrectObject(): void
14+
{
15+
$httpClient = $this->createStub(HttpClient::class);
16+
17+
$api = Attachment::fromHttpClient($httpClient);
18+
19+
$this->assertInstanceOf(Attachment::class, $api);
20+
}
21+
}

tests/Unit/Api/Attachment/RemoveTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public function testRemoveReturnsString(): void
2727
],
2828
);
2929

30-
$api = new Attachment($client);
30+
$api = Attachment::fromHttpClient($client);
3131

3232
$this->assertSame('', $api->remove(5));
3333
}

tests/Unit/Api/Attachment/ShowTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public function testShowReturnsCorrectResponse($id, string $expectedPath, string
3131
);
3232

3333
// Create the object under test
34-
$api = new Attachment($client);
34+
$api = Attachment::fromHttpClient($client);
3535

3636
// Perform the tests
3737
$this->assertSame($expectedReturn, $api->show($id));

tests/Unit/Api/Attachment/UpdateTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public function testUpdateReturnsCorrectResponse(int $id, array $params, string
3232
);
3333

3434
// Create the object under test
35-
$api = new Attachment($client);
35+
$api = Attachment::fromHttpClient($client);
3636

3737
// Perform the tests
3838
$this->assertSame($expectedReturn, $api->update($id, $params));
@@ -69,7 +69,7 @@ public function testUpdateThrowsUnexpectedResponseException(): void
6969
],
7070
);
7171

72-
$api = new Attachment($client);
72+
$api = Attachment::fromHttpClient($client);
7373

7474
$this->expectException(UnexpectedResponseException::class);
7575
$this->expectExceptionMessage('The Redmine server replied with an unexpected response.');

tests/Unit/Api/Attachment/UploadTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public function testUploadReturnsCorrectResponse(string $attachment, array $para
3131
);
3232

3333
// Create the object under test
34-
$api = new Attachment($client);
34+
$api = Attachment::fromHttpClient($client);
3535

3636
// Perform the tests
3737
$this->assertSame($expectedReturn, $api->upload($attachment, $params));

tests/Unit/Api/AttachmentTest.php

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,85 @@
77
use PHPUnit\Framework\TestCase;
88
use Redmine\Api\Attachment;
99
use Redmine\Client\Client;
10+
use Redmine\Http\HttpClient;
11+
use Redmine\Tests\Fixtures\AssertingHttpClient;
1012

1113
/**
1214
* @author Malte Gerth <mail@malte-gerth.de>
1315
*/
1416
#[CoversClass(Attachment::class)]
1517
class AttachmentTest extends TestCase
1618
{
19+
public function testExtendingTheClassTriggersDeprecationWarning(): void
20+
{
21+
// PHPUnit 10 compatible way to test trigger_error().
22+
set_error_handler(
23+
function ($errno, $errstr): bool {
24+
$this->assertSame(
25+
'Class `Redmine\Api\Attachment` will declared as final in v3.0.0, stop extending it.',
26+
$errstr,
27+
);
28+
29+
restore_error_handler();
30+
return true;
31+
},
32+
E_USER_DEPRECATED,
33+
);
34+
35+
new class ($this->createStub(HttpClient::class)) extends Attachment {};
36+
}
37+
38+
public function testConstructorTriggersDeprecationWarning(): void
39+
{
40+
// PHPUnit 10 compatible way to test trigger_error().
41+
set_error_handler(
42+
function ($errno, $errstr): bool {
43+
$this->assertSame(
44+
'Method `Redmine\Api\Attachment::__construct()` is deprecated since v2.9.0 and will declared as private in v3.0.0, use `Redmine\Api\Attachment::fromHttpClient()` instead.',
45+
$errstr,
46+
);
47+
48+
restore_error_handler();
49+
return true;
50+
},
51+
E_USER_DEPRECATED,
52+
);
53+
54+
new Attachment($this->createStub(HttpClient::class));
55+
}
56+
57+
public function testLastCallFailedWithoutPreviousRequestReturnsTrue(): void
58+
{
59+
$api = Attachment::fromHttpClient($this->createStub(HttpClient::class));
60+
61+
// Perform the tests
62+
$this->assertTrue($api->lastCallFailed());
63+
}
64+
1765
/**
1866
* Test lastCallFailed().
1967
*
2068
* @dataProvider responseCodeProvider
2169
*/
2270
#[DataProvider('responseCodeProvider')]
23-
public function testLastCallFailedTrue(int $responseCode, bool $hasFailed): void
71+
public function testLastCallFailedReturnsCorrectValue(int $responseCode, bool $hasFailed): void
2472
{
25-
// Create the used mock objects
26-
$client = $this->createMock(Client::class);
27-
$client->expects($this->once())
28-
->method('getLastResponseStatusCode')
29-
->willReturn($responseCode);
73+
$client = AssertingHttpClient::create(
74+
$this,
75+
[
76+
'GET',
77+
'/attachments/1.json',
78+
'application/json',
79+
'',
80+
$responseCode,
81+
'',
82+
'',
83+
],
84+
);
3085

3186
// Create the object under test
32-
$api = new Attachment($client);
87+
$api = Attachment::fromHttpClient($client);
88+
$api->show(1);
3389

3490
// Perform the tests
3591
$this->assertSame($hasFailed, $api->lastCallFailed());

0 commit comments

Comments
 (0)