Code Monkey home page Code Monkey logo

async-soap-guzzle's Introduction

Asynchronous SOAP client

codecov.io workflow

An asynchronous SOAP client build on top of Guzzle. The SoapClient implements meng-tian/php-async-soap.

Requirement

PHP 7.1 --enablelibxml --enable-soap

Install

composer require meng-tian/async-soap-guzzle

Usage

From v0.4.0 or newer, an instance of Psr\Http\Message\RequestFactoryInterface and an instance of Psr\Http\Message\StreamFactoryInterface need to be injected into Meng\AsyncSoap\Guzzle\Factory. These two interfaces are defined in PSR-17 to create PSR-7 compliant HTTP instances. This change will decouple this library from any specific implementation of PSR-7 and PSR-17. Clients can determine which implementation of PSR-17 they want to use. Plenty of different implementations of PSR17 can be found from Packagist, e.g., symfony/psr-http-message-bridge, or laminas/laminas-diactoros.

  1. Require this library and an implementation of PSR-17 in your composer.json:
...
    "require": {
        "php": ">=7.1.0",
        "meng-tian/async-soap-guzzle": "~0.4.0",
        "laminas/laminas-diactoros": "^2.0"  # this can be replaced by any implementation of PSR-17
    },
...
  1. Run composer install

  2. Create your async SOAP client and call your SOAP messages:

use GuzzleHttp\Client;
use Meng\AsyncSoap\Guzzle\Factory;
use Laminas\Diactoros\RequestFactory;
use Laminas\Diactoros\StreamFactory;

$factory = new Factory();
$client = $factory->create(new Client(), new StreamFactory(), new RequestFactory(), 'http://www.webservicex.net/Statistics.asmx?WSDL');

// async call
$promise = $client->callAsync('GetStatistics', [['X' => [1,2,3]]]);
$result = $promise->wait();

// sync call
$result = $client->call('GetStatistics', [['X' => [1,2,3]]]);

// magic method
$promise = $client->GetStatistics(['X' => [1,2,3]]);
$result = $promise->wait();

License

This library is released under MIT license.

async-soap-guzzle's People

Contributors

alexeyshockov avatar meng-tian avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

async-soap-guzzle's Issues

laminas/laminas-diactoros is under require-dev

Trying to utilize this package but I get the error:

Class 'Laminas\Diactoros\StreamFactory' not found

I looked at the composer.json file and you have laminas/laminas-diactoros under require-dev. Shouldn't it be included under the require key if it's a package dependency?

Mocking response

When developing an adapter for one service, I encountered the problem of mocking soap responses. How would it be best to form a response through this package?

SoapHeader

Hi Meng,

I am trying to achieve below header

<soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing"> <wsse:Security soap:mustUnderstand="true" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <wsse:UsernameToken wsu:Id="UsernameToken"> <wsse:Username>USERNAME</wsse:Username> <wsse:Password Type="#PasswordText">PASS</wsse:Password> <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">nEmCjKCvNwnnY5CfyOq3fQ==</wsse:Nonce> <wsu:Created>2018-01-11T13:09:16.157Z</wsu:Created> </wsse:UsernameToken> </wsse:Security> <wsa:Action>URL/Account_Get</wsa:Action> <wsa:To>URL/JavaAxis</wsa:To> </soap:Header>

Below are my codes

$client = $this->factory->create(
            new \GuzzleHttp\Client(),
            'URL?WSDL',
            [
                'soap_version' => 'SOAP_1_2',
                'login'        => 'USERNAME',
                'password'     => 'PASSWORD',
                'location'     => 'URL/JavaAxis',
            ]
        );

$response = $client->call('FUNCTION_NAME', [['VAR_NAME' => 'VALUE']]);

So far it will only response NULL, anything that I've missed?

Appreciate your help.

Hold more information than the body

Right now this SoapClient uses only the Guzzle Response Body to work with. For a full usage it would be useful to have information like Header, Status Code etc.

Is there a plan to implement it?

Pool Async

I need to make several soap calls using a pool.

is there any way to do this

<?php

use GuzzleHttp\Pool;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Response;
use Meng\AsyncSoap\Guzzle\Factory;

require_once '../vendor/autoload.php';


$factory = new Factory();
$client = $factory->create(new Client(), 'http://www.dneonline.com/calculator.asmx?WSDL');

// async call

$data = [1, 2, 4, 5, 6];


$requests = function ($data) use ($client) {
    foreach ($data as $key => $value) {
        yield $key => $client->callAsync('Subtract', [['intA' => $value, 'intB' => 1]]);
    }
};

$pool = new Pool(new Client(), $requests($data), [
    'concurrency' => 500,
    'fulfilled' => function (Response $response, $index) use (&$data) {
        echo $data[$index] . ' - SUCESS' . PHP_EOL;
    },
    'rejected' => function ($reason, $index) use (&$data) {
        echo $reason->getResponse()->getBody()->getContents();
        echo $data[$index] . ' - ERROR' . PHP_EOL;
    }
]);


$promise = $pool->promise();
$promise->wait();

SOAP-ERROR: Parsing Schema: can't import schema

Hello ,

I have a soap call where the namespace url is different from the wsdl url.

$client = new \SoapClient('http://example.com/?wsdl', []);
 
 $client->__setSoapHeaders(
            new \SoapHeader('http://other.domain.tld', 'AuthHeader', [
                'Username' => $this->user,
                'Password' => $this->password,
                'ResellerCode' => $this->code,
            ]));
$client->someFunction();

works

$factory = new \Meng\AsyncSoap\Guzzle\Factory();
$client = $factory->create(new \GuzzleHttp\Client(), 'http://example.com/?wsdl');

$client->call(
    'someFunction',
    [],
    [
        new SoapHeader('http://other.domain.tld',[
                'Username' => $this->user,
                'Password' => $this->password,
                'ResellerCode' => $this->code,
            ])
    ]
);

returns
SOAP-ERROR: Parsing Schema: can't import schema from 'data://text/xml/_types/CommonTypes.xsd'

I'm guessing it's related to the namespace since i'm already using your package for other calls with no issues.

Is there anyway to set the namespace ?

SoapHeaders

Prior to using this package I used __setSoapHeaders to set my authentication. Doesn't seem to be any way to do that now..?

Why arguments required?

Some methods in services, witch used soap, have methods that do not need arguments. So i must put empty array to call method but it is unreadable code. Can you make it optional?

Make response after callAsync implements ResponseInterface

Hi,

I am using promise with guzzle implementation and as a promise callback i have been using ResponseInterface. Implementation of your asynchronous SOAP request (method callAsync) does not return request that implements ResponseInterface.

Is there some possible way to get response that implements ResponseInterface ? It would be great if the response from async soap guzzle will be the same as response after calling sendAsync in guzzle implementation.

Thank you very much

Thank you!

No issue here, just wanted to thank you for this awesome package. It actually makes working with Soap somewhat bearable! ๐Ÿ˜ƒ

Concurrent Async Calls

Hi Meng-Tian,

Have you managed to do multiple async calls at the same time? Currently, in most examples - you call wait on the promise which makes it synchronous.

I have tried few things but to no avail.

The above(atleast the first option) makes the requests in a non-blocking way, but it's the order and timing of the responses not making sense.

Suppose I have 3 similar requests all initiated at the same time calling the SoapClient async function below.

echo Request: #
$response = (yield $this->client->sendAsync($request, $requestOptions));
echo Response: #

The order goes like this for a http call of 5 seconds

Request 1, Request 2, Request 3 at T
First response received at T + 5
Second response received at T + 5 + 5
Third response received at T + 5 + 5 + 5

Note: I use all 4 of your libraries to send soap requests.

Request works with regular SoapClient but does not return response with this one.

I have a rather simple no-wsdl query:

with regular SoapClient I do:

  $context = stream_context_create([
    'ssl' => [
      // set some SSL/TLS specific options
      'verify_peer' => false,
      'verify_peer_name' => false,
      'allow_self_signed' => true
    ]
  ]);

  $soapClient = new SoapClientDebug(NULL, [
    'login' => self::$user,
    'password' => self::$pass,
    'location' => self::$endpointUrl,
    'uri' => 'urn:sap-com:document:sap:rfc:functions',
    'trace' => 1,
    'use' => SOAP_LITERAL,
    'style' => SOAP_SINGLE_ELEMENT_ARRAYS,
    'soap_version' => SOAP_1_1,
    'stream_context' => $context,
  ]);

  $soapVar = new \SoapVar('<FIRST>1234</FIRST><SECOND>ABC</SECOND>', XSD_ANYXML);

  return $soapClient->GET_VALUES($soapVar);

With this one I do:

$arguments = [
  'login' => self::$user,
  'password' => self::$pass,
  'location' => self::$endpointUrl,
  'uri' => 'urn:sap-com:document:sap:rfc:functions',
  'trace' => 1,
  'use' => SOAP_LITERAL,
  'style' => SOAP_SINGLE_ELEMENT_ARRAYS,
  'soap_version' => SOAP_1_1,
];

$request_options = array(
  'auth' => [self::$user, self::$pass],
  'verify' => FALSE,
);

$soapVar = new \SoapVar('<FIRST>1234</FIRST><SECOND>ABC</SECOND>', XSD_ANYXML);

$factory = new Factory();
$client = $factory->create(new Client($request_options), NULL, $arguments);

$promise = $client->callAsync(self::$getAllValuesService, [$soapVar]);
return $promise->wait();

where $getAllValuesService = "GET_VALUES"

For both instances I wrote out with debugger the request (xml), endpoint (url) and action for the actual soap request, and they are identical.. just with the guzzle soap I am returned the following error:

SoapFault: looks like we got no XML document in SoapClient->__soapCall() (line 60 of vendor/meng-tian/php-soap-interpreter/src/Soap.php).

Hoe someone more knowledgeable in this, than I, can help.

Best regards,

Alari

Response Soap Header

Hi @meng-tian,

This is a question, not an issue.

Is there any way to get the SOAP-ENV:Header (sample below) from the response after doing a soap call?

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing">
<SOAP-ENV:Header>
....
</SOAP-ENV:Header>
<SOAP-ENV:Body>
.....
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Edit: After a bit of investigation, I found the answer I was looking for. Basically, we can pass an argument by reference to the client caller function - the client then sets the output headers to this variable.

See $outputHeaders below.

$factory = new Factory();
$client = $factory->create(new Client($client_options), $wsdl);
$response = $client->call($name, array $arguments, array $options = null, $inputHeaders = null, array &$outputHeaders = null)

Regards,
Bilal

WSDL is not cached

Hi. Thanks for the library, it's working great here.

One minor annoyance is that SoapClient provides a wsdl_cache option that this library ignores, thus no WSDL is ever cached.

The cache_wsdl option is one of WSDL_CACHE_NONE, WSDL_CACHE_DISK, WSDL_CACHE_MEMORY or WSDL_CACHE_BOTH.

The cache would improve performance.

README error

Replace "composer install ..." to "composer require"

Class 'Meng\AsyncSoap\Guzzle\Factory' not found

Hi,

Suddenly My app started to not work and here is the issue:

Symfony\Component\Debug\Exception\FatalErrorException in SMSChannel.php line 21: Class 'Meng\AsyncSoap\Guzzle\Factory' not found


use GuzzleHttp\Client;
use Meng\AsyncSoap\Guzzle\Factory;
  $message = $notification->toSms($notifiable);
        $factory = new Factory();
        $client = $factory->create(new Client(), 'http://xxxxx/WebService.asmx?wsdl');
        $promise = $client->callAsync('SendMessage', [['Username' => env('SMS_USERNAME'),
        'Password' => env('SMS_PASSWORD'),
        'Number' => env('SMS_NUMBER'),
        'Mobile' => array('string' => substr($notifiable->mobile,1)) ,
        'Message' =>$message->text,
        'Type' => '1']]);
        $result = $promise->wait();

Need more info in Readme

Hi @meng-tian , first thank you so much for your work, i really apreciate!

I wrote this issue requesting more use cases, example errors responses,SoapFault...

Hope you can update please.

Thanks again!

Support for local WSDL file

When I'm using local WSDL file, it fails with an error from CURL.
I tried with path like "/some/path/file.wsdl" and "file:///some/path/file.wsdl" but it didn't work.

The error comes from here : https://github.com/meng-tian/async-soap-guzzle/blob/master/src/Factory.php#L33

The SoapClient class support local files and I thought it would be great if it was supported here too.

Maybe add a condition to check if the URI scheme is "file" and load WSDL data without using curl ?

Error installing async-soap-guzzle

C:\www\ICE\localization_manager>composer require meng-tian/async-soap-guzzle
?[30;43mThe "https://packagist.org/packages.json" file could not be downloaded: SSL operation failed with code 1. OpenSSL Error messages:
error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed
Failed to enable crypto
failed to open stream: operation failed?[39;49m

Impossible to recover XML request

It would be great to do accesible the XML REQUEST of a client to see the lastrequest, I see debuging that the XML request is in the client object. But is impossible to recover. Why is not possible to recover it?

some like _lastRequest is not working.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.