summaryrefslogtreecommitdiffstats
path: root/vendor/clue/soap-react/src/Client.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/clue/soap-react/src/Client.php')
-rw-r--r--vendor/clue/soap-react/src/Client.php323
1 files changed, 323 insertions, 0 deletions
diff --git a/vendor/clue/soap-react/src/Client.php b/vendor/clue/soap-react/src/Client.php
new file mode 100644
index 0000000..85ee7af
--- /dev/null
+++ b/vendor/clue/soap-react/src/Client.php
@@ -0,0 +1,323 @@
+<?php
+
+namespace Clue\React\Soap;
+
+use Clue\React\Buzz\Browser;
+use Clue\React\Soap\Protocol\ClientDecoder;
+use Clue\React\Soap\Protocol\ClientEncoder;
+use Psr\Http\Message\ResponseInterface;
+use React\Promise\Deferred;
+use React\Promise\PromiseInterface;
+
+/**
+ * The `Client` class is responsible for communication with the remote SOAP
+ * WebService server.
+ *
+ * It requires a [`Browser`](https://github.com/clue/reactphp-buzz#browser) object
+ * bound to the main [`EventLoop`](https://github.com/reactphp/event-loop#usage)
+ * in order to handle async requests, the WSDL file contents and an optional
+ * array of SOAP options:
+ *
+ * ```php
+ * $loop = React\EventLoop\Factory::create();
+ * $browser = new Clue\React\Buzz\Browser($loop);
+ *
+ * $wsdl = '<?xml …';
+ * $options = array();
+ *
+ * $client = new Client($browser, $wsdl, $options);
+ * ```
+ *
+ * If you need custom connector settings (DNS resolution, TLS parameters, timeouts,
+ * proxy servers etc.), you can explicitly pass a custom instance of the
+ * [`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface)
+ * to the [`Browser`](https://github.com/clue/reactphp-buzz#browser) instance:
+ *
+ * ```php
+ * $connector = new \React\Socket\Connector($loop, array(
+ * 'dns' => '127.0.0.1',
+ * 'tcp' => array(
+ * 'bindto' => '192.168.10.1:0'
+ * ),
+ * 'tls' => array(
+ * 'verify_peer' => false,
+ * 'verify_peer_name' => false
+ * )
+ * ));
+ *
+ * $browser = new Browser($loop, $connector);
+ * $client = new Client($browser, $wsdl);
+ * ```
+ *
+ * The `Client` works similar to PHP's `SoapClient` (which it uses under the
+ * hood), but leaves you the responsibility to load the WSDL file. This allows
+ * you to use local WSDL files, WSDL files from a cache or the most common form,
+ * downloading the WSDL file contents from an URL through the `Browser`:
+ *
+ * ```php
+ * $browser = new Browser($loop);
+ *
+ * $browser->get($url)->then(
+ * function (ResponseInterface $response) use ($browser) {
+ * // WSDL file is ready, create client
+ * $client = new Client($browser, (string)$response->getBody());
+ *
+ * // do something…
+ * },
+ * function (Exception $e) {
+ * // an error occured while trying to download the WSDL
+ * }
+ * );
+ * ```
+ *
+ * The `Client` constructor loads the given WSDL file contents into memory and
+ * parses its definition. If the given WSDL file is invalid and can not be
+ * parsed, this will throw a `SoapFault`:
+ *
+ * ```php
+ * try {
+ * $client = new Client($browser, $wsdl);
+ * } catch (SoapFault $e) {
+ * echo 'Error: ' . $e->getMessage() . PHP_EOL;
+ * }
+ * ```
+ *
+ * > Note that if you have `ext-xdebug` loaded, this may halt with a fatal
+ * error instead of throwing a `SoapFault`. It is not recommended to use this
+ * extension in production, so this should only ever affect test environments.
+ *
+ * The `Client` constructor accepts an array of options. All given options will
+ * be passed through to the underlying `SoapClient`. However, not all options
+ * make sense in this async implementation and as such may not have the desired
+ * effect. See also [`SoapClient`](http://php.net/manual/en/soapclient.soapclient.php)
+ * documentation for more details.
+ *
+ * If working in WSDL mode, the `$options` parameter is optional. If working in
+ * non-WSDL mode, the WSDL parameter must be set to `null` and the options
+ * parameter must contain the `location` and `uri` options, where `location` is
+ * the URL of the SOAP server to send the request to, and `uri` is the target
+ * namespace of the SOAP service:
+ *
+ * ```php
+ * $client = new Client($browser, null, array(
+ * 'location' => 'http://example.com',
+ * 'uri' => 'http://ping.example.com',
+ * ));
+ * ```
+ *
+ * Similarly, if working in WSDL mode, the `location` option can be used to
+ * explicitly overwrite the URL of the SOAP server to send the request to:
+ *
+ * ```php
+ * $client = new Client($browser, $wsdl, array(
+ * 'location' => 'http://example.com'
+ * ));
+ * ```
+ *
+ * You can use the `soap_version` option to change from the default SOAP 1.1 to
+ * use SOAP 1.2 instead:
+ *
+ * ```php
+ * $client = new Client($browser, $wsdl, array(
+ * 'soap_version' => SOAP_1_2
+ * ));
+ * ```
+ *
+ * You can use the `classmap` option to map certain WSDL types to PHP classes
+ * like this:
+ *
+ * ```php
+ * $client = new Client($browser, $wsdl, array(
+ * 'classmap' => array(
+ * 'getBankResponseType' => BankResponse::class
+ * )
+ * ));
+ * ```
+ *
+ * The `proxy_host` option (and family) is not supported by this library. As an
+ * alternative, you can configure the given `$browser` instance to use an
+ * [HTTP proxy server](https://github.com/clue/reactphp-buzz#http-proxy).
+ * If you find any other option is missing or not supported here, PRs are much
+ * appreciated!
+ *
+ * All public methods of the `Client` are considered *advanced usage*.
+ * If you want to call RPC functions, see below for the [`Proxy`](#proxy) class.
+ */
+class Client
+{
+ private $browser;
+ private $encoder;
+ private $decoder;
+
+ /**
+ * Instantiate a new SOAP client for the given WSDL contents.
+ *
+ * @param Browser $browser
+ * @param string|null $wsdlContents
+ * @param array $options
+ */
+ public function __construct(Browser $browser, $wsdlContents, array $options = array())
+ {
+ $wsdl = $wsdlContents !== null ? 'data://text/plain;base64,' . base64_encode($wsdlContents) : null;
+
+ // Accept HTTP responses with error status codes as valid responses.
+ // This is done in order to process these error responses through the normal SOAP decoder.
+ // Additionally, we explicitly limit number of redirects to zero because following redirects makes little sense
+ // because it transforms the POST request to a GET one and hence loses the SOAP request body.
+ $browser = $browser->withOptions(array(
+ 'obeySuccessCode' => false,
+ 'followRedirects' => true,
+ 'maxRedirects' => 0
+ ));
+
+ $this->browser = $browser;
+ $this->encoder = new ClientEncoder($wsdl, $options);
+ $this->decoder = new ClientDecoder($wsdl, $options);
+ }
+
+ /**
+ * Queue the given function to be sent via SOAP and wait for a response from the remote web service.
+ *
+ * ```php
+ * // advanced usage, see Proxy for recommended alternative
+ * $promise = $client->soapCall('ping', array('hello', 42));
+ * ```
+ *
+ * Note: This is considered *advanced usage*, you may want to look into using the [`Proxy`](#proxy) instead.
+ *
+ * ```php
+ * $proxy = new Proxy($client);
+ * $promise = $proxy->ping('hello', 42);
+ * ```
+ *
+ * @param string $name
+ * @param mixed[] $args
+ * @return PromiseInterface Returns a Promise<mixed, Exception>
+ */
+ public function soapCall($name, $args)
+ {
+ try {
+ $request = $this->encoder->encode($name, $args);
+ } catch (\Exception $e) {
+ $deferred = new Deferred();
+ $deferred->reject($e);
+ return $deferred->promise();
+ }
+
+ $decoder = $this->decoder;
+
+ return $this->browser->send($request)->then(
+ function (ResponseInterface $response) use ($decoder, $name) {
+ // HTTP response received => decode results for this function call
+ return $decoder->decode($name, (string)$response->getBody());
+ }
+ );
+ }
+
+ /**
+ * Returns an array of functions defined in the WSDL.
+ *
+ * It returns the equivalent of PHP's
+ * [`SoapClient::__getFunctions()`](http://php.net/manual/en/soapclient.getfunctions.php).
+ * In non-WSDL mode, this method returns `null`.
+ *
+ * @return string[]|null
+ */
+ public function getFunctions()
+ {
+ return $this->encoder->__getFunctions();
+ }
+
+ /**
+ * Returns an array of types defined in the WSDL.
+ *
+ * It returns the equivalent of PHP's
+ * [`SoapClient::__getTypes()`](http://php.net/manual/en/soapclient.gettypes.php).
+ * In non-WSDL mode, this method returns `null`.
+ *
+ * @return string[]|null
+ */
+ public function getTypes()
+ {
+ return $this->encoder->__getTypes();
+ }
+
+ /**
+ * Returns the location (URI) of the given webservice `$function`.
+ *
+ * Note that this is not to be confused with the WSDL file location.
+ * A WSDL file can contain any number of function definitions.
+ * It's very common that all of these functions use the same location definition.
+ * However, technically each function can potentially use a different location.
+ *
+ * The `$function` parameter should be a string with the the SOAP function name.
+ * See also [`getFunctions()`](#getfunctions) for a list of all available functions.
+ *
+ * ```php
+ * assert('http://example.com/soap/service' === $client->getLocation('echo'));
+ * ```
+ *
+ * For easier access, this function also accepts a numeric function index.
+ * It then uses [`getFunctions()`](#getfunctions) internally to get the function
+ * name for the given index.
+ * This is particularly useful for the very common case where all functions use the
+ * same location and accessing the first location is sufficient.
+ *
+ * ```php
+ * assert('http://example.com/soap/service' === $client->getLocation(0));
+ * ```
+ *
+ * When the `location` option has been set in the `Client` constructor
+ * (such as when in non-WSDL mode) or via the `withLocation()` method, this
+ * method returns the value of the given location.
+ *
+ * Passing a `$function` not defined in the WSDL file will throw a `SoapFault`.
+ *
+ * @param string|int $function
+ * @return string
+ * @throws \SoapFault if given function does not exist
+ * @see self::getFunctions()
+ */
+ public function getLocation($function)
+ {
+ if (is_int($function)) {
+ $functions = $this->getFunctions();
+ if (isset($functions[$function]) && preg_match('/^\w+ (\w+)\(/', $functions[$function], $match)) {
+ $function = $match[1];
+ }
+ }
+
+ // encode request for given $function
+ return (string)$this->encoder->encode($function, array())->getUri();
+ }
+
+ /**
+ * Returns a new `Client` with the updated location (URI) for all functions.
+ *
+ * Note that this is not to be confused with the WSDL file location.
+ * A WSDL file can contain any number of function definitions.
+ * It's very common that all of these functions use the same location definition.
+ * However, technically each function can potentially use a different location.
+ *
+ * ```php
+ * $client = $client->withLocation('http://example.com/soap');
+ *
+ * assert('http://example.com/soap' === $client->getLocation('echo'));
+ * ```
+ *
+ * As an alternative to this method, you can also set the `location` option
+ * in the `Client` constructor (such as when in non-WSDL mode).
+ *
+ * @param string $location
+ * @return self
+ * @see self::getLocation()
+ */
+ public function withLocation($location)
+ {
+ $client = clone $this;
+ $client->encoder = clone $this->encoder;
+ $client->encoder->__setLocation($location);
+
+ return $client;
+ }
+}