Skip to content

Commit 412e0a5

Browse files
authored
Merge pull request #31 from clue-labs/client-ctor
Replace Factory with simplified Client constructor
2 parents 54eea46 + 98e4f7f commit 412e0a5

File tree

7 files changed

+161
-163
lines changed

7 files changed

+161
-163
lines changed

README.md

Lines changed: 52 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,6 @@ This project provides a *simple* API for invoking *async* RPCs to remote web ser
3232

3333
* [Quickstart example](#quickstart-example)
3434
* [Usage](#usage)
35-
* [Factory](#factory)
36-
* [createClient()](#createclient)
37-
* [createClientFromWsdl()](#createclientfromwsdl)
3835
* [Client](#client)
3936
* [soapCall()](#soapcall)
4037
* [getFunctions()](#getfunctions)
@@ -55,10 +52,11 @@ web service via SOAP:
5552

5653
```php
5754
$loop = React\EventLoop\Factory::create();
58-
$factory = new Factory($loop);
55+
$browser = new Browser($loop);
5956
$wsdl = 'http://example.com/demo.wsdl';
6057

61-
$factory->createClient($wsdl)->then(function (Client $client) {
58+
$browser->get($wsdl)->then(function (ResponseInterface $response) use ($browser) {
59+
$client = new Client($browser, (string)$response->getBody());
6260
$api = new Proxy($client);
6361

6462
$api->getBank(array('blz' => '12070000'))->then(function ($result) {
@@ -73,53 +71,76 @@ See also the [examples](examples).
7371

7472
## Usage
7573

76-
### Factory
74+
### Client
75+
76+
The `Client` class is responsible for communication with the remote SOAP
77+
WebService server.
7778

78-
The `Factory` class is responsible for fetching the WSDL file once and constructing
79-
the [`Client`](#client) instance.
80-
It also registers everything with the main [`EventLoop`](https://github.com/reactphp/event-loop#usage).
79+
It requires a [`Browser`](https://github.com/clue/reactphp-buzz#browser) object
80+
bound to the main [`EventLoop`](https://github.com/reactphp/event-loop#usage)
81+
in order to handle async requests and the WSDL file contents:
8182

8283
```php
8384
$loop = React\EventLoop\Factory::create();
84-
$factory = new Factory($loop);
85+
$browser = new Clue\React\Buzz\Browser($loop);
86+
87+
$client = new Client($browser, $wsdl);
8588
```
8689

87-
If you need custom DNS or proxy settings, you can explicitly pass a
90+
If you need custom DNS, TLS or proxy settings, you can explicitly pass a
8891
custom [`Browser`](https://github.com/clue/reactphp-buzz#browser) instance:
8992

9093
```php
91-
$browser = new Clue\React\Buzz\Browser($loop);
92-
$factory = new Factory($loop, $browser);
94+
$connector = new \React\Socket\Connector($loop, array(
95+
'dns' => '127.0.0.1',
96+
'tcp' => array(
97+
'bindto' => '192.168.10.1:0'
98+
),
99+
'tls' => array(
100+
'verify_peer' => false,
101+
'verify_peer_name' => false
102+
)
103+
));
104+
105+
$browser = new Browser($loop, $connector);
106+
$client = new Client($browser, $wsdl);
93107
```
94108

95-
#### createClient()
96-
97-
The `createClient(string $wsdl): PromiseInterface<Client, Exception>` method can be used to
98-
download the WSDL at the given URL into memory and create a new [`Client`](#client).
109+
The `Client` works similar to PHP's `SoapClient` (which it uses under the
110+
hood), but leaves you the responsibility to load the WSDL file. This allows
111+
you to use local WSDL files, WSDL files from a cache or the most common form,
112+
downloading the WSDL file contents from an URL through the `Browser`:
99113

100114
```php
101-
$factory->createClient($url)->then(
102-
function (Client $client) {
103-
// client ready
115+
$browser = new Browser($loop);
116+
117+
$browser->get($url)->then(
118+
function (ResponseInterface $response) use ($browser) {
119+
// WSDL file is ready, create client
120+
$client = new Client($browser, (string)$response->getBody());
121+
104122
},
105123
function (Exception $e) {
106-
// an error occured while trying to download or parse the WSDL
124+
// an error occured while trying to download the WSDL
107125
}
108126
);
109127
```
110128

111-
#### createClientFromWsdl()
112-
113-
The `createClientFromWsdl(string $wsdlContents): Client` method can be used to
114-
create a new [`Client`](#client) from the given WSDL contents.
129+
The `Client` constructor loads the given WSDL file contents into memory and
130+
parses its definition. If the given WSDL file is invalid and can not be
131+
parsed, this will throw a `SoapFault`:
115132

116-
This works similar to `createClient()`, but leaves you the responsibility to load
117-
the WSDL file. This allows you to use local WSDL files, for instance.
118-
119-
### Client
133+
```php
134+
try {
135+
$client = new Client($browser, $wsdl);
136+
} catch (SoapFault $e) {
137+
echo 'Error: ' . $e->getMessage() . PHP_EOL;
138+
}
139+
```
120140

121-
The `Client` class is responsible for communication with the remote SOAP
122-
WebService server.
141+
> Note that if you have `ext-debug` loaded, this may halt with a fatal
142+
error instead of throwing a `SoapFault`. It is not recommended to use this
143+
extension in production, so this should only ever affect test environments.
123144

124145
If you want to call RPC functions, see below for the [`Proxy`](#proxy) class.
125146

examples/client-blz.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
<?php
22

3-
use Clue\React\Soap\Factory;
4-
use Clue\React\Soap\Proxy;
3+
use Clue\React\Buzz\Browser;
54
use Clue\React\Soap\Client;
5+
use Clue\React\Soap\Proxy;
6+
use Psr\Http\Message\ResponseInterface;
67

78
require __DIR__ . '/../vendor/autoload.php';
89

910
$loop = React\EventLoop\Factory::create();
10-
$factory = new Factory($loop);
11+
$browser = new Browser($loop);
1112

1213
$blz = isset($argv[1]) ? $argv[1] : '12070000';
1314

14-
$factory->createClient('http://www.thomas-bayer.com/axis2/services/BLZService?wsdl')->then(function (Client $client) use ($blz) {
15-
//var_dump($client->getFunctions(), $client->getTypes());
16-
15+
$browser->get('http://www.thomas-bayer.com/axis2/services/BLZService?wsdl')->done(function (ResponseInterface $response) use ($browser, $blz) {
16+
$client = new Client($browser, (string)$response->getBody());
1717
$api = new Proxy($client);
1818

1919
$api->getBank(array('blz' => $blz))->then(

examples/client-wsdl.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
<?php
22

3-
use Clue\React\Soap\Factory;
3+
use Clue\React\Buzz\Browser;
44
use Clue\React\Soap\Client;
5+
use Psr\Http\Message\ResponseInterface;
56

67
require __DIR__ . '/../vendor/autoload.php';
78

89
$loop = React\EventLoop\Factory::create();
9-
$factory = new Factory($loop);
10+
$browser = new Browser($loop);
1011

1112
$wsdl = isset($argv[1]) ? $argv[1] : 'http://www.thomas-bayer.com/axis2/services/BLZService?wsdl';
1213

13-
$factory->createClient($wsdl)->then(
14-
function (Client $client) {
14+
$browser->get($wsdl)->done(
15+
function (ResponseInterface $response) use ($browser) {
16+
$client = new Client($browser, (string)$response->getBody());
17+
1518
echo 'Functions:' . PHP_EOL .
1619
implode(PHP_EOL, $client->getFunctions()) . PHP_EOL .
1720
PHP_EOL .

src/Client.php

Lines changed: 73 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,41 +13,96 @@
1313
* The `Client` class is responsible for communication with the remote SOAP
1414
* WebService server.
1515
*
16+
* It requires a [`Browser`](https://github.com/clue/reactphp-buzz#browser) object
17+
* bound to the main [`EventLoop`](https://github.com/reactphp/event-loop#usage)
18+
* in order to handle async requests and the WSDL file contents:
19+
*
20+
* ```php
21+
* $loop = React\EventLoop\Factory::create();
22+
* $browser = new Clue\React\Buzz\Browser($loop);
23+
*
24+
* $client = new Client($browser, $wsdl);
25+
* ```
26+
*
27+
* If you need custom DNS, TLS or proxy settings, you can explicitly pass a
28+
* custom [`Browser`](https://github.com/clue/reactphp-buzz#browser) instance:
29+
*
30+
* ```php
31+
* $connector = new \React\Socket\Connector($loop, array(
32+
* 'dns' => '127.0.0.1',
33+
* 'tcp' => array(
34+
* 'bindto' => '192.168.10.1:0'
35+
* ),
36+
* 'tls' => array(
37+
* 'verify_peer' => false,
38+
* 'verify_peer_name' => false
39+
* )
40+
* ));
41+
*
42+
* $browser = new Browser($loop, $connector);
43+
* $client = new Client($browser, $wsdl);
44+
* ```
45+
*
46+
* The `Client` works similar to PHP's `SoapClient` (which it uses under the
47+
* hood), but leaves you the responsibility to load the WSDL file. This allows
48+
* you to use local WSDL files, WSDL files from a cache or the most common form,
49+
* downloading the WSDL file contents from an URL through the `Browser`:
50+
*
51+
* ```php
52+
* $browser = new Browser($loop);
53+
*
54+
* $browser->get($url)->then(
55+
* function (ResponseInterface $response) use ($browser) {
56+
* // WSDL file is ready, create client
57+
* $client = new Client($browser, (string)$response->getBody());
58+
* …
59+
* },
60+
* function (Exception $e) {
61+
* // an error occured while trying to download the WSDL
62+
* }
63+
* );
64+
* ```
65+
*
66+
* The `Client` constructor loads the given WSDL file contents into memory and
67+
* parses its definition. If the given WSDL file is invalid and can not be
68+
* parsed, this will throw a `SoapFault`:
69+
*
70+
* ```php
71+
* try {
72+
* $client = new Client($browser, $wsdl);
73+
* } catch (SoapFault $e) {
74+
* echo 'Error: ' . $e->getMessage() . PHP_EOL;
75+
* }
76+
* ```
77+
*
78+
* > Note that if you have `ext-debug` loaded, this may halt with a fatal
79+
* error instead of throwing a `SoapFault`. It is not recommended to use this
80+
* extension in production, so this should only ever affect test environments.
81+
*
1682
* If you want to call RPC functions, see below for the [`Proxy`](#proxy) class.
1783
*
1884
* Note: It's recommended (and easier) to wrap the `Client` in a [`Proxy`](#proxy) instance.
1985
* All public methods of the `Client` are considered *advanced usage*.
2086
*/
2187
final class Client
2288
{
23-
private $wsdl;
2489
private $browser;
2590
private $encoder;
2691
private $decoder;
2792

2893
/**
29-
* [internal] Instantiate new SOAP client, see Factory instead
94+
* Instantiate a new SOAP client for the given WSDL contents.
3095
*
31-
* @param string $wsdl
3296
* @param Browser $browser
33-
* @param ClientEncoder $encoder
34-
* @param ClientDecoder $decoder
35-
* @internal
97+
* @param string $wsdlContents
3698
*/
37-
public function __construct($wsdl, Browser $browser, ClientEncoder $encoder = null, ClientDecoder $decoder = null)
99+
public function __construct(Browser $browser, $wsdlContents)
38100
{
39-
if ($encoder === null) {
40-
$encoder = new ClientEncoder($wsdl);
41-
}
42-
43-
if ($decoder === null) {
44-
$decoder = new ClientDecoder($wsdl);
45-
}
46-
47-
$this->wsdl = $wsdl;
48101
$this->browser = $browser;
49-
$this->encoder = $encoder;
50-
$this->decoder = $decoder;
102+
$this->encoder = new ClientEncoder(
103+
'data://text/plain;base64,' . base64_encode($wsdlContents)
104+
);
105+
$this->decoder = new ClientDecoder();
51106
}
52107

53108
/**

src/Factory.php

Lines changed: 0 additions & 84 deletions
This file was deleted.

tests/ClientTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
use Clue\React\Soap\Client;
4+
use PHPUnit\Framework\TestCase;
5+
6+
class ClientTest extends TestCase
7+
{
8+
public function testConstructorThrowsWhenUrlIsInvalid()
9+
{
10+
if (extension_loaded('xdebug')) {
11+
$this->markTestSkipped('Invalid WSDL causes a fatal error when ext-xdebug is loaded');
12+
}
13+
14+
$browser = $this->getMockBuilder('Clue\React\Buzz\Browser')->disableOriginalConstructor()->getMock();
15+
$wsdl = 'invalid';
16+
17+
$client = new Client($browser, $wsdl);
18+
}
19+
}

0 commit comments

Comments
 (0)