Skip to content

Commit 3aebdc8

Browse files
committed
feat: create Group::fromHttpClient()
1 parent c8b2db0 commit 3aebdc8

File tree

13 files changed

+259
-138
lines changed

13 files changed

+259
-138
lines changed

CHANGELOG.md

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

1212
- New method `Redmine\Api\Attachment::fromHttpClient()` for creating the class.
1313
- New method `Redmine\Api\CustomField::fromHttpClient()` for creating the class.
14+
- New method `Redmine\Api\Group::fromHttpClient()` for creating the class.
1415
- New method `Redmine\Api\Issue::fromHttpClient()` for creating the class.
1516
- Add support for PHP 8.5
1617
- Add support for Redmine 6.1.
@@ -25,6 +26,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2526
- Extending `Redmine\Api\Attachment` is deprecated and will be set to final in future, create a wrapper class instead.
2627
- `Redmine\Api\CustomField::__construct()` is deprecated and will be set to private in future, use `\Redmine\Api\CustomField::fromHttpClient()` instead.
2728
- Extending `Redmine\Api\CustomField` is deprecated and will be set to final in future, create a wrapper class instead.
29+
- `Redmine\Api\Group::__construct()` is deprecated and will be set to private in future, use `\Redmine\Api\Group::fromHttpClient()` instead.
30+
- Extending `Redmine\Api\Group` is deprecated and will be set to final in future, create a wrapper class instead.
2831
- `Redmine\Api\Issue::__construct()` is deprecated and will be set to private in future, use `\Redmine\Api\Issue::fromHttpClient()` instead.
2932
- Extending `Redmine\Api\Issue` is deprecated and will be set to final in future, create a wrapper class instead.
3033

src/Redmine/Api/Group.php

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

33
namespace Redmine\Api;
44

5+
use Redmine\Client\Client;
56
use Redmine\Exception;
67
use Redmine\Exception\MissingParameterException;
78
use Redmine\Exception\SerializerException;
89
use Redmine\Exception\UnexpectedResponseException;
10+
use Redmine\Http\HttpClient;
911
use Redmine\Http\HttpFactory;
1012
use Redmine\Serializer\JsonSerializer;
1113
use Redmine\Serializer\PathSerializer;
@@ -21,6 +23,11 @@
2123
*/
2224
class Group extends AbstractApi
2325
{
26+
final public static function fromHttpClient(HttpClient $httpClient): self
27+
{
28+
return new self($httpClient, true);
29+
}
30+
2431
/**
2532
* @var null|array<mixed>
2633
*/
@@ -31,6 +38,32 @@ class Group extends AbstractApi
3138
*/
3239
private ?array $groupNames = null;
3340

41+
/**
42+
* @deprecated v2.9.0 Use fromHttpClient() instead.
43+
* @see Issue::fromHttpClient()
44+
*
45+
* @param Client|HttpClient $client
46+
*/
47+
public function __construct($client/*, bool $privatelyCalled = false*/)
48+
{
49+
$privatelyCalled = (func_num_args() > 1) ? func_get_arg(1) : false;
50+
51+
if ($privatelyCalled === true) {
52+
parent::__construct($client);
53+
54+
return;
55+
}
56+
57+
if (static::class !== self::class) {
58+
$className = (new \ReflectionClass($this))->isAnonymous() ? '' : ' in `' . static::class . '`';
59+
@trigger_error('Class `' . self::class . '` will declared as final in v3.0.0, stop extending it' . $className . '.', E_USER_DEPRECATED);
60+
} else {
61+
@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);
62+
}
63+
64+
parent::__construct($client);
65+
}
66+
3467
/**
3568
* List groups.
3669
*
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\CustomField;
4+
5+
use PHPUnit\Framework\Attributes\CoversClass;
6+
use PHPUnit\Framework\TestCase;
7+
use Redmine\Api\CustomField;
8+
use Redmine\Http\HttpClient;
9+
10+
#[CoversClass(CustomField::class)]
11+
class FromHttpClientTest extends TestCase
12+
{
13+
public function testReturnsCorrectObject(): void
14+
{
15+
$httpClient = $this->createStub(HttpClient::class);
16+
17+
$api = CustomField::fromHttpClient($httpClient);
18+
19+
$this->assertInstanceOf(CustomField::class, $api);
20+
}
21+
}

tests/Unit/Api/Group/AddUserTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public function testAddUserReturnsCorrectResponse(int $groupId, int $userId, str
3232
);
3333

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

3737
// Perform the tests
3838
$return = $api->addUser($groupId, $userId);
@@ -74,7 +74,7 @@ public function testAddUserReturnsEmptyString(): void
7474
);
7575

7676
// Create the object under test
77-
$api = new Group($client);
77+
$api = Group::fromHttpClient($client);
7878

7979
// Perform the tests
8080
$return = $api->addUser(1, 2);

tests/Unit/Api/Group/CreateTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public function testCreateReturnsCorrectResponse(array $parameters, string $expe
3636
);
3737

3838
// Create the object under test
39-
$api = new Group($client);
39+
$api = Group::fromHttpClient($client);
4040

4141
// Perform the tests
4242
$return = $api->create($parameters);
@@ -123,7 +123,7 @@ public function testCreateReturnsEmptyString(): void
123123
);
124124

125125
// Create the object under test
126-
$api = new Group($client);
126+
$api = Group::fromHttpClient($client);
127127

128128
// Perform the tests
129129
$return = $api->create(['name' => 'Group Name']);
@@ -140,7 +140,7 @@ public function testCreateThrowsExceptionIfNameIsMissing(): void
140140
$client = $this->createMock(HttpClient::class);
141141

142142
// Create the object under test
143-
$api = new Group($client);
143+
$api = Group::fromHttpClient($client);
144144

145145
$this->expectException(MissingParameterException::class);
146146
$this->expectExceptionMessage('Theses parameters are mandatory: `name`');
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\Group;
4+
5+
use PHPUnit\Framework\Attributes\CoversClass;
6+
use PHPUnit\Framework\TestCase;
7+
use Redmine\Api\Group;
8+
use Redmine\Http\HttpClient;
9+
10+
#[CoversClass(Group::class)]
11+
class FromHttpClientTest extends TestCase
12+
{
13+
public function testReturnsCorrectObject(): void
14+
{
15+
$httpClient = $this->createStub(HttpClient::class);
16+
17+
$api = Group::fromHttpClient($httpClient);
18+
19+
$this->assertInstanceOf(Group::class, $api);
20+
}
21+
}

tests/Unit/Api/Group/ListNamesTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public function testListNamesReturnsCorrectResponse(string $expectedPath, int $r
3333
);
3434

3535
// Create the object under test
36-
$api = new Group($client);
36+
$api = Group::fromHttpClient($client);
3737

3838
// Perform the tests
3939
$this->assertSame($expectedResponse, $api->listNames());
@@ -98,7 +98,7 @@ public function testListNamesCallsHttpClientOnlyOnce(): void
9898
);
9999

100100
// Create the object under test
101-
$api = new Group($client);
101+
$api = Group::fromHttpClient($client);
102102

103103
// Perform the tests
104104
$this->assertSame([1 => 'Group 1'], $api->listNames());

tests/Unit/Api/Group/ListTest.php

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
use PHPUnit\Framework\Attributes\CoversClass;
66
use PHPUnit\Framework\TestCase;
77
use Redmine\Api\Group;
8-
use Redmine\Client\Client;
98
use Redmine\Exception\UnexpectedResponseException;
9+
use Redmine\Tests\Fixtures\AssertingHttpClient;
1010

1111
#[CoversClass(Group::class)]
1212
class ListTest extends TestCase
@@ -17,21 +17,21 @@ public function testListWithoutParametersReturnsResponse(): void
1717
$response = '["API Response"]';
1818
$expectedReturn = ['API Response'];
1919

20-
// Create the used mock objects
21-
$client = $this->createMock(Client::class);
22-
$client->expects($this->once())
23-
->method('requestGet')
24-
->with('/groups.json')
25-
->willReturn(true);
26-
$client->expects($this->exactly(1))
27-
->method('getLastResponseBody')
28-
->willReturn($response);
29-
$client->expects($this->exactly(1))
30-
->method('getLastResponseContentType')
31-
->willReturn('application/json');
20+
$client = AssertingHttpClient::create(
21+
$this,
22+
[
23+
'GET',
24+
'/groups.json',
25+
'application/json',
26+
'',
27+
200,
28+
'application/json',
29+
$response,
30+
],
31+
);
3232

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

3636
// Perform the tests
3737
$this->assertSame($expectedReturn, $api->list());
@@ -44,43 +44,43 @@ public function testListeWithParametersReturnsResponse(): void
4444
$response = '["API Response"]';
4545
$expectedReturn = ['API Response'];
4646

47-
// Create the used mock objects
48-
$client = $this->createMock(Client::class);
49-
$client->expects($this->once())
50-
->method('requestGet')
51-
->with('/groups.json?limit=25&offset=0&0=not-used')
52-
->willReturn(true);
53-
$client->expects($this->exactly(1))
54-
->method('getLastResponseBody')
55-
->willReturn($response);
56-
$client->expects($this->exactly(1))
57-
->method('getLastResponseContentType')
58-
->willReturn('application/json');
47+
$client = AssertingHttpClient::create(
48+
$this,
49+
[
50+
'GET',
51+
'/groups.json?limit=25&offset=0&0=not-used',
52+
'application/json',
53+
'',
54+
200,
55+
'application/json',
56+
$response,
57+
],
58+
);
5959

6060
// Create the object under test
61-
$api = new Group($client);
61+
$api = Group::fromHttpClient($client);
6262

6363
// Perform the tests
6464
$this->assertSame($expectedReturn, $api->list($parameters));
6565
}
6666

6767
public function testListThrowsException(): void
6868
{
69-
// Create the used mock objects
70-
$client = $this->createMock(Client::class);
71-
$client->expects($this->exactly(1))
72-
->method('requestGet')
73-
->with('/groups.json')
74-
->willReturn(true);
75-
$client->expects($this->exactly(1))
76-
->method('getLastResponseBody')
77-
->willReturn('');
78-
$client->expects($this->exactly(1))
79-
->method('getLastResponseContentType')
80-
->willReturn('application/json');
69+
$client = AssertingHttpClient::create(
70+
$this,
71+
[
72+
'GET',
73+
'/groups.json',
74+
'application/json',
75+
'',
76+
200,
77+
'application/json',
78+
'',
79+
],
80+
);
8181

8282
// Create the object under test
83-
$api = new Group($client);
83+
$api = Group::fromHttpClient($client);
8484

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

tests/Unit/Api/Group/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 Group($client);
30+
$api = Group::fromHttpClient($client);
3131

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

tests/Unit/Api/Group/RemoveUserTest.php

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

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

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

0 commit comments

Comments
 (0)