Giter Club home page Giter Club logo

ext-soap-engine's Introduction

Ext-SOAP powered SOAP engine

This package is a SOAP engine that leverages the built-in functions from PHP's ext-soap extension.

It basically flips the SoapClient inside out: All the built-in functions for encoding, decoding and HTTP transport can be used in a standalone way.

If your package contains a SoapClient, you might consider using this package as an alternative:

  • It gives you full control over the HTTP layer.
  • It validates the $options you pass to the SoapClient and gives you meaningful errors.
  • It transforms the types and methods into real objects so that you can actually use that information.
  • It makes it possible to use the encoding / decoding logic without doing any SOAP calls to a server.
  • ...

Want to help out? ๐Ÿ’š

Want more information about the future of this project? Check out this list of the next big projects we'll be working on.

Installation

composer require php-soap/ext-soap-engine

Example usage:

This example contains an advanced setup for creating a flexible ext-soap based engine. It shows you the main components that you can use for configuring PHP's SoapClient and to transform it into a SOAP engine:

use Soap\Engine\SimpleEngine;
use Soap\ExtSoapEngine\AbusedClient;
use Soap\ExtSoapEngine\Configuration\ClassMap\ClassMapCollection;
use Soap\ExtSoapEngine\Configuration\TypeConverter\TypeConverterCollection;
use Soap\ExtSoapEngine\ExtSoapDriver;
use Soap\ExtSoapEngine\ExtSoapOptions;
use Soap\ExtSoapEngine\Transport\ExtSoapClientTransport;
use Soap\ExtSoapEngine\Transport\TraceableTransport;

$engine = new SimpleEngine(
    ExtSoapDriver::createFromClient(
        $client = AbusedClient::createFromOptions(
            ExtSoapOptions::defaults($wsdl, [
                'soap_version' => SOAP_1_2,
            ])
                ->disableWsdlCache()
                ->withClassMap(new ClassMapCollection())
                ->withTypeMap(new TypeConverterCollection())
        )
    ),
    $transport = new TraceableTransport(
        $client,
        new ExtSoapClientTransport($client)
    )
);

Fetching a SOAP Resource:

$result = $engine->request('SomeMethod', [(object)['param1' => true]]);

// Collecting last soap call:
var_dump($transport->collectLastRequestInfo());

You can still set advanced configuration on the actual SOAP client:

$client->__setLocation(...);
$client->__setSoapHeaders(...);
$client->__setCookie(...);

Reading / Parsing metadata

var_dump(
    $engine->getMetadata()->getMethods(),
    $engine->getMetadata()->getTypes()
);

$methodInfo = $engine->getMetadata()->getMethods()->fetchByName('SomeMethod');

Engine

This package provides following engine components:

  • ExtSoapEncoder: Uses PHP's SoapClient in order to encode a mixed request body into a SOAP request.
  • ExtSoapDecoder: Uses PHP's SoapClient in order to decode a SOAP Response into mixed data.
  • ExtSoapMetadata: Parses the methods and types from PHP's SoapClient into something more usable.
  • ExtSoapDriver: Combines the ext-soap encoder, decoder and metadata tools into a usable ext-soap preset.

Transports

  • ExtSoapClientTransport: Uses PHP's SoapClient to handle SOAP requests.
  • ExtSoapServerTransport: Uses PHP's SoapServer to handle SOAP requests. It can e.g. be used during Unit tests.
  • TraceableTransport: Can be used to decorate another transport and keeps track of the last request and response. It should be used as an alternative for fetching it on the SoapClient.

In ext-soap, there are some well known issues regarding the HTTP layer. Therefore we recommend using the PSR-18 based transport instead of the ones above. Besides dealing with some issues, it also provides a set of middleware for dealing with some common issues you might not be able to solve with the regular SoapClient.

Configuration options

ExtSoapOptions

This package provides a little wrapper around all available \SoapClient options. It provides sensible default options. If you want to set specific options, you can do so in a sane way: It will validate the options before they are passed to the \SoapClient. This way, you'll spend less time browsing the official PHP documentation.

<?php

use Soap\ExtSoapEngine\ExtSoapOptions;
use Soap\ExtSoapEngine\Wsdl\Naming\Md5Strategy;use Soap\ExtSoapEngine\Wsdl\TemporaryWsdlLoaderProvider;
use Soap\Psr18Transport\Wsdl\Psr18Loader;
use Soap\Wsdl\Loader\FlatteningLoader;

$options = ExtSoapOptions::defaults($wsdl, ['location' => 'http://somedifferentserver.com'])
    ->disableWsdlCache()
    ->withClassMap(\MyClassMap::getCollection())
    ->withWsdlProvider(new TemporaryWsdlLoaderProvider(
        new FlatteningLoader(new Psr18Loader($httpClient)),
        new Md5Strategy(),
        'some/dir'
    ));

$typemap = $options->getTypeMap();
$typemap->add(new \MyTypeConverter());

WsdlProvider

A WSDL provider can be used in order to load a WSDL. Since ext-soap requires a loadable URL, it works slightly different from the wsdl loaders inside php-soap/wsdl.

use Soap\ExtSoapEngine\ExtSoapOptions;

$options = ExtSoapOptions::defaults($wsdl)
    ->withWsdlProvider($yourProvider);

This package contains some built-in providers:

InMemoryWsdlProvider

By using the in-memory WSDL provider, you can use a complete XML version of the WSDL as source. This one might come in handy during tests, but probably shouldn't be used in production.

<?php
use Soap\ExtSoapEngine\Wsdl\InMemoryWsdlProvider;

$provider = new InMemoryWsdlProvider();
$wsdl = ($provider)('<definitions ..... />');

PassThroughWsdlProvider

The pass-through WSDL provider is used by default. You can pass every string you would normally pass to the built-in SOAP client's wsdl option. No additional checks are executed, the loading of the file will be handled by the internal SoapClient class.

<?php
use Soap\ExtSoapEngine\Wsdl\PassThroughWsdlProvider;

$provider = new PassThroughWsdlProvider();
$wsdl = ($provider)('some.wsdl');

PermanentWsdlLoaderProvider

This provider can permanently cache a (remote) WSDL. This one is very useful to use in production, where the WSDL shouldn't change too much. You can force it to load to a permanent location in e.g. a cronjob. It will improve performance since the soap-client won't have to fetch the WSDL remotely. You can use any WSDL loader

<?php
use Soap\ExtSoapEngine\Wsdl\Naming\Md5Strategy;
use Soap\ExtSoapEngine\Wsdl\PermanentWsdlLoaderProvider;
use Soap\Wsdl\Loader\FlatteningLoader;
use Soap\Wsdl\Loader\StreamWrapperLoader;

$provider = new PermanentWsdlLoaderProvider(
    new FlatteningLoader(new StreamWrapperLoader()),
    new Md5Strategy(),
    'target/location'
);

// Force downloads:
$provider = $provider->forceDownload();

$wsdl = ($provider)('some.wsdl');

TemporaryWsdlLoaderProvider

This provider can temporarily fetch a (remote) WSDL through a WSDL loader. This one can be used in development, where WSDL files might change frequently. You can use any WSDL loader

<?php
use Soap\ExtSoapEngine\Wsdl\Naming\Md5Strategy;
use Soap\ExtSoapEngine\Wsdl\TemporaryWsdlLoaderProvider;
use Soap\Wsdl\Loader\FlatteningLoader;
use Soap\Wsdl\Loader\StreamWrapperLoader;

$provider = new TemporaryWsdlLoaderProvider(
    new FlatteningLoader(new StreamWrapperLoader()),
    new Md5Strategy(),
    'target/location'
);

$wsdl = ($provider)('some.wsdl');

Writing your own WSDL provider

Didn't find the WSDL provider you needed? No worries! It is very easy to create your own WSDL provider. The only thing you'll need to do is implement the WsdlProvider interface:

namespace Soap\ExtSoapEngine\Wsdl;

interface WsdlProvider
{
    /**
     * This method can be used to transform a location into another location.
     * The output needs to be processable by the SoapClient $wsdl option.
     */
    public function __invoke(string $location): string;
}

ClassMap

By providing a class map, you let ext-soap know how data of specific SOAP types can be converted to actual classes.

Usage:

use Soap\ExtSoapEngine\Configuration\ClassMap\ClassMap;
use Soap\ExtSoapEngine\ExtSoapOptions;

$options = ExtSoapOptions::defaults($wsdl);
$classmap = $options->getClassMap();
$classmap->set(new ClassMap('WsdlType', 'PhpClassName'));

TypeConverter

Some exotic XSD types are hard to transform to PHP objects. A typical example are dates: some people like it as a timestamp, some want it as a DateTime, ... By adding custom TypeConverters, it is possible to convert a WSDL type to / from a PHP type.

These TypeConverters are added by default:

  • DateTimeTypeConverter
  • DateTypeConverter
  • DoubleTypeConverter
  • DecimalTypeConverter

You can also create your own converter by implementing the TypeConverterInterface.

Usage:

use Soap\ExtSoapEngine\Configuration\TypeConverter;
use Soap\ExtSoapEngine\ExtSoapOptions;

$options = ExtSoapOptions::defaults($wsdl);
$typemap = $options->getTypeMap();
$typemap->add(new TypeCOnverter\DateTimeTypeConverter());
$typemap->add(new TypeConverter\DecimalTypeConverter());
$typemap->add(new TypeConverter\DoubleTypeConverter());

ext-soap-engine's People

Contributors

damosse31 avatar pableu avatar veewee avatar wannevancamp 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

Watchers

 avatar  avatar  avatar  avatar  avatar

ext-soap-engine's Issues

Incorrect work with SoapClient::__doRequest()

Bug Report

Q A
BC Break no
Version 1.1.0

Summary

Hello! SoapClient::__doRequest() does return nullable string, but AbusedClient::doActualRequest() expects string always.

https://www.php.net/manual/en/soapclient.dorequest.php

public SoapClient::__doRequest(
    string $request,
    string $location,
    string $action,
    int $version,
    bool $oneWay = false
): ?string
Soap\ExtSoapEngine\AbusedClient::doActualRequest(): Return value must be of type string, null returned
#0 php-soap/ext-soap-engine/src/Transport/ExtSoapClientTransport.php(26): Soap\ExtSoapEngine\AbusedClient->doActualRequest()
#1 php-soap/engine/src/SimpleEngine.php(25): Soap\ExtSoapEngine\Transport\ExtSoapClientTransport->request()
#2 phpro/soap-client/src/Phpro/SoapClient/Caller/EngineCaller.php(27): Soap\Engine\SimpleEngine->request()
#3 phpro/soap-client/src/Phpro/SoapClient/Caller/EventDispatchingCaller.php(30): Phpro\SoapClient\Caller\EngineCaller->__invoke()

How to reproduce

Sorry, I can't reproduce. You can replace to stub in test.

Expected behaviour

Without exception :)

Deprecated: Creation of dynamic property

Q A
Version 1.6.0

Support Question

In the ExtSoapDecoder we are getting the deprecation warnings: Creation of dynamic properties is deprecated, since php8.2. It's done in the soap client.

I was wondering, Is it possible to fix that or is that something internally for the php soap client?

How to force CDATA for a specific SOAP Element?

Q A
Version v1.3.0

hi @veewee,

i hope this project is still alive ;)
eBay had another great idea to make developers crazy ๐Ÿ˜• and I have no idea how to solve this with your project, so I please need some help/advise.

based on ebay WSDL I am able to generate the classmap and create a request like this:

<SOAP-ENV:Body>
        <ns1:ReviseFixedPriceItemRequest>
            <ns1:Item>
                <ns1:Description>&lt;!DOCTYPE html&gt; &lt;!--suppress HtmlFormInputWithoutLabel
                    --&gt; &lt;html&gt; &lt;head&gt; &lt;meta charset="UTF-8"/&gt;
                    &lt;title&gt;Kunde&lt;/title&gt; &lt;meta name="viewport"
                    content="width=device-width,initial-scale=1"/&gt; &lt;link rel="stylesheet"...................
                </ns1:Description>             
               </ns1:Item>
        </ns1:ReviseFixedPriceItemRequest>
    </SOAP-ENV:Body>

but ebay forces us (next month) to send this request like that:

<SOAP-ENV:Body>
    <ns1:ReviseFixedPriceItemRequest>
        <ns1:Item>
            <ns1:Description>
                <![CDATA[
                    <!DOCTYPE html> <!--suppress HtmlFormInputWithoutLabel --> <html> <head> <meta charset="UTF-8"/>
                    <title>Kunde</title> <meta name="viewport" content="width=device-width,initial-scale=1"/> <link rel="stylesheet"...................
                ]]>
            </ns1:Description>            
        </ns1:Item>
    </ns1:ReviseFixedPriceItemRequest>
</SOAP-ENV:Body>

and sadly I have absolutely no clue how to make this work.
i would be very happy, if you could help me here !! ๐Ÿ™ ๐Ÿ™

here's the latest trading WSDL of ebay.

thanks !!!
micha

Incorrect work with SoapClient in php8

Q A
Version 1.0.0

Support Question

Since php8 SoapClient::__doRequest() has bool $oneWay, not integer.

I have an error:

In AbusedClient.php line 64:                                                                                 
  SoapClient::__doRequest(): Argument #5 ($oneWay) must be of type bool, int given 

What am I doing wrong?

Throw exception on `null` results

Feature Request

Q A
New Feature yes
RFC no
BC Break no

Summary

Ext-soap returns null on various errorneous situations:

  • timeout reached
  • encoding failed
  • decoding failed
  • HTML result instead of XML
  • On invalid HTTP codes if the payload is HTML
  • ...

This null result can be handled by the AbusedClient and result in an exception instead - which makes more sense.

To investigate:

  • Can we find out "what" goes wrong that results in null?
  • Is null always an indication for errors? Or are there situations that a soap service doesn't return a response?

Context:

Request not described by WSDL

Q A
Version 1.3.0

Support Question

I'm implementing communication with external SOAP which requires secure conversation
(http://schemas.xmlsoap.org/ws/2005/02/sc). This involves requesting a security token, then signing of XML document for each method provided by WSDL service.

My question is how would anyone use library's SOAP client to make a request which is not described by WSDL? It is not supported out of the box, so any tip is welcome.

Action/method which is called for requesting security token is this:
http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT

Injecting AnyType converter into soap response

Let's take an example of response XSD schema:

<xsd:complexType name="ResponseData">
  <xsd:sequence>
    <xsd:element minOccurs="0" name="data" type="xsd:anyType"/>
  </xsd:sequence>
</xsd:complexType>

data here is anyType, meaning the payload follows a different schema unknown to this particular WSDL.

For decimal or dateTime, I could create a custom TypeConverterInterface and it will perfectly convert the data into my wrapper classes.

But for some reason I can't make ExtSoapDriver hijack anyType and use my custom converter, it will just return stdClass. I remember seeing some issues where it was suggested to add some extra manipulation, but can't seem to find it anywhere.

I can't generate original bindings and hard code that data field to my custom class because it's a general data structure for transport and the actual class will depend on the domain (hence why I'm trying to find a way to set it dynamically).

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.