Skip to content

Commit 04d465b

Browse files
Samuel Nogueiradbu
Samuel Nogueira
authored andcommitted
Fix composer version conflict with react/http v0.8 (#28)
* Fix composer version conflict with react/http v0.8 - Upgraded dependency on react/http-client - Introduced dependency on react/socket so \Http\Adapter\React\buildDnsResolver and \Http\Adapter\React\buildHttpClient remain usable as before (no need for major version bump on php-http/react-adapter)
1 parent 48251c9 commit 04d465b

File tree

4 files changed

+169
-8
lines changed

4 files changed

+169
-8
lines changed

CHANGELOG.md

+12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Change Log
22

3+
## 2.1.0 - 2017-12-20
4+
5+
### Changed
6+
7+
- Added compatibility with `react/http-client` v0.5 (compatibility with v0.4 kept)
8+
- `ReactFactory::buildHttpClient` now accepts a `\React\Socket\ConnectorInterface` (only for `react/http-client` v0.5).
9+
If none provided, will use React HTTP Client defaults.
10+
11+
### Deprecations
12+
- Passing a `\React\Dns\Resolver\Resolver` to `ReactFactory::buildHttpClient` is deprecated and will be removed in **3.0.0**.
13+
To control connector behavior (DNS, timeout, etc), pass a `\React\Socket\ConnectorInterface` instead.
14+
315
## 2.0.0 - 2017-09-18
416

517
### Changed

composer.json

+5-3
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@
1313
"require": {
1414
"php": "^5.5 || ^7.0",
1515
"php-http/httplug": "^1.0",
16-
"react/http-client": "^0.4.8",
16+
"react/http-client": "^0.4.8 || ^0.5",
1717
"react/dns": "^0.4.1",
18-
"react/stream": "^0.4.3",
18+
"react/stream": "^0.4.3 || ^0.7",
19+
"react/socket": "^0.8",
1920
"php-http/discovery": "^1.0"
2021
},
2122
"require-dev": {
2223
"php-http/client-integration-tests": "^0.6",
23-
"php-http/message": "^1.0"
24+
"php-http/message": "^1.0",
25+
"phpunit/phpunit": "^4.8.36 || ^5.4"
2426
},
2527
"provide": {
2628
"php-http/client-implementation": "1.0",

src/ReactFactory.php

+85-5
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
use React\EventLoop\Factory as EventLoopFactory;
77
use React\Dns\Resolver\Resolver as DnsResolver;
88
use React\Dns\Resolver\Factory as DnsResolverFactory;
9-
use React\HttpClient\Factory as HttpClientFactory;
109
use React\HttpClient\Client as HttpClient;
10+
use React\HttpClient\Factory as HttpClientFactory;
11+
use React\Socket\Connector;
12+
use React\Socket\ConnectorInterface;
1113

1214
/**
1315
* Factory wrapper for React instances.
@@ -43,24 +45,102 @@ public static function buildDnsResolver(
4345
return $factory->createCached($dns, $loop);
4446
}
4547

48+
/**
49+
* @param LoopInterface $loop
50+
* @param DnsResolver|null $dns
51+
*
52+
* @return ConnectorInterface
53+
*/
54+
public static function buildConnector(
55+
LoopInterface $loop,
56+
DnsResolver $dns = null
57+
) {
58+
return null !== $dns
59+
? new Connector($loop, ['dns' => $dns])
60+
: new Connector($loop);
61+
}
62+
4663
/**
4764
* Build a React Http Client.
4865
*
49-
* @param LoopInterface $loop
50-
* @param DnsResolver $dns
66+
* @param LoopInterface $loop
67+
* @param ConnectorInterface|DnsResolver|null $connector Only pass this argument if you need to customize DNS
68+
* behaviour. With react http client v0.5, pass a connector,
69+
* with v0.4 this must be a DnsResolver.
5170
*
5271
* @return HttpClient
5372
*/
5473
public static function buildHttpClient(
5574
LoopInterface $loop,
56-
DnsResolver $dns = null
75+
$connector = null
5776
) {
77+
if (class_exists(HttpClientFactory::class)) {
78+
// if HttpClientFactory class exists, use old behavior for backwards compatibility
79+
return static::buildHttpClient04($loop, $connector);
80+
} else {
81+
return static::buildHttpClient05($loop, $connector);
82+
}
83+
}
84+
85+
/**
86+
* Builds a React Http client v0.4 style.
87+
*
88+
* @param LoopInterface $loop
89+
* @param DnsResolver|null $dns
90+
*
91+
* @return HttpClient
92+
*/
93+
protected static function buildHttpClient04(
94+
LoopInterface $loop,
95+
$dns = null
96+
) {
97+
// create dns resolver if one isn't provided
5898
if (null === $dns) {
59-
$dns = self::buildDnsResolver($loop);
99+
$dns = static::buildDnsResolver($loop);
100+
}
101+
102+
// validate connector instance for proper error reporting
103+
if (!$dns instanceof DnsResolver) {
104+
throw new \InvalidArgumentException('For react http client v0.4, $dns must be an instance of DnsResolver');
60105
}
61106

62107
$factory = new HttpClientFactory();
63108

64109
return $factory->create($loop, $dns);
65110
}
111+
112+
/**
113+
* Builds a React Http client v0.5 style.
114+
*
115+
* @param LoopInterface $loop
116+
* @param DnsResolver|ConnectorInterface|null $connector
117+
*
118+
* @return HttpClient
119+
*/
120+
protected static function buildHttpClient05(
121+
LoopInterface $loop,
122+
$connector = null
123+
) {
124+
// build a connector with given DnsResolver if provided (old deprecated behavior)
125+
if ($connector instanceof DnsResolver) {
126+
@trigger_error(
127+
sprintf(
128+
'Passing a %s to buildHttpClient is deprecated since version 2.1.0 and will be removed in 3.0. If you need no specific behaviour, omit the $dns argument, otherwise pass a %s',
129+
DnsResolver::class,
130+
ConnectorInterface::class
131+
),
132+
E_USER_DEPRECATED
133+
);
134+
$connector = static::buildConnector($loop, $connector);
135+
}
136+
137+
// validate connector instance for proper error reporting
138+
if (null !== $connector && !$connector instanceof ConnectorInterface) {
139+
throw new \InvalidArgumentException(
140+
'$connector must be an instance of DnsResolver or ConnectorInterface'
141+
);
142+
}
143+
144+
return new HttpClient($loop, $connector);
145+
}
66146
}

tests/ReactFactoryTest.php

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
namespace Http\Adapter\React\Tests;
4+
5+
use Http\Adapter\React\ReactFactory;
6+
use PHPUnit\Framework\TestCase;
7+
use React\Dns\Resolver\Resolver;
8+
use React\EventLoop\LoopInterface;
9+
use React\HttpClient\Client;
10+
use React\HttpClient\Factory;
11+
use React\Socket\ConnectorInterface;
12+
13+
/**
14+
* These tests don't really ensure the correct instances are baked into the returned http client, instead, they are
15+
* just testing the code against the expected use cases.
16+
*
17+
* @author Samuel Nogueira <[email protected]>
18+
*/
19+
class ReactFactoryTest extends TestCase
20+
{
21+
/**
22+
* @var \React\EventLoop\LoopInterface
23+
*/
24+
private $loop;
25+
26+
protected function setUp()
27+
{
28+
$this->loop = $this->getMockBuilder(LoopInterface::class)->getMock();
29+
}
30+
31+
public function testBuildHttpClientWithConnector()
32+
{
33+
if (class_exists(Factory::class)) {
34+
$this->markTestSkipped('This test only runs with react http client v0.5 and above');
35+
}
36+
37+
$connector = $this->getMockBuilder(ConnectorInterface::class)->getMock();
38+
$client = ReactFactory::buildHttpClient($this->loop, $connector);
39+
$this->assertInstanceOf(Client::class, $client);
40+
}
41+
42+
/**
43+
* @deprecated Building HTTP client passing a DnsResolver instance is deprecated. Should pass a ConnectorInterface
44+
* instance instead.
45+
*/
46+
public function testBuildHttpClientWithDnsResolver()
47+
{
48+
$connector = $this->getMockBuilder(Resolver::class)->disableOriginalConstructor()->getMock();
49+
$client = ReactFactory::buildHttpClient($this->loop, $connector);
50+
$this->assertInstanceOf(Client::class, $client);
51+
}
52+
53+
public function testBuildHttpClientWithoutConnector()
54+
{
55+
$client = ReactFactory::buildHttpClient($this->loop);
56+
$this->assertInstanceOf(Client::class, $client);
57+
}
58+
59+
/**
60+
* @expectedException \InvalidArgumentException
61+
*/
62+
public function testBuildHttpClientWithInvalidConnectorThrowsException()
63+
{
64+
$connector = $this->getMockBuilder(LoopInterface::class)->getMock();
65+
ReactFactory::buildHttpClient($this->loop, $connector);
66+
}
67+
}

0 commit comments

Comments
 (0)