Goetas-webservices / soap-client

Overview

goetas-webservices / soap-client

Build Status

PHP implementation of SOAP 1.1 and 1.2 client specifications.

Strengths:

  • Pure PHP, no dependencies on ext-soap
  • Extensible (JMS event listeners support)
  • PSR-7 HTTP messaging
  • PSR-17 HTTP messaging factories
  • PSR-18 HTTP Client
  • No WSDL/XSD parsing on production
  • IDE type hinting support

Only document/literal style is supported and the webservice should follow the WS-I guidelines.

There are no plans to support the deprecated rpc and encoded styles. Webservices not following the WS-I specifications might work, but they are officially not supported.

Demo

goetas-webservices/soap-client-demo is a demo project that shows how to consume a SOAP api in a generic PHP web application.

Installation

The recommended way to install goetas-webservices / soap-client is using Composer:

Add this packages to your composer.json file.

{
    "require": {
        "goetas-webservices/soap-client": "^0.3",
    },
    "require-dev": {
        "goetas-webservices/wsdl2php": "^0.5.1",
    },
}

How to

To improve performance, this library is based on the concept that all the SOAP/WSDL metadata has to be compiled into PHP compatible metadata (in reality is a big plain PHP array, so is really fast).

To do this we have to define a configuration file (in this case called config.yml) that holds some important information.

Here is an example:

# config.yml

soap_client:
  alternative_endpoints:
    MyServiceName:
      MySoapPortName: http://localhost:8080/service

  namespaces:
    'http://www.example.org/test/': 'TestNs/MyApp'
  destinations_php:
    'TestNs/MyApp': soap/src
  destinations_jms:
    'TestNs/MyApp': soap/metadata
  aliases:
    'http://www.example.org/test/':
      MyCustomXSDType:  'MyCustomMappedPHPType'

  metadata:
    'test.wsdl': ~
    'http://www.webservicex.net/weather.asmx?WSDL': ~

This file has some important sections:

SOAP Specific

  • alternative_endpoints (optional) allows you to specify alternative URLs that can be used when developing your integration. If this parameter is not present, will be used the URL defined by the WSDL file, but if is set, will be used the specified URL for the service called MyServiceName and on MySoapPortName port.

  • unwrap_returns (optional, default: false) allows to define the "wrapped" SOAP services mode. Instructs the client to "unwrap" all the returns.

WSDL Specific

  • metadata specifies where are placed WSDL files that will be used to generate al the required PHP metadata.

XML/XSD Specific

  • namespaces (required) defines the mapping between XML namespaces and PHP namespaces. (in the example we have the http://www.example.org/test/ XML namespace mapped to TestNs\MyApp)

  • destinations_php (required) specifies the directory where to save the PHP classes that belongs to TestNs\MyApp PHP namespace. (in this example TestNs\MyApp classes will ne saved into soap/src directory.

  • destinations_jms (required) specifies the directory where to save JMS Serializer metadata files that belongs to TestNs\MyApp PHP namespace. (in this example TestNs\MyApp metadata will ne saved into soap/metadata directory.

  • aliases (optional) specifies some mappings that are handled by custom JMS serializer handlers. Allows to specify to do not generate metadata for some XML types, and assign them directly a PHP class. For that PHP class is necessary to create a custom JMS serialize/deserialize handler.

Metadata generation

In order to be able to use the SOAP client we have to generate some metadata and PHP classes.

To do it we can run:

bin/soap-client generate \
 tests/config.yml \
 --dest-class=GlobalWeather/Container/SoapClientContainer \
 soap/src-gw/Container 
  • bin/soap-client generate is the command we are running
  • tests/config.yml is a path to our configuration file
  • --dest-class=GlobalWeather/Container/SoapClientContainer allows to specify the fully qualified class name of the container class that will hold all the webservice metadata.
  • soap/src/Container is the path where to save the container class that holds all the webservice metadata (you will have to configure the auto loader to load it)

Using the client

Once all the metadata are generated we can use our SOAP client.

Let's see a minimal example:

getWeather(2010, "May", "USA", Header::asMustUnderstand(new SomeAuth('me', 'pwd'))); ">
// composer auto loader
require __DIR__ . '/vendor/autoload.php';

// instantiate the main container class
// the name was defined by --dest-class=GlobalWeather/Container/SoapClientContainer
// parameter during the generation process
$container = new SoapClientContainer();

// create a JMS serializer instance
$serializer = SoapContainerBuilder::createSerializerBuilderFromContainer($container)->build();
// get the metadata from the container
$metadata = $container->get('goetas_webservices.soap.metadata_reader');

$factory = new ClientFactory($metadata, $serializer);

/**
 * @var $client \GlobalWeather\SoapStubs\WeatherSoap
 */
 // get the soap client
$client = $factory->getClient('http://www.webservicex.net/weather.asmx?WSDL');

// call the webservice
$result = $client->getWeather(2010, "May", "USA");

// call the webservice with custom headers
$result = $client->getWeather(2010, "May", "USA", Header::asMustUnderstand(new SomeAuth('me', 'pwd')));

Please note the @var $client \GlobalWeather\SoapStubs\WeatherSoap. The generated metadata have also a "stub" class that allows modern IDE to give you type hinting for parameters and return data.

This allows you to develop faster your client.

Using the client with dynamic endpoints

Suppose that you have same Webservice with different endpoints (ex. for each customer), so you want to change endpoints dynamically and you don't want to write each new endpoint in your config and run the generator for each customer.

With the help of Symfony's EnvVarProcessorInterface, you can use alternative_endpoints to set dynamically the webservice endpoints.

Here is an example:

# config.yml
soap_client:
  alternative_endpoints:
    MyServiceName:
      MySoapPortName: 'env(custom_vars:ENDPOINT_SERVICE1_PORT1)'

So, SoapClientContainer will resolve at runtime the endpoint for the specific service and port and the value will be taken from the ENDPOINT_SERVICE1_PORT1 variable.

Example of simple class that implements EnvVarProcessorInterface, responsible for providing a values for our custom endpoint locations (as custom_vars:ENDPOINT_SERVICE1_PORT1).

// SimpleEnvVarProcessor.php used for the `env(custom_vars:*)` variables resolution

use Symfony\Component\DependencyInjection\EnvVarProcessorInterface;

class SimpleEnvVarProcessor implements EnvVarProcessorInterface
{
    private $map = [];

    public function __construct(array $map)
    {
        $this->map = $map;
    }

    public function getEnv($prefix, $name, \Closure $getEnv)
    {
        return $this->map[$name];
    }

    public static function getProvidedTypes()
    {
        return [];
    }
}

At the end, to use the SoapClientContainer:

set('container.env_var_processors_locator', $varContainer); // now $container can be used as explained in the section "Using the client"">
// instantiate our variable processor and set the values for our custom variables
$varProcessor = new SimpleEnvVarProcessor([
    'ENDPOINT_SERVICE1_PORT1' => 'http://localhost:8080/service'
]);

// create an empty symfony container and set into it the $varProcessor namined as 'custom_vars'
$varContainer = new \Symfony\Component\DependencyInjection\Container(); 
$varContainer->set('custom_vars', $varProcessor);

// create the soap container and use $varContainer "env()" style variables resolution
$container = new SoapClientContainer();
$container->set('container.env_var_processors_locator', $varContainer);

// now $container can be used as explained in the section "Using the client"

In this way the endpoint for the MyServiceName.MySoapPortName will be dynamically resolved to http://localhost:8080/service even if the WSDL stats something else.

Note

The code in this project is provided under the MIT license. For professional support contact [email protected] or visit https://www.goetas.com

Comments
  • Serializer Extend

    Serializer Extend

    Hi, Sorry for the question. But I have this metadata yml

    Igm\Synergy\Controllers\Boards\HotelMealPlansNotifRSType: properties: hotel: expose: true access_type: public_method serialized_name: Hotel accessor: getter: getHotel setter: setHotel type: Igm\Synergy\Controllers\Boards\HotelMealPlansNotifRSType\HotelAType mealPlans: expose: true access_type: public_method serialized_name: MealPlans accessor: getter: getMealPlans setter: setMealPlans type: array<Igm\Synergy\Controllers\Boards\HotelMealPlansNotifRSType\MealPlansAType\MealPlanAType> xml_list: inline: false entry_name: MealPlan skip_when_empty: true

    This class have this properties:

    class HotelMealPlansNotifRSType extends BaseController {

    /**
     * @property \Igm\Synergy\Controllers\Boards\HotelMealPlansNotifRSType\HotelAType
     * $hotel
     */
    private $hotel = null;
    
    /**
     * @property
     * \Igm\Synergy\Controllers\Boards\HotelMealPlansNotifRSType\MealPlansAType\MealPlanAType[]
     * $mealPlans
     */
    private $mealPlans = null;
    

    }

    So far, everything is correct. But this class extends from another: BaseController. I need to exclude the parent's class properties in JMS\Serializer\Metadata\PropertyMetadata Object

    With exclude : true, works from the HotelMealPlansNotifRSType but not from the extended properties.

    opened by victorgp89 9
  • Problem defining multiple inline schemas with the same targetNamespace

    Problem defining multiple inline schemas with the same targetNamespace

    Hi! First of all, thanks for all your efforts in trying to make soap work with PHP 👍 I know it's a pain..

    Talking about that, I've been playing (read: debugging) my third party SOAP webservice with your libraries and have the following issues:

    The WSDL (2.0) definition that I get from the webservice, has multiple inline schemas with the same targetNamespace. It seems like your schema reader is overwriting it everytime it finds a <xs:schema> line. I looked it up in the WSDL-2.0 spec at http://www.w3.org/TR/wsdl20/ which states:

    3.1.2 Inlining XML Schema ... A WSDL 2.0 document MAY inline two or more schemas from the same targetNamespace. For example, two or more inlined schemas can have the same targetNamespace provided that they do not define the same elements or types. A WSDL 2.0 document MUST NOT define the same element or type in more than one inlined schema. ...

    So the desired behaviour is that multiple schema nodes with the same targetNamespace should "extend" each other, not override. I'd like to make PR to make that happen. Before I start, any concerns, thoughts, ideas? :D

    opened by rvdbogerd 7
  • How to using your library?

    How to using your library?

    Hi,

    I'm trying use your library for source https://gclient.geis.cz/GService/GService.svc?singlewsdl, but I don't know if I have configured it incorrectly or source is not good. Can you explain where I can find error?

    My config file:

    soap_client:
    
      namespaces:
        'http://tempuri.org/': 'Soap/GeisClient'
      destinations_php:
        'Geis/Client': src/soap
      destinations_jms:
        'Geis/Client': src/soap/metadata
    
      metadata:
        'https://gclient.geis.cz/GService/GService.svc?singlewsdl': ~
    

    Command which I run

     vendor/goetas-webservices/soap-client/bin/soap-client generate \
     soap_config.yml \
     --dest-class=Soap/GeisClient \
     src/soap
    

    The result is this error:

    In SchemaReader.php line 597:
    Can't find type named {http://schemas.datacontract.org/2004/07/GService.Manager}#RequestOfServiceRequestHUsxwOXq, at line 1 in https://gclient.geis.cz/GService/GService.svc?singlewsdl  
    In Schema.php line 248:                                                                                                                         
    Can't find the Type named {http://schemas.datacontract.org/2004/07/GService.Manager}#RequestOfServiceRequestHUsxwOXq.                                                                                                                         
    

    Thanks

    bug 
    opened by radoslavius 4
  • Pass soapEndpoint and soapAction attributes on the serializer context

    Pass soapEndpoint and soapAction attributes on the serializer context

    Follow-up on #33:

    I have reduced the number of code changes and reverted the refactor, it made the PR unclear.

    I have now added a test for checking if the context parameters are correctly passed to the serializer handlers.

    opened by rvdbogerd 3
  • Location to save JMS metadata

    Location to save JMS metadata

    Hi, I have this config.yml:

    soap_client: ~
    xsd2php:
      namespaces:
        'http://dev.synergy.app/login': 'Igm\Synergy\Login'
        'http://dev.synergy.app/schema': 'Igm\Synergy\Schema'
        'http://dev.synergy.app/exception': 'Igm\Synergy\Exception'
        'http://dev.synergy.app/mealplans': 'Igm\Synergy\Controllers\Mealplans'
      destinations_php:
       'Igm\Synergy\Controllers\Mealplans': src/application/controllers/mealplans
       'Igm\Synergy\Schema': src/application/schema
       'Igm\Synergy\Login': src/application/login
       'Igm\Synergy\Exception': src/application/exception
      destinations_jms:
        'Igm\Synergy\Controllers\MealPlans': metadata/mealplans
        'Igm\Synergy\Login': metadata/login
        'Igm\Synergy\Exception': metadata/exception
    wsdl2php:
      metadata:
        '/var/www/igm_xml/include/mealplan.wsdl': ~
    

    The classes generate correctly but I have this error:

    Unable to determine location to save JMS metadata for class 'Igm\Synergy\Controllers\Mealplans\SoapEnvelope\Headers\GetMealPlansInput

    question 
    opened by victorgp89 3
  • Add soap action and endpoint as attributes on the SerializationContext

    Add soap action and endpoint as attributes on the SerializationContext

    Hi!

    Could we add these parameters to the SerializationContext? I really need this so that my custom Subscriber can add WS:Addressing and other security related headers to the soap message on serialization.

    opened by rvdbogerd 2
  • fix goetas-webservices/soap-client#26

    fix goetas-webservices/soap-client#26

    Fixes https://github.com/goetas-webservices/soap-client/issues/26

    Now i have notice that in operations array there is alread a method key that respect the same strategy, we can use it

    opened by riccardonar 2
  • Operation name in SoapStub class

    Operation name in SoapStub class

    I have this operation name OTA_HotelRateAmountNotif, it is transformed in oTAHotelRateAmountNotif in SoapStub class. https://github.com/goetas-webservices/soap-client/blob/049195ef277abce548d05348cfd51dd96d0f7cc6/src/StubGeneration/ClientStubGenerator.php#L109

    The operation oTAHotelRateAmountNotif isn't find by your Client because it checks the key of operations array only by strtolower in findOperation https://github.com/goetas-webservices/soap-client/blob/049195ef277abce548d05348cfd51dd96d0f7cc6/src/Client.php#L141

    A solution can be to compile operations array key with same strategy https://github.com/goetas-webservices/soap-client/blob/049195ef277abce548d05348cfd51dd96d0f7cc6/src/Metadata/Generator/MetadataGenerator.php#L91

    Or is it better to remove the camelize transformation in Stub generator?

    bug 
    opened by riccardonar 2
  • XSD2PHP

    XSD2PHP

    The definition "goetas_webservices.xsd2php.schema_reader" has a reference to an abstract definition "logger". Abstract definitions cannot be the target of references.

    This error in library why does it appear?

    opened by victorgp89 2
  • Pass soap context to serializer

    Pass soap context to serializer

    Follow-up on https://github.com/goetas-webservices/soap-client/pull/33:

    I have reduced the number of code changes and reverted the refactor, it made the PR unclear.

    I have now added a test for checking if the context parameters are correctly passed to the serializer handlers.

    opened by rvdbogerd 1
  • Is there a way to see/print the request and response messages?

    Is there a way to see/print the request and response messages?

    Is there a way to see/print the request and response messages? Something like a debug or test feature to print a log file with these messages? I would like to tag this as "help wanted" but I don't know how ...

    question 
    opened by etcware 1
  • About credentials

    About credentials

    Sorry I cannot reopen issue #61, I have an additional problem, I cannot generate the metadata because also to access to WSDL during metadata generation needs credentials...

    feature-request 
    opened by etcware 2
  • HTML_ENTITY_DECODE

    HTML_ENTITY_DECODE

    Hi Goetas, Thanks for your job. Is it possible to perform an html_entity_decode with some predeserialize event? I would not like to do it for all clients that use the api if not only for those that return this type of coding.

    question 
    opened by victorgp89 0
  • Can't make anyType to work with soap-client

    Can't make anyType to work with soap-client

    I'm consuming a Soap server that has some fields declared as xs:anyType.

    There's a note in xsd2php README.md about how to declare custom handlers for those types, but I can't get them to work with soap-client.

    Could you provide a short example to make it work ? How to register a custom JMS Serializer handler inside soap client container ?

    opened by Toilal 1
  • FAULTDETAIL

    FAULTDETAIL

    Hi,

    I wanted to see a problem I have about the Fault class. When a web service returns an object inside the FaultDetail like this:

    image

    I have seen that a FaultHandler had been created.

    What it does is insert the node as a string when it deserializes it:

    [detail:Igm\Synergy\SoapClient\Envelope\SoapEnvelope12\Parts\Fault:private] => <ns3:LinkHotelException xmlns:ns3="http://ws.link.test.hotelresb2b.com/exception"><ns3:errorCode>0221</ns3:errorCode><ns3:language>2</ns3:language><ns3:message>The room with this affiliation does not exist in the system.[asdsadsad]</ns3:message></ns3:LinkHotelException>

    Is it possible to emulate the behavior of HeaderPlaceHolder to be able to insert any type of object always inside?

    question 
    opened by victorgp89 0
  • Bug in example

    Bug in example

    Hi! I've tried to run example script from readme.md section 'Using the client'. Unsuccessfully. I finally got it started. I had to change: $metadata = $container->get('goetas_webservices.soap_client.metadata_reader'); to $metadata = $container->get('goetas_webservices.soap_client.metadata_loader.array');

    It's a bug or?

    opened by tomasz-kusy 4
Releases(v0.2.10)
Owner
Goetas Web Services
XML related webservice tools
Goetas Web Services
Guzzle, an extensible PHP HTTP client

Guzzle, PHP HTTP client Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and trivial to integrate with web services. Simple interf

Guzzle 22.3k Jan 2, 2023
A Chainable, REST Friendly, PHP HTTP Client. A sane alternative to cURL.

Httpful Httpful is a simple Http Client library for PHP 7.2+. There is an emphasis of readability, simplicity, and flexibility – basically provide the

Nate Good 1.7k Dec 21, 2022
PHP's lightweight HTTP client

Buzz - Scripted HTTP browser Buzz is a lightweight (<1000 lines of code) PHP 7.1 library for issuing HTTP requests. The library includes three clients

Kris Wallsmith 1.9k Jan 4, 2023
HTTPlug, the HTTP client abstraction for PHP

HTTPlug HTTPlug, the HTTP client abstraction for PHP. Intro HTTP client standard built on PSR-7 HTTP messages. The HTTPlug client interface is compati

The PHP HTTP group 2.4k Dec 30, 2022
Retrofit implementation in PHP. A REST client for PHP.

Retrofit PHP Retrofit is a type-safe REST client. It is blatantly stolen from square/retrofit and implemented in PHP. ❗ UPGRADE NOTICE ❗ Version 3 int

null 153 Dec 21, 2022
Unirest in PHP: Simplified, lightweight HTTP client library.

Unirest for PHP Unirest is a set of lightweight HTTP libraries available in multiple languages, built and maintained by Mashape, who also maintain the

Kong 1.3k Dec 28, 2022
↪️ Bypass for PHP creates a custom HTTP Server to return predefined responses to client requests

Bypass for PHP provides a quick way to create a custom HTTP Server to return predefined responses to client requests.Useful for tests with Pest PHP or PHPUnit.

CiaReis 101 Dec 1, 2022
A PHP proxy to solve client browser HTTP CORS(cross-origin) restrictions.

cors-bypass-proxy A PHP proxy to solve client browser HTTP CORS(cross-origin) restrictions. A simple way to solve CORS issue when you have no access t

Gracious Emmanuel 15 Nov 17, 2022
Zenscrape package is a simple PHP HTTP client-provider that makes it easy to parsing site-pages

Zenscrape package is a simple PHP HTTP client-provider that makes it easy to parsing site-pages

Andrei 3 Jan 17, 2022
Async HTTP/1.1+2 client for PHP based on Amp.

This package provides an asynchronous HTTP client for PHP based on Amp. Its API simplifies standards-compliant HTTP resource traversal and RESTful web

AMPHP 641 Dec 19, 2022
Event-driven, streaming HTTP client and server implementation for ReactPHP

HTTP Event-driven, streaming HTTP client and server implementation for ReactPHP. This HTTP library provides re-usable implementations for an HTTP clie

ReactPHP 640 Dec 29, 2022
Simple HTTP cURL client for PHP 7.1+ based on PSR-18

Simple HTTP cURL client for PHP 7.1+ based on PSR-18 Installation composer require sunrise/http-client-curl QuickStart composer require sunrise/http-f

Sunrise // PHP 15 Sep 5, 2022
amadeus-ws-client: PHP client for the Amadeus GDS SOAP Web Service interface

amadeus-ws-client: PHP client for the Amadeus GDS SOAP Web Service interface This client library provides access to the Amadeus GDS SOAP Web Service i

Amadeus Benelux 164 Nov 18, 2022
General purpose PHP SOAP-client

General purpose PHP SOAP-client Sick and tired of building crappy SOAP implementations? This package aims to help you with some common SOAP integratio

PHPro 695 Dec 26, 2022
Simple, async SOAP webservice client, built on top of ReactPHP.

clue/reactphp-soap Simple, async SOAP web service client library, built on top of ReactPHP. Most notably, SOAP is often used for invoking Remote proce

Christian Lück 62 Jul 5, 2022
Boilerplate between the Magento API and ImportExport, so that you can do fast Array/XMLRPC/SOAP based product imports.

Boilerplate between the Magento API and ImportExport, so that you can do fast Array/XMLRPC/SOAP based product imports.

Daniel Sloof 249 May 30, 2022
The Salla OAuth Client library is designed to provide client applications with secure delegated access to Salla Merchant stores.

Salla Provider for OAuth 2.0 Client This package provides Salla OAuth 2.0 support for the PHP League's OAuth 2.0 Client. To use this package, it will

Salla 14 Nov 27, 2022
Google-api-php-client - A PHP client library for accessing Google APIs

Google APIs Client Library for PHP Reference Docs https://googleapis.github.io/google-api-php-client/main/ License Apache 2.0 The Google API Client Li

Google APIs 8.4k Dec 30, 2022
PHP Kafka client is used in PHP-FPM and Swoole. PHP Kafka client supports 50 APIs, which might be one that supports the most message types ever.

longlang/phpkafka Introduction English | 简体中文 PHP Kafka client is used in PHP-FPM and Swoole. The communication protocol is based on the JSON file in

Swoole Project 235 Dec 31, 2022
PHP JSON-RPC 2.0 Server/Client Implementation with Automatic Client Class Generation via SMD

PHP JSON-RPC 2.0 Server/Client Implementation with Automatic Client Class Generation via SMD

Sergey Bykov 63 Feb 14, 2022