diff --git a/.travis.yml b/.travis.yml index 111864b4..0173573f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,20 +6,19 @@ cache: matrix: include: - - php: 7.0 - - php: 7.0 - env: DEPENDENCIES='low' - php: 7.1 - php: 7.1 env: DEPENDENCIES='low' - php: 7.2 - php: 7.2 env: DEPENDENCIES='low' + - php: 7.3 + - php: 7.3 + env: DEPENDENCIES='low' fast_finish: true before_install: - composer selfupdate - - composer global require hirak/prestissimo install: - if [ "$DEPENDENCIES" != "low" ]; then travis_retry composer update --no-progress --profile --prefer-dist --no-scripts --no-interaction; fi; diff --git a/README.md b/README.md index 4518d08a..e0c8963c 100644 --- a/README.md +++ b/README.md @@ -46,18 +46,24 @@ You can customize the generated code based on the manual installation pages in t - [Add type converters.](docs/type-converter.md) - [Listen to events.](docs/events.md) - - [Logger plugin](docs/plugins/logger.md) - - [Validator plugin](docs/plugins/validator.md) - - [Caching plugin](docs/plugins/caching.md) -- [Specify your data transfer handler.](docs/handlers.md) - - [SoapHandle](docs/handlers.md#soaphandle) - - [HTTPlugHandle](docs/handlers.md#httplughandle) - - [LocalSoapServerHandle](docs/handlers.md#localsoapserverhandle) + - [Logger Subscriber](docs/event-subscribers/logger.md) + - [Validator Subscriber](docs/event-subscribers/validator.md) + - [Caching Subscriber](docs/event-subscribers/caching.md) +- [Get in control of the soap-client](docs/engine.md) + - [Choose a driver](docs/engine.md#driver) + - [ExtSoapDriver](docs/drivers/ext-soap.md) + - [Create your own driver](docs/drivers/new.md) + - [Specify your HTTP handler.](docs/engine.md#handler) + - [HttPlugHandle](docs/handlers/httplug.md) (Supports [middlewares](docs/middlewares.md)) + - [ExtSoapClientHandle](docs/handlers/ext-soap/client.md) + - [ExtSoapServerHandle](docs/handlers/ext-soap/local-server.md) + - [Create your own handler](docs/handlers/new.md) - [Configure one or multiple HTTP middlewares.](docs/middlewares.md) - [BasicAuthMiddleware](docs/middlewares.md#basicauthmiddleware) - [NtlmMiddleware](docs/middlewares.md#ntlmmiddleware) - [WsaMiddleware](docs/middlewares.md#wsamiddleware) - [WsseMiddleware](docs/middlewares.md#wssemiddleware) + - [Create your own middleware](docs/middlewares.md#creating-your-own-middleware) - [Select a WSDL Provider](docs/wsdl-providers.md) @@ -119,12 +125,17 @@ Implementing SOAP extensions is a real pain in the ass. You can specify which data transfer handler like e.g. Guzzle you want to use. Depending on the selected handler, you can easily add support for SOAP extensions or advanced authentication through HTTP middlewares. + +Dealing with ext-soap is not for all developers. There are some nasty quirks you need to know about. + Therefor, we made it possible for you to use which ever driver you want to use. + By default we will still ship an ext-soap driver, but it is completely opt-in. + You can use any user-land SoapClient implementation if you wrap it in our own driver interfaces. Testing webservices is hard! That is Why this package is fully compatible with [php-vcr](http://php-vcr.github.io/). Testing your SOAP client will be very fast and without any errors at the 3th party side of the integration. Last but not least, we want to make it easy for you to configure your SoapClient. - That is why we included a ClientBuilder on which you can configure your custom Client. + That is why we included a generated ClientFactory on which you can configure your custom Client. You want some other settings during development and in production? - No problem! Sit back and let the ClientBuilder handle your Client initialisation. + No problem! Sit back and let the factory handle your Client initialisation. diff --git a/composer.json b/composer.json index 12ed7d26..914dbf98 100644 --- a/composer.json +++ b/composer.json @@ -10,17 +10,17 @@ } ], "require": { - "php": "^7.0", - "ext-soap": "*", + "php": "^7.1", + "ext-dom": "*", "ext-xml": "*", - "doctrine/collections": "~1.3", "psr/log": "^1.0", "symfony/console": "~2.8|~3.0|~4.0", "symfony/event-dispatcher": "~2.8|~3.0|~4.0", "symfony/filesystem": "~2.8|~3.0|~4.0", - "symfony/validator": "~2.8|~3.0|~4.0" + "symfony/options-resolver": "^4.1" }, "require-dev": { + "ext-soap": "*", "guzzlehttp/guzzle": "^6.3.2", "guzzlehttp/promises": "^1.3.1", "guzzlehttp/psr7": "^1.4.2", @@ -36,27 +36,30 @@ "php-http/mock-client": "^1.0", "php-vcr/php-vcr": "~1.3.2", "php-vcr/phpunit-testlistener-vcr": "3.0", - "phpro/grumphp": "~0.11", - "phpspec/phpspec": "~3.2", - "phpspec/prophecy": "~1.7", + "phpro/grumphp": "~0.15", + "phpspec/phpspec": "~3.4", + "phpspec/prophecy": "~1.8", "phpunit/phpunit": "~6.0", "psr/http-message": "^1.0", "robrichards/wse-php": "^2.0.2", "robrichards/xmlseclibs": "^3.0", - "squizlabs/php_codesniffer": "~2.7", - "zendframework/zend-code": "^3.1.0" + "symfony/validator": "~2.8|~3.0|~4.0", + "squizlabs/php_codesniffer": "~2.9", + "zendframework/zend-code": "^3.3.1" }, "suggest": { - "doctrine/common": "For caching SOAP responses", + "ext-soap": "If you want to use PHP's ext-soap driver.", "php-http/client-implementation": "For gaining control over the HTTP layer", + "phpro/annotated-cache": "For caching SOAP responses", + "psr/log-implementation": "For logging SOAP requests, responses and errors", "psr/http-message": "For gaining control over the HTTP layer", "php-http/httplug": "For gaining control over the HTTP layer", "php-http/message-factory": "For gaining control over the HTTP layer", "php-http/discovery": "For gaining control over the HTTP layer", "php-http/message": "For gaining control over the HTTP layer", "php-http/client-common": "For gaining control over the HTTP layer", - "monolog/monolog": "For logging SOAP transactions", - "robrichards/wse-php": "If you want to use the WSA or WSSE middleware" + "robrichards/wse-php": "If you want to use the WSA or WSSE middleware", + "symfony/validator": "If you easily want to validate SOAP requests / responses manually" }, "autoload": { "psr-0": { diff --git a/docs/cli/generate-clientfactory.md b/docs/cli/generate-clientfactory.md index 0bd6990b..12183e13 100644 --- a/docs/cli/generate-clientfactory.md +++ b/docs/cli/generate-clientfactory.md @@ -34,25 +34,35 @@ Example output: namespace App\Client; -use App\Client\Client; +use App\Client\MyClient; use App\Order\OrderClassmap; -use Phpro\SoapClient\ClientFactory as PhproClientFactory; -use Phpro\SoapClient\ClientBuilder; +use Phpro\SoapClient\Soap\Driver\ExtSoap\ExtSoapEngineFactory; +use Phpro\SoapClient\Soap\Driver\ExtSoap\ExtSoapOptions; class ClientFactory { - public static function factory(string $wsdl) : \App\Client + public static function factory(string $wsdl) : \App\Client\MyClient { - $clientFactory = new PhproClientFactory(Client::class); - $clientBuilder = new ClientBuilder($clientFactory, $wsdl, []); - $clientBuilder->withClassMaps(OrderClassmap::getCollection()); + $engine = ExtSoapEngineFactory::fromOptions( + ExtSoapOptions::defaults($wsdl, []) + ->withClassMap(OrderClassmap::getCollection()) + ); + $eventDispatcher = new EventDispatcher(); - return $clientBuilder->build(); + return new MyClient($engine, $eventDispatcher); } + } ``` -You can then tweak this class to fit your needs. \ No newline at end of file +You can then tweak this class to fit your needs. + +Here you can find some bookmarks for changing the factory: + +- [Configuring ExtSoapOptions](../drivers/ext-soap.md#extsoapoptions) +- [Listening to events](../events.md) +- [Configuring the engine](../engine.md) +- [Using HTTP middleware](../middlewares.md) diff --git a/docs/code-generation/configuration.md b/docs/code-generation/configuration.md index 43609cb0..779dc6a4 100644 --- a/docs/code-generation/configuration.md +++ b/docs/code-generation/configuration.md @@ -9,9 +9,14 @@ The code generation commands require a configuration file to determine how the S use Phpro\SoapClient\CodeGenerator\Config\Config; use Phpro\SoapClient\CodeGenerator\Rules; use Phpro\SoapClient\CodeGenerator\Assembler; +use Phpro\SoapClient\Soap\Driver\ExtSoap\ExtSoapOptions; +use Phpro\SoapClient\Soap\Driver\ExtSoap\ExtSoapEngineFactory; return Config::create() - ->setWsdl('http://localhost/path/to/soap.wsdl') + ->setEngine(ExtSoapEngineFactory::fromOptions( + ExtSoapOptions::defaults('wsdl.xml', []) + ->disableWsdlCache() + )) ->setTypeDestination('src/SoapTypes') ->setTypeNamespace('SoapTypes') ->setClientDestination('src/SoapClient') @@ -20,7 +25,6 @@ return Config::create() ->setClassMapNamespace('Acme\\Classmap') ->setClassMapDestination('src/acme/classmap') ->setClassMapName('AcmeClassmap') - ->addSoapOption('features', SOAP_SINGLE_ELEMENT_ARRAYS) ->addRule(new Rules\AssembleRule(new Assembler\GetterAssembler( (new Assembler\GetterAssemblerOptions()) ->withReturnType() @@ -40,12 +44,15 @@ return Config::create() Luckily a command is provided to generate this for you in an interactive manner. Execute `vendor/bin/soap-client generate:config` to start the interactive config generator. -**wsdl** +**engine** -String - REQUIRED +`Phpro\SoapClient\Soap\Engine\Engine` - REQUIRED -The full path the the WSDL file you want to parse +Specify how the code generation tool can talk to SOAP. +By default, we push PHP's built-in ext-soap engine by code generation. +However, it is possible to change this to any other engine you want to use. +[Read more about engines.](../engine.md) **type destination** @@ -59,25 +66,6 @@ String - REQUIRED The destination of the generated soap client. - -**soapOptions** - -Array - OPTIONAL - -The soap options you want to add to the SoapClient during code generation. -Default values: - - -```php -[ - 'trace' => false, - 'exceptions' => true, - 'keep_alive' => true, - 'cache_wsdl' => WSDL_CACHE_NONE, -] -``` - - **type namespace** String - OPTIONAL diff --git a/docs/drivers/ext-soap.md b/docs/drivers/ext-soap.md new file mode 100644 index 00000000..fb0adbc0 --- /dev/null +++ b/docs/drivers/ext-soap.md @@ -0,0 +1,46 @@ +# ExtSoapDriver + +``` +❗️ Make sure ext-soap is loaded. +``` + +This soap driver wraps PHPs ext-soap `\SoapClient` implementation. + +- It abuses the `__doRequest()` method to make it possible to encode the request and decode the response. +- Metadata is being parsed based on the `__getTypes()` and `__getFunctions()` method. + +**Example usage** + +```php + 'http://somedifferentserver.com']) + ->disableWsdlCache() + ->withClassMap(MyClassMap::getCollection()) + ->withWsdlProvider(HttPlugWsdlProvider::createForClient($httpClient)); + +$typemap = $options->getTypeMap(); +$typemap->add(new MyTypeConverter()); +``` diff --git a/docs/drivers/new.md b/docs/drivers/new.md new file mode 100644 index 00000000..f3ef7108 --- /dev/null +++ b/docs/drivers/new.md @@ -0,0 +1,123 @@ +# Creating your own SOAP driver + +It is possible to use whatever package you want to handle metadata parsing, encoding and decoding inside the soap client. +This is done by specifying a custom driver. A driver consist of an encoder, a decoder and a metadata provider. + +- [Drivers](#drivers) +- [Encoders](#encoders) +- [Decoders](#decoders) +- [MetadataProviders](#metadataproviders) +- [Composition](#composition) + + +## Drivers + +You can create your own SOAP by implementing the `Phpro\SoapClient\Soap\Engine\DriverInterface` + +```php +addSubscriber(new LogSubscriber($logger)); +``` + +The logger accepts a PSR-3 `LoggerInterface`. + It will hook in to the Request, Response and Fault event and will log every step of the SOAP process. + No more code pollution for logging! diff --git a/docs/plugins/validator.md b/docs/event-subscribers/validator.md similarity index 64% rename from docs/plugins/validator.md rename to docs/event-subscribers/validator.md index d1fa944e..3fd0925f 100644 --- a/docs/plugins/validator.md +++ b/docs/event-subscribers/validator.md @@ -1,12 +1,24 @@ -# Validator plugin +# Validator Subscriber + +Require the symfony validator: + +```bash +composer require symfony/validator +``` + +Register the validator subscriber: + +```php +use Phpro\SoapClient\Event\Subscriber\ValidatorSubscriber; + +$eventDispatcher->addSubscriber(new ValidatorSubscriber($validator)); +``` It is possible to use the [Symfony validator component](https://symfony.com/doc/current/components/validator.html) to validate your request objects before sending them to the server. Since some servers return very cryptographic errors, the validation of request components could save you a lot of time during development. -The validator plugin is activated automatically when you attach a `ValidatorInterface` ` -to the `ClientBuilder::withValidator()`. It will hook in to the Request event and will throw a `RequestException` when your request object doesn't contain valid data. diff --git a/docs/events.md b/docs/events.md index 4aa58719..c865f829 100644 --- a/docs/events.md +++ b/docs/events.md @@ -1,6 +1,6 @@ # Hooking in with events -The `Client` class has a build-in EventDispatcher. +The `Client` class uses an EventDispatcher which can be configured inside the [generated client factory](cli/generate-clientfactory.md). It will trigger events at all important phases of the SOAP call: - Events::REQUEST (RequestEvent) @@ -20,6 +20,7 @@ $dispatcher->addSubscriber(new ResponseFailedSubscriber()); This package ships with some default subscriber plugins: -- [Logger plugin](plugins/logger.md) -- [Validator plugin](plugins/validator.md) -- [Caching plugin](plugins/caching.md) +- [Logger subscriber](event-subscribers/logger.md) +- [Validator subscriber](event-subscribers/validator.md) +- [Caching subscriber](event-subscribers/caching.md) + diff --git a/docs/handlers.md b/docs/handlers.md deleted file mode 100644 index d926a3a4..00000000 --- a/docs/handlers.md +++ /dev/null @@ -1,87 +0,0 @@ -# Use your preferred data transfer layer with Handlers - -The build-in SOAP client doesn't support extensions by default. -To overcome this problem, you are forced to overwrite the `__doRequest()` method. -By doing this, your code will be tied to the SoapClient which makes it hard to test and to reuse the logic. - -This package contains a handler system which allows you to get control over the HTTP layer of the soap client. -The handler system makes it possible to make changes to the request and the response before sending it to the server. - -Here is a list of built-in handlers: - -- [SoapHandle](#soaphandle) -- [HttPlugHandle](#guzzlehandle) -- [LocalSoapServerHandle](#localsoapserverhandle) - - -## SoapHandle - -*Features: LastRequestInfoCollector* - -The SoapHandle is used by default and works with the built-in `__doRequest()` method. -This Handle is not configurable and can be used for soap implementations which do not use extensions. -It is activated by default to get you going as quick as posible. - -**Configuration** -```php -$clientBuilder = new ClientBuilder($clientFactory, $wsdl, $soapOptions); -$client = $clientBuilder->build(); -``` - - -## HttPlugHandle - -*Features: LastRequestInfoCollector, MiddlewareSupporting* - -[HTTPlug](http://httplug.io/) is a HTTP client abstraction that can be used with multiple client packages. -With this handler it is easy to get in control about the HTTP layer of the SOAP client. -You can specify one or multiple middlewares that are being applied on your http client. -This makes it possible to manipulate the request and response objects so that you can get full control. - -This handler is based on middlewares which are applied to your guzzle client. -[You can read more about middlewares in this section.](middlewares.md) - -**Dependencies** - -Load HTTP plug core packages: - -```sh -composer require psr/http-message:^1.0 php-http/httplug:^1.1 php-http/message-factory:^1.0 php-http/discovery:^1.3 php-http/message:^1.6 php-http/client-common:^1.6 -``` - -**Select HTTP Client** - -Select one of the many clients you want to use to perform the HTTP requests: -http://docs.php-http.org/en/latest/clients.html#clients-adapters - -```sh -composer require php-http/client-implementation:^1.0 -``` - -**Configuration** -```php -$clientBuilder = new ClientBuilder($clientFactory, $wsdl, $soapOptions); -$clientBuilder->withHandler(HttPlugHandle::createForClient($httpClient)); -$client = $clientBuilder->build(); -``` - -## LocalSoapServerHandle - -*Features: LastRequestInfoCollector* - -The LocalSoapServerHandle can be used to link the soap-client to a local PHP SoapServer instance. -This handle can be used for testing purposes, it is not recommended to use it in production. - -*NOTE: * Since SoapServer is sending headers, you want to run this handler in a separate process. -You can use `@runInSeparateProcess` in PHPunit. - - -**Configuration** -```php -$soapServer = new \SoapServer('some.wsdl', []); -$soapServer->setObject($someTestingImplementation); - -$clientBuilder = new ClientBuilder($clientFactory, $wsdl, $soapOptions); -$clientBuilder->withHandler(new LocalSoapServerHandle($soapServer)); -$client = $clientBuilder->build(); -``` diff --git a/docs/handlers/ext-soap/client.md b/docs/handlers/ext-soap/client.md new file mode 100644 index 00000000..40826631 --- /dev/null +++ b/docs/handlers/ext-soap/client.md @@ -0,0 +1,24 @@ +# ExtSoapClientHandle + +*Features: LastRequestInfoCollector* + +``` +❗️ Make sure ext-soap is loaded. +``` + +The ExtSoapServerHandle is used by default and works with the built-in `__doRequest()` method. +This Handle is not configurable and can be used for soap implementations which do not use extensions. +It is activated by default to get you going as quick as possible. + + +**Example usage** + +```php +setObject($someTestingImplementation); + +$engine = ExtSoapEngineFactory::fromOptionsWithHandler( + ExtSoapOptions::defaults($wsdl, []), + new ExtSoapServerHandle($soapServer) +); +$client = new YourClient($engine, $eventDispatcher); +``` diff --git a/docs/handlers/httplug.md b/docs/handlers/httplug.md new file mode 100644 index 00000000..0cf683cf --- /dev/null +++ b/docs/handlers/httplug.md @@ -0,0 +1,52 @@ +# HttPlugHandle + +*Features: LastRequestInfoCollector, MiddlewareSupporting* + +[HTTPlug](http://httplug.io/) is a HTTP client abstraction that can be used with multiple client packages. +With this handler it is easy to get in control about the HTTP layer of the SOAP client. +You can specify one or multiple middlewares that are being applied on your http client. +This makes it possible to manipulate the request and response objects so that you can get full control. + +This handler knows how to deal with HTTP middlewares if they are supported by your HTTP client. +[You can read more about middlewares in this section.](../middlewares.md) + +**Dependencies** + +Load HTTP plug core packages: + +```sh +composer require psr/http-message:^1.0 php-http/httplug:^1.1 php-http/message-factory:^1.0 php-http/discovery:^1.3 php-http/message:^1.6 php-http/client-common:^1.6 +``` + + +**Select HTTP Client** + +Select one of the many clients you want to use to perform the HTTP requests: +http://docs.php-http.org/en/latest/clients.html#clients-adapters + +```sh +composer require php-http/client-implementation:^1.0 +``` + +**Example usage** + +```php + ['User-Agent' => 'testing/1.0']]) +); +$handler->addMiddleware(new BasicAuthMiddleware('user', 'password')); + +$engine = ExtSoapEngineFactory::fromOptionsWithHandler( + ExtSoapOptions::defaults($wsdl, []), + $handler +); +$client = new YourClient($engine, $eventDispatcher); +``` diff --git a/docs/handlers/new.md b/docs/handlers/new.md new file mode 100644 index 00000000..bfe1aaab --- /dev/null +++ b/docs/handlers/new.md @@ -0,0 +1,25 @@ +# Creating your own HTTP handler + +You can create your own HTTP handler by implementing the `HandlerInterface` + +```php + [ - [ - 'type_name' => 'base64Binary', - 'type_ns' => 'http://www.w3.org/2001/XMLSchema', - 'from_xml' => function($xml) { - $doc = new \DOMDocument(); - $doc->loadXML($xml); - - return $doc->textContent; - }, - 'to_xml' => function($raw) { - return sprintf('%s', $raw); - }, - ], - ], -]; -``` - -More information: - -- [Code in php-src](https://github.com/php/php-src/blob/php-7.2.10/ext/soap/php_encoding.c#L175) -- [Functional test](../../test/PhproTest/SoapClient/Functional/Encoding/Base64BinaryTest.php) - - ## Duplicate typenames When there are 2 types with the same name in different XML namespaces, @@ -81,7 +46,7 @@ Alternative workaround: More information: - [Code in php-src](https://github.com/php/php-src/blob/php-7.2.10/ext/soap/php_encoding.c#L468) -- [Functional test](../../test/PhproTest/SoapClient/Functional/Encoding/DuplicateTypenamesTest.php) +- [Functional test](../../test/PhproTest/SoapClient/Functional/ExtSoap/Encoding/DuplicateTypenamesTest.php) ## Enumerations @@ -102,7 +67,7 @@ For example: ``` - It is perfectly possible to pass a value of "InvalidData" to the server through the soap-client. -- Internally, ext-soap will not register any types, since it converts the value to a string. +- Internally, ext-soap will typehint this enum as a string so there is no complex type available. - You won't be able to access the available options without manually parsing the WSDL file. - If you do want to use a custom class for the enumerations type, you can create a type converter like this: @@ -127,34 +92,5 @@ $soapOptions = [ ``` More information: -- [Functional test](../../test/PhproTest/SoapClient/Functional/Encoding/EnumTest.php) +- [Functional test](../../test/PhproTest/SoapClient/Functional/ExtSoap/Encoding/EnumTest.php) - [Lack of validation in php-src](https://github.com/php/php-src/blob/php-7.2.10/ext/soap/php_encoding.c#L3172-L3200) - - -## SimpleContent - -Ext-soap does support `xsd:simpleContent` types. The implementation is a bit strange. - -Example: - -```xml - - - - - - - -``` - -- The `SimpleContent` complexType will be registered as a type. -- Code will be generated for this type. -- The fields are: - - country : string - - _ : int -- As you can see, the `_` field is being used as the xml textContent. - - -More information: -- [Functional test](../../test/PhproTest/SoapClient/Functional/Encoding/SimpleContentTest.php) - diff --git a/docs/middlewares.md b/docs/middlewares.md index b1b36200..4276eb19 100644 --- a/docs/middlewares.md +++ b/docs/middlewares.md @@ -1,12 +1,12 @@ # Get control of the HTTP layer with middlewares -If the SOAP server has some extensions enabled, it is hard to get them working with the built-in SOAP client. +If the SOAP server has some extensions enabled, it is hard to get them working with the ext-soap client. In many cases, you'll have to transform the XML request before sending it to the server or normalize the response XML before converting it back to objects. It is also possible to specify some custom HTTP headers to make sure you can authenticate on the remote server. To make sure your soap-client can work with middlewares, -you'll have to check if your [data transfer handler](handlers.md) supports middlewares. +you'll have to check if your [data transfer handler](engine.md#handler) supports middlewares. You can take a look to the list of handlers and check if your handler has the feature "MiddlewareSupporting". Next, you can use one of the built-in middlewares: @@ -31,7 +31,7 @@ This basic authentication middleware provides the features you need to add a use **Usage** ```php -$clientBuilder->addMiddleware(new BasicAuthMiddleware('username', 'password')); +$handler->addMiddleware(new BasicAuthMiddleware('username', 'password')); ``` @@ -58,7 +58,7 @@ composer require robrichards/wse-php:^2.0 **Usage** ```php -$clientBuilder->addMiddleware(new WsaMiddleware()); +$handler->addMiddleware(new WsaMiddleware()); ``` @@ -102,8 +102,8 @@ $wsse = new WsseMiddleware('privatekey.pem', 'publickey.pyb'); $wsse->withEncryption('client-x509.pem'); $wsse->withServerCertificateHasSubjectKeyIdentifier(true); -// Add it to the clientbuilder -$clientBuilder->addMiddleware($wsse); +// Add it to the handler +$handler->addMiddleware($wsse); ``` @@ -114,7 +114,7 @@ If you need to remove all empty nodes from the request xml, you can simply add t **Usage** ```php -$clientBuilder->addMiddleware(new RemoveEmptyNodesMiddleware()); +$handler->addMiddleware(new RemoveEmptyNodesMiddleware()); ``` @@ -131,7 +131,6 @@ property to false on the fly so that you don't have to change the WSDL on the se ```php $wsdlProvier = HttPlugWsdlProvider::create($client); $wsdlProvider->addMiddleware(new DisableExtensionsMiddleware()); -$clientBuilder->withWsdlProvider($wsdlProvider); ``` diff --git a/docs/plugins/logger.md b/docs/plugins/logger.md deleted file mode 100644 index 8dedfdac..00000000 --- a/docs/plugins/logger.md +++ /dev/null @@ -1,5 +0,0 @@ -# Logger plugin - -The logger plugin is activated automatically when you attach a `LoggerInterface` to the `ClientBuilder`. - It will hook in to the Request, Response and Fault event and will log every step of the SOAP process. - No more code pollution for logging! \ No newline at end of file diff --git a/docs/usage.md b/docs/usage.md index 834c5f5f..444825bd 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -4,33 +4,13 @@ Now that we explained all parts of your new SoapClient, it is time to interact w Look at following snippet: ```php -$wsdl = 'http://path.to/your.wsdl'; -$clientFactory = new ClientFactory(YourClient::class); -$soapOptions = [ - 'cache_wsdl' => WSDL_CACHE_NONE -]; - -$clientBuilder = new ClientBuilder($clientFactory, $wsdl, $soapOptions); -$clientBuilder->withLogger(new Logger()); -$clientBuilder->withEventDispatcher(new EventDispatcher()); -$clientBuilder->addClassMap(new ClassMap('WsdlType', PhpType::class)); -$clientBuilder->addTypeConverter(new DateTimeTypeConverter()); -$client = $clientBuilder->build(); - +$client = MyclientFactory::factory($wsdl = 'http://path.to/your.wsdl'); $response = $client->helloWorld(new HelloWorldRequest('name')); echo $response->getGreeting(); ``` -Note: The `Logger` class is not provided by this package, use any PSR-3 compatible logger here (i.e. monolog). - -In the first part of the snippet you can see the global configuration of your own SOAP client. - The `YourClient` class will be instantiated by a `ClientFactory`, which is responsible for injecting the client dependencies. - It is possible to use the same Client with different WSDL endpoints and SOAP options. - This makes it easy for changing between environments. - -Next, the client will be configured by the `ClientBuilder`. - As you can see it is possible to add a Logger, EventDispatcher, Classmaps and TypeConverters. - This makes the Soap client fully configurable. +The client will be initialized inside your generated client factory. + More information about the [generated client factory can be found here](cli/generate-clientfactory.md). In the last part of the snippet you can see how the client works. It will use the generated value-objects to call the `RequestInterface` on the SoapClient. @@ -38,4 +18,4 @@ In the last part of the snippet you can see how the client works. Readable, right? A client implements a single WSDL, so when the service you are implementing has multiple WSDL's then you'll need to create a client for each of the WSDL's you want to use. - You can then manually create a wrapper class if you desire to do so. \ No newline at end of file + You can then manually create a wrapper class if you desire to do so. diff --git a/docs/wsdl-providers.md b/docs/wsdl-providers.md index b5090972..f78953d2 100644 --- a/docs/wsdl-providers.md +++ b/docs/wsdl-providers.md @@ -4,14 +4,25 @@ The built-in SOAP client does not give you control on how the WSDL is downloaded Therefor we've created a `WsdlProvider` mechanism that can be customized to your demands. -General configuration: +**Example usage** ```php -$clientBuilder = new ClientBuilder($clientFactory, $wsdl, $soapOptions); -$clientBuilder->withWsdlProvider($provider); -$client = $clientBuilder->build(); +/** @var \Phpro\SoapClient\Wsdl\Provider\WsdlProviderInterface $provider */ +$wsdl = $provider->provide('my.wsdl'); ``` + +**Example usage with SoapOptions** +```php +withWsdlProvider($provider); +``` + + Here is a list of built-in providers: - [HttPlugWsdlProvider](#httplugwsdlprovider) @@ -46,8 +57,11 @@ http://docs.php-http.org/en/latest/clients.html#clients-adapters composer require php-http/client-implementation:^1.0 ``` -**Configuration** +**Usage** ```php +setLocation('/some/destination/file.wsdl'); // Middlewares support: $provider->addMiddleware($middleware); - - -// Register to the client builder -$clientBuilder = new ClientBuilder($clientFactory, $wsdl, $soapOptions); -$clientBuilder->withWsdlProvider($provider); -$client = $clientBuilder->build(); ``` -*Note:* If you want to cache the WSDL so that you don't have to download it on every request, you can use the built-in caching options: - -```php -$clientBuilder = new ClientBuilder($clientFactory, $wsdl, [ - 'cache_wsdl' => WSDL_CACHE_BOTH, -]); -``` +*Note:* If you want to cache the WSDL so that you don't have to download it on every request, you can use ext-soap `cache_wsdl` option. To change the TTL of the cache, you can adjust following `php.ini` setting: @@ -84,12 +86,13 @@ soap.wsdl_cache_ttl: 86400 By using the in-memory WSDL provider, you can just 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. -**Configuration** +**Usage** ```php -$wsdl = '' -$clientBuilder = new ClientBuilder($clientFactory, $wsdl, $soapOptions); -$clientBuilder->withWsdlProvider(new InMemoryWsdlProvider()); -$client = $clientBuilder->build(); +provide(''); ``` @@ -98,11 +101,12 @@ $client = $clientBuilder->build(); The local WSDL provider can be used to load a local file. It contains an additional check to make sure that the WSDL file exists and throws a `WsdlException` if it does not exist. -**Configuration** +**Usage** ```php -$clientBuilder = new ClientBuilder($clientFactory, $wsdl, $soapOptions); -$clientBuilder->withWsdlProvider(LocalWsdlProvider::create()); -$client = $clientBuilder->build(); +withWsdlProvider(new MixedWsdlProvider()); -$client = $clientBuilder->build(); + ./test/PhproTest/SoapClient/Integration - - ./test/PhproTest/SoapClient/Functional - diff --git a/spec/Phpro/SoapClient/ClientFactorySpec.php b/spec/Phpro/SoapClient/ClientFactorySpec.php deleted file mode 100644 index 63c0eddc..00000000 --- a/spec/Phpro/SoapClient/ClientFactorySpec.php +++ /dev/null @@ -1,29 +0,0 @@ -beConstructedWith(Client::class); - } - - function it_is_initializable() - { - $this->shouldHaveType(ClientFactory::class); - } - - function it_should_load_a_new_client(SoapClient $soapClient, EventDispatcherInterface $dispatcher) - { - $this->factory($soapClient, $dispatcher)->shouldReturnAnInstanceOf(Client::class); - } -} diff --git a/spec/Phpro/SoapClient/ClientSpec.php b/spec/Phpro/SoapClient/ClientSpec.php index cfd46f74..436542c7 100644 --- a/spec/Phpro/SoapClient/ClientSpec.php +++ b/spec/Phpro/SoapClient/ClientSpec.php @@ -4,6 +4,7 @@ use Phpro\SoapClient\Client; use Phpro\SoapClient\ClientInterface; +use Phpro\SoapClient\Soap\Engine\EngineInterface; use Phpro\SoapClient\Soap\SoapClient; use PhpSpec\ObjectBehavior; use Prophecy\Argument; @@ -11,9 +12,9 @@ class ClientSpec extends ObjectBehavior { - function let(SoapClient $soapClient, EventDispatcherInterface $dispatcher) + function let(EngineInterface $engine, EventDispatcherInterface $dispatcher) { - $this->beConstructedWith($soapClient, $dispatcher); + $this->beConstructedWith($engine, $dispatcher); } function it_is_initializable() diff --git a/spec/Phpro/SoapClient/CodeGenerator/ClientGeneratorSpec.php b/spec/Phpro/SoapClient/CodeGenerator/ClientGeneratorSpec.php index bb3637b6..0cd965b3 100644 --- a/spec/Phpro/SoapClient/CodeGenerator/ClientGeneratorSpec.php +++ b/spec/Phpro/SoapClient/CodeGenerator/ClientGeneratorSpec.php @@ -9,6 +9,7 @@ use Phpro\SoapClient\CodeGenerator\Model\Client; use Phpro\SoapClient\CodeGenerator\Model\ClientMethod; use Phpro\SoapClient\CodeGenerator\Model\ClientMethodMap; +use Phpro\SoapClient\CodeGenerator\Model\Parameter; use Phpro\SoapClient\CodeGenerator\Rules\RuleSetInterface; use PhpSpec\ObjectBehavior; use Prophecy\Argument; @@ -40,7 +41,7 @@ function it_is_a_generator() function it_generates_clients(RuleSetInterface $ruleSet, FileGenerator $file, Client $client, ClientMethodMap $map, ClassGenerator $class) { - $method = ClientMethod::createFromExtSoapFunctionString('TestResponse Test(Test $parameters)', 'MyParameterNamespace'); + $method = new ClientMethod('Test', [new Parameter('parameters', 'Test')], 'TestResponse'); $ruleSet->applyRules(Argument::type(ClientMethodContext::class))->shouldBeCalled(); $file->generate()->willReturn('code'); $file->getClass()->willReturn($class); diff --git a/spec/Phpro/SoapClient/CodeGenerator/Config/ConfigSpec.php b/spec/Phpro/SoapClient/CodeGenerator/Config/ConfigSpec.php index ac41a2ca..1ae2dd25 100644 --- a/spec/Phpro/SoapClient/CodeGenerator/Config/ConfigSpec.php +++ b/spec/Phpro/SoapClient/CodeGenerator/Config/ConfigSpec.php @@ -7,6 +7,7 @@ use Phpro\SoapClient\CodeGenerator\Rules\RuleSet; use Phpro\SoapClient\Exception\InvalidArgumentException; use Phpro\SoapClient\Exception\WsdlException; +use Phpro\SoapClient\Soap\Engine\EngineInterface; use Phpro\SoapClient\Util\Filesystem; use Phpro\SoapClient\Wsdl\Provider\LocalWsdlProvider; use Phpro\SoapClient\Wsdl\Provider\MixedWsdlProvider; @@ -31,34 +32,15 @@ function it_is_a_config_class() $this->shouldImplement(ConfigInterface::class); } - function it_has_a_wsdl() + function it_has_an_engine(EngineInterface $engine) { - $this->setWsdl($value = 'http://myservice/some.wsdl'); - $this->getWsdl()->shouldReturn($value); + $this->setEngine($engine); + $this->getEngine()->shouldReturn($engine); } - function it_has_a_wsdl_provider() + function it_requires_an_engine() { - $this->getWsdlProvider()->shouldImplement(MixedWsdlProvider::class); - } - - function it_can_overwrite_wsdl_prover() - { - $this->setWsdlProvider($value = new LocalWsdlProvider(new Filesystem())); - $this->getWsdlProvider()->shouldReturn($value); - } - - function it_requires_a_wsdl() - { - $this->shouldThrow(InvalidArgumentException::class)->duringGetWsdl(); - } - - function it_requires_a_valid_wsdl_provider(WsdlProviderInterface $wsdlProvider) - { - $this->setWsdl($wsdl = 'some.wsdl'); - $wsdlProvider->provide($wsdl)->willThrow(WsdlException::class); - $this->setWsdlProvider($wsdlProvider); - $this->shouldThrow(InvalidArgumentException::class)->duringGetWsdl(); + $this->shouldThrow(InvalidArgumentException::class)->duringGetEngine(); } function it_requires_a_typedestination() @@ -72,24 +54,6 @@ function it_has_a_ruleset() $this->getRuleSet()->shouldBe($value); } - function it_had_soap_options() - { - $this->getSoapOptions()->shouldBe( - [ - 'trace' => false, - 'exceptions' => true, - 'keep_alive' => true, - 'cache_wsdl' => WSDL_CACHE_NONE, - ] - ); - - $this->setSoapOptions($value = []); - $this->getSoapOptions()->shouldBe($value); - - $this->addSoapOption('key', 'value'); - $this->getSoapOptions()->shouldBe(['key' => 'value']); - } - public function it_has_a_type_destination() { $this->setTypeDestination($value = 'src/type'); diff --git a/spec/Phpro/SoapClient/CodeGenerator/Model/TypeMapSpec.php b/spec/Phpro/SoapClient/CodeGenerator/Model/TypeMapSpec.php index c334a385..87c40b5d 100644 --- a/spec/Phpro/SoapClient/CodeGenerator/Model/TypeMapSpec.php +++ b/spec/Phpro/SoapClient/CodeGenerator/Model/TypeMapSpec.php @@ -2,6 +2,7 @@ namespace spec\Phpro\SoapClient\CodeGenerator\Model; +use Phpro\SoapClient\CodeGenerator\Model\Property; use Phpro\SoapClient\CodeGenerator\Model\Type; use Phpro\SoapClient\CodeGenerator\Model\TypeMap; use PhpSpec\ObjectBehavior; @@ -17,10 +18,10 @@ class TypeMapSpec extends ObjectBehavior { function let() { - $this->beConstructedWith('MyNamespace', [ - 'type1' => [ - 'prop1' => 'string', - ], + $this->beConstructedWith($namespace = 'MyNamespace', [ + new Type($namespace, 'type1', [ + new Property('prop1', 'string', $namespace) + ]) ]); } diff --git a/spec/Phpro/SoapClient/CodeGenerator/Model/TypeSpec.php b/spec/Phpro/SoapClient/CodeGenerator/Model/TypeSpec.php index 0c893d84..8eb9d82f 100644 --- a/spec/Phpro/SoapClient/CodeGenerator/Model/TypeSpec.php +++ b/spec/Phpro/SoapClient/CodeGenerator/Model/TypeSpec.php @@ -17,7 +17,11 @@ class TypeSpec extends ObjectBehavior { function let() { - $this->beConstructedWith('MyNamespace', 'myType', ['prop1' => 'string']); + $this->beConstructedWith( + $namespace = 'MyNamespace', + 'myType', + [new Property('prop1', 'string', $namespace)] + ); } function it_is_initializable() @@ -58,7 +62,12 @@ function it_should_not_replace_underscores_in_paths() function it_should_prefix_reserved_keywords() { - $this->beConstructedWith('MyNamespace', 'Final', ['xor' => 'string']); + $this->beConstructedWith( + $namespace = 'MyNamespace', + 'Final', + [new Property('xor', 'string', $namespace)] + ); + $this->getFileInfo('my/some_dir')->getPathname()->shouldReturn('my/some_dir/FinalType.php'); $this->getName()->shouldReturn('FinalType'); $this->getProperties()[0]->getName()->shouldReturn('xor'); diff --git a/spec/Phpro/SoapClient/CodeGenerator/Parser/FunctionStringParserSpec.php b/spec/Phpro/SoapClient/CodeGenerator/Parser/FunctionStringParserSpec.php deleted file mode 100644 index b51ae6f9..00000000 --- a/spec/Phpro/SoapClient/CodeGenerator/Parser/FunctionStringParserSpec.php +++ /dev/null @@ -1,45 +0,0 @@ -beConstructedWith('TestResponse Test(Test1 $parameter1, Test2 $parameter2)', 'MyParameterNamespace'); - } - - function it_is_initializable() - { - $this->shouldHaveType(FunctionStringParser::class); - } - - function it_should_parse_parameters() { - $result = $this->parseParameters(); - $result->shouldHaveCount(2); - - $result[0]->shouldHaveType(Parameter::class); - $result[0]->getName()->shouldBe('parameter1'); - $result[0]->getType()->shouldBe('MyParameterNamespace\Test1'); - - $result[1]->shouldHaveType(Parameter::class); - $result[1]->getName()->shouldBe('parameter2'); - $result[1]->getType()->shouldBe('MyParameterNamespace\Test2'); - } - - function it_should_parse_name() { - $this->parseName()->shouldReturn('Test'); - } - - function it_should_parse_return_type() { - $this->parseReturnType()->shouldReturn('TestResponse'); - } -} diff --git a/spec/Phpro/SoapClient/CodeGenerator/TypeGeneratorSpec.php b/spec/Phpro/SoapClient/CodeGenerator/TypeGeneratorSpec.php index f942a70e..c0eaffa7 100644 --- a/spec/Phpro/SoapClient/CodeGenerator/TypeGeneratorSpec.php +++ b/spec/Phpro/SoapClient/CodeGenerator/TypeGeneratorSpec.php @@ -6,6 +6,7 @@ use Phpro\SoapClient\CodeGenerator\Context\PropertyContext; use Phpro\SoapClient\CodeGenerator\Context\TypeContext; use Phpro\SoapClient\CodeGenerator\GeneratorInterface; +use Phpro\SoapClient\CodeGenerator\Model\Property; use Phpro\SoapClient\CodeGenerator\Model\Type; use Phpro\SoapClient\CodeGenerator\Rules\RuleSetInterface; use Phpro\SoapClient\CodeGenerator\TypeGenerator; @@ -40,7 +41,11 @@ function it_is_a_generator() function it_generates_types(RuleSetInterface $ruleSet, FileGenerator $file, ClassGenerator $class) { - $type = new Type('MyNamespace', 'MyType', ['prop1' => 'string']); + $type = new Type( + $namespace = 'MyNamespace', + 'MyType', + [new Property('prop1', 'string', $namespace)] + ); $property = $type->getProperties()[0]; $file->generate()->willReturn('code'); diff --git a/spec/Phpro/SoapClient/CodeGenerator/Util/NormalizerSpec.php b/spec/Phpro/SoapClient/CodeGenerator/Util/NormalizerSpec.php index 1a4acce7..5d70c4d4 100644 --- a/spec/Phpro/SoapClient/CodeGenerator/Util/NormalizerSpec.php +++ b/spec/Phpro/SoapClient/CodeGenerator/Util/NormalizerSpec.php @@ -36,6 +36,19 @@ function it_can_normalize_classnames() $this->normalizeClassname('my-./final*type_123')->shouldReturn('MyFinalType123'); } + function it_can_normalize_fqn_classnames() + { + $this->normalizeClassnameInFQN('ns1\\myType')->shouldReturn('ns1\\MyType'); + $this->normalizeClassnameInFQN('ns1\\final')->shouldReturn('ns1\\FinalType'); + $this->normalizeClassnameInFQN('ns1\\Final')->shouldReturn('ns1\\FinalType'); + $this->normalizeClassnameInFQN('ns1\\UpperCased')->shouldReturn('ns1\\UpperCased'); + $this->normalizeClassnameInFQN('ns1\\my-./*type_123')->shouldReturn('ns1\\MyType123'); + $this->normalizeClassnameInFQN('ns1\\my-./final*type_123')->shouldReturn('ns1\\MyFinalType123'); + + $this->normalizeClassnameInFQN('string')->shouldReturn('string'); + $this->normalizeClassnameInFQN('NoNamespace')->shouldReturn('NoNamespace'); + } + function it_can_normalize_method_names() { $this->normalizeMethodName('myMethod')->shouldReturn('myMethod'); @@ -66,13 +79,13 @@ function it_normalizes_datatypes() $this->normalizeDataType('Iterator')->shouldReturn('Iterator'); $this->normalizeDataType('long')->shouldReturn('int'); $this->normalizeDataType('short')->shouldReturn('int'); - $this->normalizeDataType('dateTime')->shouldReturn('\\DateTime'); - $this->normalizeDataType('date')->shouldReturn('\\DateTime'); + $this->normalizeDataType('dateTime')->shouldReturn('\\DateTimeInterface'); + $this->normalizeDataType('date')->shouldReturn('\\DateTimeInterface'); $this->normalizeDataType('boolean')->shouldReturn('bool'); $this->normalizeDataType('decimal')->shouldReturn('float'); // Special cases: - $this->normalizeDataType('DATE')->shouldReturn('\\DateTime'); + $this->normalizeDataType('DATE')->shouldReturn('\\DateTimeInterface'); $this->normalizeDataType('SomeCustomDateType')->shouldReturn('SomeCustomDateType'); $this->normalizeDataType('ArrayOfConsolidatedAgreement')->shouldReturn('ArrayOfConsolidatedAgreement'); } diff --git a/spec/Phpro/SoapClient/Event/Subscriber/ZendCodeValidationSubscriberSpec.php b/spec/Phpro/SoapClient/Console/Event/Subscriber/ZendCodeValidationSubscriberSpec.php similarity index 84% rename from spec/Phpro/SoapClient/Event/Subscriber/ZendCodeValidationSubscriberSpec.php rename to spec/Phpro/SoapClient/Console/Event/Subscriber/ZendCodeValidationSubscriberSpec.php index 07b9acfa..aca69aaf 100644 --- a/spec/Phpro/SoapClient/Event/Subscriber/ZendCodeValidationSubscriberSpec.php +++ b/spec/Phpro/SoapClient/Console/Event/Subscriber/ZendCodeValidationSubscriberSpec.php @@ -1,8 +1,8 @@ shouldHaveType('Phpro\SoapClient\Plugin\LogPlugin'); + $this->shouldHaveType(LogSubscriber::class); } function it_should_be_an_event_subscriber() diff --git a/spec/Phpro/SoapClient/Plugin/ValidatorPluginSpec.php b/spec/Phpro/SoapClient/Event/Subscriber/ValidatorSubscriberSpec.php similarity index 88% rename from spec/Phpro/SoapClient/Plugin/ValidatorPluginSpec.php rename to spec/Phpro/SoapClient/Event/Subscriber/ValidatorSubscriberSpec.php index 04015b37..66ef22f5 100644 --- a/spec/Phpro/SoapClient/Plugin/ValidatorPluginSpec.php +++ b/spec/Phpro/SoapClient/Event/Subscriber/ValidatorSubscriberSpec.php @@ -1,6 +1,6 @@ shouldHaveType(ValidatorPlugin::class); + $this->shouldHaveType(ValidatorSubscriber::class); } function it_should_be_an_event_subscriber() diff --git a/spec/Phpro/SoapClient/Soap/ClassMap/ClassMapCollectionSpec.php b/spec/Phpro/SoapClient/Soap/ClassMap/ClassMapCollectionSpec.php index 2ab1bc73..09de02a8 100644 --- a/spec/Phpro/SoapClient/Soap/ClassMap/ClassMapCollectionSpec.php +++ b/spec/Phpro/SoapClient/Soap/ClassMap/ClassMapCollectionSpec.php @@ -38,11 +38,4 @@ function it_should_add_a_classmap(ClassMap $classMap2) $this->add($classMap2); $this->has($classMap2)->shouldBe(true); } - - function it_should_convert_to_wsdl_classmap() - { - $this->toSoapClassMap()->shouldBe([ - 'WsdlType' => 'PhpClass' - ]); - } } diff --git a/spec/Phpro/SoapClient/Soap/Driver/ExtSoap/Generator/DummyMethodArgumentsGeneratorSpec.php b/spec/Phpro/SoapClient/Soap/Driver/ExtSoap/Generator/DummyMethodArgumentsGeneratorSpec.php new file mode 100644 index 00000000..df49de07 --- /dev/null +++ b/spec/Phpro/SoapClient/Soap/Driver/ExtSoap/Generator/DummyMethodArgumentsGeneratorSpec.php @@ -0,0 +1,46 @@ +beConstructedWith($metadata); + } + + function it_is_initializable() + { + $this->shouldHaveType(DummyMethodArgumentsGenerator::class); + } + + function it_can_parse_dummy_arguments(MetadataInterface $metadata) + { + $metadata->getMethods()->willReturn( + new MethodCollection( + new Method( + 'method', + [ + new Parameter('param1', XsdType::create('string')), + new Parameter('param1', XsdType::create('integer')), + ], + XsdType::create('string') + ) + ) + ); + + $this->generateForSoapCall('method')->shouldBe([null, null]); + } +} diff --git a/spec/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/MethodsParserSpec.php b/spec/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/MethodsParserSpec.php new file mode 100644 index 00000000..679ad616 --- /dev/null +++ b/spec/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/MethodsParserSpec.php @@ -0,0 +1,128 @@ +beConstructedWith(new XsdTypeCollection( + XsdType::create('simpleType') + ->withBaseType('string') + )); + } + + function it_is_initializable() + { + $this->shouldHaveType(MethodsParser::class); + } + + function it_can_parse_ext_soap_function_strings() + { + $abusedClient = $this->mockAbusedClient($methods = [ + 'TestResponse Test0Param()', + 'TestResponse Test1Param(Test1 $parameter1)', + 'TestResponse Test2Param(Test1 $parameter1, Test2 $parameter2)', + 'list(Response1 $response1, Response2 $response2) TestReturnList()', + 'list(Response1 $response1, Response2 $response2) TestReturnListWithParams(Test1 $parameter1, Test2 $parameter2)', + 'simpleType TestSimpleType(simpleType $parameter1)', + ]); + + $result = $this->parse($abusedClient); + $result->shouldHaveType(MethodCollection::class); + $result->shouldHaveCount(\count($methods)); + + $result->fetchOneByName('Test0Param')->shouldHaveMethod( + 'Test0Param', + [], + XsdType::create('TestResponse') + ); + $result->fetchOneByName('Test1Param')->shouldHaveMethod( + 'Test1Param', + [ + new Parameter('parameter1', XsdType::create('Test1')), + ], + XsdType::create('TestResponse') + ); + $result->fetchOneByName('Test2Param')->shouldHaveMethod( + 'Test2Param', + [ + new Parameter('parameter1', XsdType::create('Test1')), + new Parameter('parameter2', XsdType::create('Test2')), + ], + XsdType::create('TestResponse') + ); + $result->fetchOneByName('TestReturnList')->shouldHaveMethod( + 'TestReturnList', + [], + XsdType::create('array') + ); + $result->fetchOneByName('TestReturnListWithParams')->shouldHaveMethod( + 'TestReturnListWithParams', + [ + new Parameter('parameter1', XsdType::create('Test1')), + new Parameter('parameter2', XsdType::create('Test2')), + ], + XsdType::create('array') + ); + + $simpleType = XsdType::create('simpleType')->withBaseType('string'); + $result->fetchOneByName('TestSimpleType')->shouldHaveMethod( + 'TestSimpleType', + [ + new Parameter('parameter1', $simpleType) + ], + $simpleType + ); + } + + public function getMatchers(): array + { + return [ + 'haveMethod' => function (Method $subject, string $name, array $parameters, XsdType $returnType) { + $prefix = 'Expected method '.$name; + + Assert::assertInstanceOf(Method::class, $subject, $prefix.' is not of type Method'); + Assert::assertSame($name, $subject->getName(), $prefix. ' has unexpected name '.$subject->getName()); + Assert::assertEquals($parameters, $subject->getParameters(), $prefix. ' has invalid parameters.'); + Assert::assertEquals($returnType, $subject->getReturnType(), $prefix. ' has unexpected return type.'.$subject->getReturnType()->getName()); + + return true; + }, + ]; + } + + /** + * Phpspec cant mock the __getFunctions + */ + private function mockAbusedClient(array $functions): AbusedClient + { + return new class($functions) extends AbusedClient { + /** @var array */ + private $functions; + + public function __construct(array $functions) + { + $this->functions = $functions; + } + + public function __getFunctions() + { + return $this->functions; + } + }; + } +} diff --git a/spec/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/TypesParserSpec.php b/spec/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/TypesParserSpec.php new file mode 100644 index 00000000..1023e5de --- /dev/null +++ b/spec/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/TypesParserSpec.php @@ -0,0 +1,94 @@ +beConstructedWith(new XsdTypeCollection( + XsdType::create('simpleType')->withBaseType('string') + )); + } + + function it_is_initializable() + { + $this->shouldHaveType(TypesParser::class); + } + + function it_can_parse_ext_soap_types_strings_with_single_argument() + { + $abusedClient = $this->mockAbusedClient([ + 'string simpleType', + 'union unionType {string, integer}', + 'list listType {integer}', + <<parse($abusedClient); + $types->shouldHaveType(TypeCollection::class); + $types->shouldHaveCount(1); + + $type = $types->fetchOneByName('ProductLine'); + $type->getName()->shouldBe('ProductLine'); + + $properties = $type->getProperties(); + $properties->shouldHaveCount(4); + + $properties[0]->shouldHaveType(Property::class); + $properties[0]->getName()->shouldBe('Mode'); + $properties[0]->getType()->shouldBeLike(XsdType::create('string')); + + $properties[1]->shouldHaveType(Property::class); + $properties[1]->getName()->shouldBe('RelevanceRank'); + $properties[1]->getType()->shouldBeLike(XsdType::create('string')); + + $properties[2]->shouldHaveType(Property::class); + $properties[2]->getName()->shouldBe('ProductInfo'); + $properties[2]->getType()->shouldBeLike(XsdType::create('ProductInfo')); + + $properties[3]->shouldHaveType(Property::class); + $properties[3]->getName()->shouldBe('xsdType'); + $properties[3]->getType()->shouldBeLike(XsdType::create('simpleType')->withBaseType('string')); + } + + /** + * Phpspec cant mock the __getTypes() + */ + private function mockAbusedClient(array $types): AbusedClient + { + return new class($types) extends AbusedClient { + /** @var array */ + private $types; + + public function __construct(array $types) + { + $this->types = $types; + } + + public function __getTypes() + { + return $this->types; + } + }; + } +} diff --git a/spec/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/Visitor/ListVisitorSpec.php b/spec/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/Visitor/ListVisitorSpec.php new file mode 100644 index 00000000..555e167a --- /dev/null +++ b/spec/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/Visitor/ListVisitorSpec.php @@ -0,0 +1,46 @@ +shouldHaveType(ListVisitor::class); + } + + function it_is_an_xsd_type_visitor() + { + $this->shouldHaveType(XsdTypeVisitorInterface::class); + } + + function it_returns_null_on_invalid_entry() + { + $this('union unionType {member1,member2}')->shouldBe(null); + $this('union unionType')->shouldBe(null); + $this('struct x {}')->shouldBe(null); + $this('string simpleType')->shouldBe(null); + } + + function it_returns_type_on_valid_entry() + { + $this('list listType {,member1,member2}')->shouldBeLike( + XsdType::create('listType') + ->withBaseType('array') + ->withMemberTypes(['member1','member2']) + ); + $this('list listType')->shouldBeLike( + XsdType::create('listType') + ->withBaseType('array') + ); + } +} diff --git a/spec/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/Visitor/SimpleTypeVisitorSpec.php b/spec/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/Visitor/SimpleTypeVisitorSpec.php new file mode 100644 index 00000000..3aa74e8d --- /dev/null +++ b/spec/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/Visitor/SimpleTypeVisitorSpec.php @@ -0,0 +1,42 @@ +shouldHaveType(SimpleTypeVisitor::class); + } + + function it_is_an_xsd_type_visitor() + { + $this->shouldHaveType(XsdTypeVisitorInterface::class); + } + + function it_returns_null_on_invalid_entry() + { + $this('list listType {,member1,member2}')->shouldBe(null); + $this('list listType')->shouldBe(null); + $this('union unionType {,member1,member2}')->shouldBe(null); + $this('union unionType')->shouldBe(null); + $this('struct x {}')->shouldBe(null); + } + + function it_returns_type_on_valid_entry() + { + $this('string simpleType')->shouldBeLike( + XsdType::create('simpleType') + ->withBaseType('string') + ); + } +} diff --git a/spec/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/Visitor/UnionVisitorSpec.php b/spec/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/Visitor/UnionVisitorSpec.php new file mode 100644 index 00000000..8ae9cf50 --- /dev/null +++ b/spec/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/Visitor/UnionVisitorSpec.php @@ -0,0 +1,46 @@ +shouldHaveType(UnionVisitor::class); + } + + function it_is_an_xsd_type_visitor() + { + $this->shouldHaveType(XsdTypeVisitorInterface::class); + } + + function it_returns_null_on_invalid_entry() + { + $this('list listType {,member1,member2}')->shouldBe(null); + $this('list listType')->shouldBe(null); + $this('struct x {}')->shouldBe(null); + $this('string simpleType')->shouldBe(null); + } + + function it_returns_type_on_valid_entry() + { + $this('union unionType {member1,member2}')->shouldBeLike( + XsdType::create('unionType') + ->withBaseType('anyType') + ->withMemberTypes(['member1','member2']) + ); + $this('union unionType')->shouldBeLike( + XsdType::create('unionType') + ->withBaseType('anyType') + ); + } +} diff --git a/spec/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/XsdTypesParserSpec.php b/spec/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/XsdTypesParserSpec.php new file mode 100644 index 00000000..5c004176 --- /dev/null +++ b/spec/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/XsdTypesParserSpec.php @@ -0,0 +1,112 @@ +beConstructedWith($visitor1, $visitor2); + } + + function it_is_initializable() + { + $this->shouldHaveType(XsdTypesParser::class); + } + + function it_can_parse_ext_soap_types_strings_with_single_argument( + XsdTypeVisitorInterface $visitor1, + XsdTypeVisitorInterface $visitor2 + ) { + $abusedClient = $this->mockAbusedClient([ + $typeString1 = 'string simpleType1', + $typeString2 = 'string simpleType2', + $typeString3 = 'struct invalid xsdtype {}' + ]); + + $visitor1->__invoke($typeString1)->willReturn($type1 = XsdType::create('simpleType1')); + $visitor1->__invoke($typeString2)->willReturn(null); + $visitor1->__invoke($typeString3)->willReturn(null); + + $visitor2->__invoke($typeString1)->shouldNotBeCalled(); + $visitor2->__invoke($typeString2)->willReturn($type2 = XsdType::create('simpleType2')); + $visitor2->__invoke($typeString3)->willReturn(null); + + $result =$this->parse($abusedClient); + $result->shouldHaveType(XsdTypeCollection::class); + $result->shouldHaveCount(2); + $result->shouldIterateAs([$type1, $type2]); + } + + function it_contains_a_default_set_of_visitors() + { + $this->beConstructedThrough('default', []); + $abusedClient = $this->mockAbusedClient([ + $unionString1 = 'union unionType {member1,member2}', + $unionString2 = 'union unionType', + $listString1 = 'list listType {member1,member2}', + $listString2 = 'list listType', + $simpleTypeString = 'string simpleType', + $structString = 'struct invalid xsdtype {}' + ]); + + $result = $this->parse($abusedClient); + $result->shouldHaveCount(5); + $iterator = $result->getIterator(); + $iterator[0]->getName()->shouldBe('unionType'); + $iterator[1]->getName()->shouldBe('unionType'); + $iterator[2]->getName()->shouldBe('listType'); + $iterator[3]->getName()->shouldBe('listType'); + $iterator[4]->getName()->shouldBe('simpleType'); + } + + function it_can_handle_double_typenames_in_separate_namespaces() + { + $this->beConstructedThrough('default', []); + $abusedClient = $this->mockAbusedClient([ + $typeString1 = 'string simpleType', + $typeString2 = 'integer simpleType', + ]); + + $result = $this->parse($abusedClient); + $result->shouldHaveCount(2); + $iterator = $result->getIterator(); + $iterator[0]->getName()->shouldBe('simpleType'); + $iterator[0]->getBaseType()->shouldBe('string'); + $iterator[1]->getName()->shouldBe('simpleType'); + $iterator[1]->getBaseType()->shouldBe('integer'); + $result->fetchByNameWithFallback('simpleType')->getBaseType()->shouldBe('string'); + } + + /** + * Phpspec cant mock the __getTypes() + */ + private function mockAbusedClient(array $types): AbusedClient + { + return new class($types) extends AbusedClient { + /** @var array */ + private $types; + + public function __construct(array $types) + { + $this->types = $types; + } + + public function __getTypes() + { + return $this->types; + } + }; + } +} diff --git a/spec/Phpro/SoapClient/Soap/Engine/Metadata/Collection/MethodCollectionSpec.php b/spec/Phpro/SoapClient/Soap/Engine/Metadata/Collection/MethodCollectionSpec.php new file mode 100644 index 00000000..6956b3ff --- /dev/null +++ b/spec/Phpro/SoapClient/Soap/Engine/Metadata/Collection/MethodCollectionSpec.php @@ -0,0 +1,72 @@ +beConstructedWith($method); + } + + function it_is_initializable() + { + $this->shouldHaveType(MethodCollection::class); + } + + function it_is_an_iterator_aggregate() + { + $this->shouldHaveType(\IteratorAggregate::class); + } + + function it_is_countable() + { + $this->shouldHaveType(\Countable::class); + } + + function it_has_a_count() + { + $this->count()->shouldBe(1); + } + + function it_can_return_iterator(Method $method) + { + $iterator = $this->getIterator(); + $iterator->shouldHaveType(\ArrayIterator::class); + $iterator->shouldIterateAs([$method]); + } + + function it_can_add_method(Method $method2) + { + $this->add($method2); + $this->getIterator()[1]->shouldBe($method2); + } + + function it_can_map_over_methods() + { + $this->map(function() { + return 'hello'; + })->shouldBe(['hello']); + } + + function it_can_find_method_by_name(Method $method) + { + $method->getName()->willReturn($name = 'name'); + $this->fetchOneByName($name)->shouldBe($method); + } + + function it_throws_exception_when_a_method_could_not_be_found_by_name(Method $method) + { + $method->getName()->willReturn($name = 'name'); + $this->shouldthrow(MetadataException::class)->duringFetchOneByName('invalid'); + } +} diff --git a/spec/Phpro/SoapClient/Soap/Engine/Metadata/Collection/TypeCollectionSpec.php b/spec/Phpro/SoapClient/Soap/Engine/Metadata/Collection/TypeCollectionSpec.php new file mode 100644 index 00000000..408db2cf --- /dev/null +++ b/spec/Phpro/SoapClient/Soap/Engine/Metadata/Collection/TypeCollectionSpec.php @@ -0,0 +1,72 @@ +beConstructedWith($type); + } + + function it_is_initializable() + { + $this->shouldHaveType(TypeCollection::class); + } + + function it_is_an_iterator_aggregate() + { + $this->shouldHaveType(\IteratorAggregate::class); + } + + function it_is_countable() + { + $this->shouldHaveType(\Countable::class); + } + + function it_has_a_count() + { + $this->count()->shouldBe(1); + } + + function it_can_return_iterator(Type $type) + { + $iterator = $this->getIterator(); + $iterator->shouldHaveType(\ArrayIterator::class); + $iterator->shouldIterateAs([$type]); + } + + function it_can_add_type(Type $type2) + { + $this->add($type2); + $this->getIterator()[1]->shouldBe($type2); + } + + function it_can_map_over_types() + { + $this->map(function() { + return 'hello'; + })->shouldBe(['hello']); + } + + function it_can_find_type_by_name(Type $type) + { + $type->getName()->willReturn($name = 'name'); + $this->fetchOneByName($name)->shouldBe($type); + } + + function it_throws_exception_when_a_type_could_not_be_found_by_name(Type $type) + { + $type->getName()->willReturn($name = 'name'); + $this->shouldthrow(MetadataException::class)->duringFetchOneByName('invalid'); + } +} diff --git a/spec/Phpro/SoapClient/Soap/Engine/Metadata/Collection/XsdTypeCollectionSpec.php b/spec/Phpro/SoapClient/Soap/Engine/Metadata/Collection/XsdTypeCollectionSpec.php new file mode 100644 index 00000000..6a0686a6 --- /dev/null +++ b/spec/Phpro/SoapClient/Soap/Engine/Metadata/Collection/XsdTypeCollectionSpec.php @@ -0,0 +1,67 @@ +beConstructedWith($XsdType); + } + + function it_is_initializable() + { + $this->shouldHaveType(XsdTypeCollection::class); + } + + function it_is_an_iterator_aggregate() + { + $this->shouldImplement(\IteratorAggregate::class); + } + + function it_is_countable() + { + $this->shouldImplement(\Countable::class); + } + + function it_has_a_count() + { + $this->count()->shouldBe(1); + } + + function it_can_return_iterator(XsdType $XsdType) + { + $iterator = $this->getIterator(); + $iterator->shouldHaveType(\ArrayIterator::class); + $iterator->shouldIterateAs([$XsdType]); + } + + function it_can_add_XsdType(XsdType $XsdType2) + { + $this->add($XsdType2); + $this->getIterator()[1]->shouldBe($XsdType2); + } + + function it_can_map_over_XsdTypes() + { + $this->map(function() { + return 'hello'; + })->shouldBe(['hello']); + } + + function it_can_find_XsdType_by_name(XsdType $XsdType) + { + $XsdType->getName()->willReturn($name = 'name'); + $this->fetchByNameWithFallback($name)->shouldBe($XsdType); + $this->fetchByNameWithFallback('unknown')->shouldBeLike(XsdType::guess('unknown')); + } +} diff --git a/spec/Phpro/SoapClient/Soap/Engine/Metadata/LazyInMemoryMetadataSpec.php b/spec/Phpro/SoapClient/Soap/Engine/Metadata/LazyInMemoryMetadataSpec.php new file mode 100644 index 00000000..ae69cba3 --- /dev/null +++ b/spec/Phpro/SoapClient/Soap/Engine/Metadata/LazyInMemoryMetadataSpec.php @@ -0,0 +1,49 @@ +beConstructedWith($metadata); + } + + function it_is_initializable() + { + $this->shouldHaveType(LazyInMemoryMetadata::class); + } + + function it_is_metadata() + { + $this->shouldImplement(MetadataInterface::class); + } + + function it_lazy_loads_types_once(MetadataInterface $metadata) + { + $metadata->getTypes()->willReturn($collection = new TypeCollection()); + $metadata->getTypes()->shouldBeCalledOnce(); + + $this->getTypes()->shouldBe($collection); + $this->getTypes()->shouldBe($collection); + } + + function it_lazy_loads_methods_once(MetadataInterface $metadata) + { + $metadata->getMethods()->willReturn($collection = new MethodCollection()); + $metadata->getMethods()->shouldBeCalledOnce(); + + $this->getMethods()->shouldBe($collection); + $this->getMethods()->shouldBe($collection); + } +} diff --git a/spec/Phpro/SoapClient/Soap/Engine/Metadata/Model/MethodSpec.php b/spec/Phpro/SoapClient/Soap/Engine/Metadata/Model/MethodSpec.php new file mode 100644 index 00000000..eab6a252 --- /dev/null +++ b/spec/Phpro/SoapClient/Soap/Engine/Metadata/Model/MethodSpec.php @@ -0,0 +1,50 @@ +beConstructedWith( + 'name', + [ + new Parameter('name', XsdType::create('type')) + ], + XsdType::create('returnType') + ); + } + + function it_is_initializable() + { + $this->shouldHaveType(Method::class); + } + + function it_contains_a_name() + { + $this->getName()->shouldBe('name'); + } + + function it_contains_parameters() + { + $parameters = $this->getParameters(); + $parameters->shouldHaveCount(1); + $parameters[0]->shouldHaveType(Parameter::class); + $parameters[0]->getName()->shouldBe('name'); + $parameters[0]->getType()->shouldBeLike(XsdType::create('type')); + } + + function it_contains_a_return_type() + { + $this->getReturnType()->shouldBeLike(XsdType::create('returnType')); + } +} diff --git a/spec/Phpro/SoapClient/Soap/Engine/Metadata/Model/ParameterSpec.php b/spec/Phpro/SoapClient/Soap/Engine/Metadata/Model/ParameterSpec.php new file mode 100644 index 00000000..c31b5c30 --- /dev/null +++ b/spec/Phpro/SoapClient/Soap/Engine/Metadata/Model/ParameterSpec.php @@ -0,0 +1,34 @@ +beConstructedWith('name', XsdType::create('type')); + } + + function it_is_initializable() + { + $this->shouldHaveType(Parameter::class); + } + + function it_contains_a_name() + { + $this->getName()->shouldBe('name'); + } + + function it_contains_a_type() + { + $this->getType()->shouldBeLike(XsdType::create('type')); + } +} diff --git a/spec/Phpro/SoapClient/Soap/Engine/Metadata/Model/PropertySpec.php b/spec/Phpro/SoapClient/Soap/Engine/Metadata/Model/PropertySpec.php new file mode 100644 index 00000000..cffe1708 --- /dev/null +++ b/spec/Phpro/SoapClient/Soap/Engine/Metadata/Model/PropertySpec.php @@ -0,0 +1,34 @@ +beConstructedWith('name', XsdType::create('type')); + } + + function it_is_initializable() + { + $this->shouldHaveType(Property::class); + } + + function it_contains_a_name() + { + $this->getName()->shouldBe('name'); + } + + function it_contains_a_type() + { + $this->getType()->shouldBeLike(XsdType::create('type')); + } +} diff --git a/spec/Phpro/SoapClient/Soap/Engine/Metadata/Model/TypeSpec.php b/spec/Phpro/SoapClient/Soap/Engine/Metadata/Model/TypeSpec.php new file mode 100644 index 00000000..e4c039ce --- /dev/null +++ b/spec/Phpro/SoapClient/Soap/Engine/Metadata/Model/TypeSpec.php @@ -0,0 +1,46 @@ +beConstructedWith(XsdType::create('name'), [ + new Property('name', XsdType::create('type')) + ]); + } + + function it_is_initializable() + { + $this->shouldHaveType(Type::class); + } + + function it_contains_a_name() + { + $this->getName()->shouldBe('name'); + } + + function it_contains_a_xsd_type() + { + $this->getXsdType()->shouldBeLike(XsdType::create('name')); + } + + function it_contains_properties() + { + $properties = $this->getProperties(); + $properties->shouldHaveCount(1); + $properties[0]->shouldHaveType(Property::class); + $properties[0]->getName()->shouldBe('name'); + $properties[0]->getType()->shouldBeLike(XsdType::create('type')); + } +} diff --git a/spec/Phpro/SoapClient/Soap/Engine/Metadata/Model/XsdTypeSpec.php b/spec/Phpro/SoapClient/Soap/Engine/Metadata/Model/XsdTypeSpec.php new file mode 100644 index 00000000..a09b332c --- /dev/null +++ b/spec/Phpro/SoapClient/Soap/Engine/Metadata/Model/XsdTypeSpec.php @@ -0,0 +1,104 @@ +beConstructedThrough('create', ['myType']); + } + + function it_is_initializable() + { + $this->shouldHaveType(XsdType::class); + } + + function it_contains_a_name() + { + $this->getName()->shouldBe('myType'); + } + + function it_doesnt_contain_other_metadata_than_name_on_initialisation() + { + $this->getBaseTypeOrFallbackToName()->shouldBe('myType'); + $this->getName()->shouldBe('myType'); + $this->getXmlNamespace()->shouldBe(''); + $this->getXmlNamespaceName()->shouldBe(''); + $this->getBaseType()->shouldBe(''); + $this->getMemberTypes()->shouldBe([]); + } + + function it_cannot_guess_unknown_types() + { + $type = $this->guess('myType'); + $type->getName()->shouldBe('myType'); + $type->getBaseType()->shouldBe(''); + } + + function it_can_guess_known_types() + { + foreach (XsdType::fetchAllKnownBaseTypeMappings() as $typeName => $baseType) { + $type = $this->guess($typeName); + $type->getName()->shouldBe($typeName); + $type->getBaseType()->shouldBe($baseType); + } + } + + function it_can_add_base_type() + { + $new = $this->withBaseType('baseType'); + $new->shouldNotBe($this); + $new->getName()->shouldBe('myType'); + $new->getBaseType()->shouldBe('baseType'); + $new->getBaseTypeOrFallbackToName()->shouldBe('baseType'); + } + + function it_can_add_known_base_type_and_move_actual_type_to_member_types() + { + foreach (XsdType::fetchAllKnownBaseTypeMappings() as $typeName => $baseType) { + $new = $this->withBaseType($typeName); + $new->shouldNotBe($this); + $new->getName()->shouldBe('myType'); + $new->getBaseType()->shouldBe($baseType); + $new->getBaseTypeOrFallbackToName()->shouldBe($baseType); + $new->getMemberTypes()->shouldBe([$typeName]); + } + } + + function it_can_add_member_types() + { + $new = $this->withMemberTypes($types = ['type1', 'type2']); + $new->shouldNotBe($this); + $new->getName()->shouldBe('myType'); + $new->getMemberTypes()->shouldBe($types); + } + + function it_can_add_xml_namespace() + { + $new = $this->withXmlNamespace($namespace = 'http://www.w3.org/2001/XMLSchema'); + $new->shouldNotBe($this); + $new->getName()->shouldBe('myType'); + $new->getXmlNamespace()->shouldBe($namespace); + } + + function it_can_add_xml_namespace_name() + { + $new = $this->withXmlNamespaceName($namespaceName = 'xsd'); + $new->shouldNotBe($this); + $new->getName()->shouldBe('myType'); + $new->getXmlNamespaceName()->shouldBe($namespaceName); + } + + function it_can_return_name_as_string() + { + $this->__toString()->shouldBe('myType'); + } +} diff --git a/spec/Phpro/SoapClient/Soap/Handler/SoapHandleSpec.php b/spec/Phpro/SoapClient/Soap/Handler/SoapHandleSpec.php deleted file mode 100644 index 5ea6f443..00000000 --- a/spec/Phpro/SoapClient/Soap/Handler/SoapHandleSpec.php +++ /dev/null @@ -1,42 +0,0 @@ -beConstructedWith($client); - } - - function it_is_initializable() - { - $this->shouldHaveType(SoapHandle::class); - } - - function it_is_a_soap_handler() - { - $this->shouldHaveType(HandlerInterface::class); - } - - function it_can_request_soap_messages(SoapClient $client) - { - $request = new SoapRequest('body', 'uri', 'action', 1, 0); - $client->doInternalRequest('body', 'uri', 'action', 1, 0)->willReturn($response = 'result'); - - $result = $this->request($request); - $result->shouldHaveType(SoapResponse::class); - $result->getResponse()->shouldBe($response); - } -} diff --git a/spec/Phpro/SoapClient/Soap/HttpBinding/Converter/Psr7ToLastRequestInfoConverterSpec.php b/spec/Phpro/SoapClient/Soap/HttpBinding/Converter/Psr7ToLastRequestInfoConverterSpec.php new file mode 100644 index 00000000..ee750dbc --- /dev/null +++ b/spec/Phpro/SoapClient/Soap/HttpBinding/Converter/Psr7ToLastRequestInfoConverterSpec.php @@ -0,0 +1,48 @@ +shouldHaveType(Psr7ToLastRequestInfoConverter::class); + } + + + function it_can_load_from_psr7_request_and_response() + { + $request = new Request('POST', '/', ['x-request-header' => 'value'], 'REQUESTBODY'); + $response = new Response(200, ['x-response-header' => 'value'], 'RESPONSEBODY'); + + $result = $this->convert($request, $response); + $result->shouldBeAnInstanceOf(LastRequestInfo::class); + $result->getLastRequestHeaders()->shouldBe('x-request-header: value'); + $result->getLastRequest()->shouldBe('REQUESTBODY'); + $result->getLastResponseHeaders()->shouldBe('x-response-header: value'); + $result->getLastResponse()->shouldBe('RESPONSEBODY'); + } + + function it_can_load_from_psr7_request_and_response_without_body() + { + $request = new Request('GET', '/', ['x-request-header' => 'value'], ''); + $respone = new Response(204, ['x-response-header' => 'value'], ''); + + $result = $this->convert($request, $respone); + $result->shouldBeAnInstanceOf(LastRequestInfo::class); + $result->getLastRequestHeaders()->shouldBe('x-request-header: value'); + $result->getLastRequest()->shouldBe(''); + $result->getLastResponseHeaders()->shouldBe('x-response-header: value'); + $result->getLastResponse()->shouldBe(''); + } +} diff --git a/spec/Phpro/SoapClient/Soap/HttpBinding/LastRequestInfoSpec.php b/spec/Phpro/SoapClient/Soap/HttpBinding/LastRequestInfoSpec.php index cdf59a55..1d3b37d1 100644 --- a/spec/Phpro/SoapClient/Soap/HttpBinding/LastRequestInfoSpec.php +++ b/spec/Phpro/SoapClient/Soap/HttpBinding/LastRequestInfoSpec.php @@ -2,9 +2,6 @@ namespace spec\Phpro\SoapClient\Soap\HttpBinding; -use GuzzleHttp\Psr7\Request; -use GuzzleHttp\Psr7\Response; -use Phpro\SoapClient\Soap\SoapClient; use PhpSpec\ObjectBehavior; use Prophecy\Argument; use Phpro\SoapClient\Soap\HttpBinding\LastRequestInfo; @@ -53,39 +50,4 @@ function it_can_create_an_empty_class() $result->getLastResponseHeaders()->shouldBe(''); $result->getLastResponse()->shouldBe(''); } - - // Note: the __get* cannot be mocked with phpspec. - function it_can_create_from_a_soapclient(SoapClient $client) - { - $result = $this->createFromSoapClient($client); - $result->shouldBeAnInstanceOf(LastRequestInfo::class); - $result->getLastRequestHeaders()->shouldBe(''); - $result->getLastRequest()->shouldBe(''); - $result->getLastResponseHeaders()->shouldBe(''); - $result->getLastResponse()->shouldBe(''); - } - - function it_can_load_from_psr7_request_and_response() - { - $request = new Request('POST', '/', ['x-request-header' => 'value'], 'REQUESTBODY'); - $response = new Response(200, ['x-response-header' => 'value'], 'RESPONSEBODY'); - - $result = $this->createFromPsr7RequestAndResponse($request, $response); - $result->getLastRequestHeaders()->shouldBe('x-request-header: value'); - $result->getLastRequest()->shouldBe('REQUESTBODY'); - $result->getLastResponseHeaders()->shouldBe('x-response-header: value'); - $result->getLastResponse()->shouldBe('RESPONSEBODY'); - } - - function it_can_load_from_psr7_request_and_response_without_body() - { - $request = new Request('GET', '/', ['x-request-header' => 'value'], ''); - $respone = new Response(204, ['x-response-header' => 'value'], ''); - - $result = $this->createFromPsr7RequestAndResponse($request, $respone); - $result->getLastRequestHeaders()->shouldBe('x-request-header: value'); - $result->getLastRequest()->shouldBe(''); - $result->getLastResponseHeaders()->shouldBe('x-response-header: value'); - $result->getLastResponse()->shouldBe(''); - } } diff --git a/spec/Phpro/SoapClient/Soap/SoapClientFactorySpec.php b/spec/Phpro/SoapClient/Soap/SoapClientFactorySpec.php deleted file mode 100644 index 02a47a2b..00000000 --- a/spec/Phpro/SoapClient/Soap/SoapClientFactorySpec.php +++ /dev/null @@ -1,26 +0,0 @@ -toSoapClassMap()->willReturn([]); - $typeConverters->toSoapTypeMap()->willReturn([]); - $this->beConstructedWith($classMap, $typeConverters); - } - - function it_is_initializable() - { - $this->shouldHaveType(SoapClientFactory::class); - } - -} diff --git a/spec/Phpro/SoapClient/Soap/SoapClientSpec.php b/spec/Phpro/SoapClient/Soap/SoapClientSpec.php deleted file mode 100644 index 6c481541..00000000 --- a/spec/Phpro/SoapClient/Soap/SoapClientSpec.php +++ /dev/null @@ -1,11 +0,0 @@ -shouldImplement(TypeConverterInterface::class); } + function it_creates_datetime_interface_from_xml() + { + $date = '2019-01-25T13:55:00+00:00'; + + $result = $this->convertXmlToPhp(''.$date.''); + $result->shouldBeAnInstanceOf(\DateTimeImmutable::class); + $result->getTimezone()->shouldMatchWithCurrentTimeZone(); + $result->format(\DateTime::ATOM)->shouldBe($date); + } + function it_returns_empty_string_on_null_passed() { $this->convertPhpToXml(null)->shouldReturn(''); @@ -37,4 +47,17 @@ function it_returns_correct_datetime_string_on_valid_type_passed() '' . $dateTime->format('Y-m-d\TH:i:sP') . '' ); } + + public function getMatchers() + { + return [ + 'matchWithCurrentTimeZone' => function (\DateTimeZone $dateTimeZone) { + $name = $dateTimeZone->getName(); + + return $name === date('T') + || $name === date('P') + || $name === date('e'); + } + ]; + } } diff --git a/spec/Phpro/SoapClient/Soap/TypeConverter/DateTypeConverterSpec.php b/spec/Phpro/SoapClient/Soap/TypeConverter/DateTypeConverterSpec.php index 4d28f401..28642e44 100644 --- a/spec/Phpro/SoapClient/Soap/TypeConverter/DateTypeConverterSpec.php +++ b/spec/Phpro/SoapClient/Soap/TypeConverter/DateTypeConverterSpec.php @@ -20,6 +20,15 @@ function it_is_a_type_converter() $this->shouldImplement(TypeConverterInterface::class); } + function it_creates_datetime_interface_from_xml() + { + $date = '2019-01-25'; + + $result = $this->convertXmlToPhp(''.$date.''); + $result->shouldBeAnInstanceOf(\DateTimeImmutable::class); + $result->format('Y-m-d')->shouldBe($date); + } + function it_returns_empty_string_on_null_passed() { $this->convertPhpToXml(null)->shouldReturn(''); diff --git a/spec/Phpro/SoapClient/Soap/TypeConverter/TypeConverterCollectionSpec.php b/spec/Phpro/SoapClient/Soap/TypeConverter/TypeConverterCollectionSpec.php index 1640596d..d6452d63 100644 --- a/spec/Phpro/SoapClient/Soap/TypeConverter/TypeConverterCollectionSpec.php +++ b/spec/Phpro/SoapClient/Soap/TypeConverter/TypeConverterCollectionSpec.php @@ -28,10 +28,4 @@ function it_should_know_its_registered_converters() { $this->has(new DateTypeConverter())->shouldBe(true); } - - function it_should_convert_to_soap_type_map() - { - $result = $this->toSoapTypeMap(); - $result[0]['type_name']->shouldBe('date'); - } } diff --git a/src/Phpro/SoapClient/Client.php b/src/Phpro/SoapClient/Client.php index cd069e89..8fc03d03 100644 --- a/src/Phpro/SoapClient/Client.php +++ b/src/Phpro/SoapClient/Client.php @@ -4,14 +4,12 @@ use Phpro\SoapClient\Event; use Phpro\SoapClient\Exception\SoapException; +use Phpro\SoapClient\Soap\Engine\EngineInterface; use Phpro\SoapClient\Type\MixedResult; use Phpro\SoapClient\Type\MultiArgumentRequestInterface; use Phpro\SoapClient\Type\RequestInterface; use Phpro\SoapClient\Type\ResultInterface; use Phpro\SoapClient\Type\ResultProviderInterface; -use SoapClient; - -use SoapHeader; use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** @@ -22,35 +20,21 @@ class Client implements ClientInterface { /** - * @var SoapClient + * @var EngineInterface */ - protected $soapClient; + protected $engine; /** * @var EventDispatcherInterface */ protected $dispatcher; - /** - * @param SoapClient $soapClient - * @param EventDispatcherInterface $dispatcher - */ - public function __construct(SoapClient $soapClient, EventDispatcherInterface $dispatcher) + public function __construct(EngineInterface $engine, EventDispatcherInterface $dispatcher) { - $this->soapClient = $soapClient; + $this->engine = $engine; $this->dispatcher = $dispatcher; } - /** - * @param SoapHeader|SoapHeader[] $soapHeaders - * @return $this - */ - public function applySoapHeaders($soapHeaders): self - { - $this->soapClient->__setSoapHeaders($soapHeaders); - return $this; - } - /** * Make it possible to debug the last request. * @@ -58,26 +42,19 @@ public function applySoapHeaders($soapHeaders): self */ public function debugLastSoapRequest(): array { + $lastRequestInfo = $this->engine->collectLastRequestInfo(); return [ 'request' => [ - 'headers' => $this->soapClient->__getLastRequestHeaders(), - 'body' => $this->soapClient->__getLastRequest(), + 'headers' => $lastRequestInfo->getLastRequestHeaders(), + 'body' => $lastRequestInfo->getLastRequest(), ], 'response' => [ - 'headers' => $this->soapClient->__getLastResponseHeaders(), - 'body' => $this->soapClient->__getLastResponse(), + 'headers' => $lastRequestInfo->getLastResponseHeaders(), + 'body' => $lastRequestInfo->getLastResponse(), ], ]; } - /** - * @param string $location - */ - public function changeSoapLocation(string $location) - { - $this->soapClient->__setLocation($location); - } - /** * @param string $method * @param RequestInterface $request @@ -92,7 +69,7 @@ protected function call(string $method, RequestInterface $request): ResultInterf try { $arguments = ($request instanceof MultiArgumentRequestInterface) ? $request->getArguments() : [$request]; - $result = call_user_func_array([$this->soapClient, $method], $arguments); + $result = $this->engine->request($method, $arguments); if ($result instanceof ResultProviderInterface) { $result = $result->getResult(); diff --git a/src/Phpro/SoapClient/ClientBuilder.php b/src/Phpro/SoapClient/ClientBuilder.php deleted file mode 100644 index e9a6a263..00000000 --- a/src/Phpro/SoapClient/ClientBuilder.php +++ /dev/null @@ -1,230 +0,0 @@ -classMaps = new ClassMapCollection(); - $this->converters = new TypeConverterCollection(); - $this->dispatcher = new EventDispatcher(); - $this->wsdlProvider = new MixedWsdlProvider(); - $this->clientFactory = $clientFactory; - $this->wsdl = $wsdl; - $this->soapOptions = $soapOptions; - - // Add default converters: - $this->addTypeConverter(new TypeConverter\DateTimeTypeConverter()); - $this->addTypeConverter(new TypeConverter\DateTypeConverter()); - $this->addTypeConverter(new TypeConverter\DecimalTypeConverter()); - $this->addTypeConverter(new TypeConverter\DoubleTypeConverter()); - } - - /** - * @param LoggerInterface $logger - */ - public function withLogger(LoggerInterface $logger) - { - $this->logger = $logger; - } - - /** - * @param ValidatorInterface $validator - */ - public function withValidator(ValidatorInterface $validator) - { - $this->validator = $validator; - } - - /** - * @param EventDispatcherInterface $dispatcher - */ - public function withEventDispatcher(EventDispatcherInterface $dispatcher) - { - $this->dispatcher = $dispatcher; - } - - /** - * @param WsdlProviderInterface $wsdlProvider - */ - public function withWsdlProvider(WsdlProviderInterface $wsdlProvider) - { - $this->wsdlProvider = $wsdlProvider; - } - - /** - * @param TypeConverterCollection $converters - */ - public function withTypeConverter(TypeConverterCollection $converters) - { - $this->converters = $converters; - } - - /** - * @param ClassMapCollection $classMaps - */ - public function withClassMaps(ClassMapCollection $classMaps) - { - $this->classMaps = $classMaps; - } - - /** - * @param ClassMapInterface $classMap - */ - public function addClassMap(ClassMapInterface $classMap) - { - $this->classMaps->add($classMap); - } - - /** - * @param TypeConverterInterface $typeConverter - */ - public function addTypeConverter(TypeConverterInterface $typeConverter) - { - $this->converters->add($typeConverter); - } - - /** - * @param HandlerInterface $handler - */ - public function withHandler(HandlerInterface $handler) - { - $this->handler = $handler; - } - - /** - * @param MiddlewareInterface $middleware - */ - public function addMiddleware(MiddlewareInterface $middleware) - { - $this->middlewares[] = $middleware; - } - - /** - * @return ClientInterface - * @throws \Phpro\SoapClient\Exception\InvalidArgumentException - */ - public function build(): ClientInterface - { - $soapClientFactory = new SoapClientFactory($this->classMaps, $this->converters); - $soapClient = $soapClientFactory->factory($this->wsdlProvider->provide($this->wsdl), $this->soapOptions); - - if ($this->handler && !$soapClient instanceof SoapClient) { - throw new InvalidArgumentException(sprintf( - 'You can only add handlers if the SoapClientFactory is returning an instance of %s. Got: %s', - SoapClient::class, - get_class($soapClient) - )); - } - - if ($this->handler) { - $soapClient->setHandler($this->handler); - } - - if (count($this->middlewares)) { - if (!$this->handler instanceof MiddlewareSupportingInterface) { - throw new InvalidArgumentException('The SOAP handler you selected does not support middlewares.'); - } - - foreach ($this->middlewares as $middleware) { - $this->handler->addMiddleware($middleware); - } - } - - if ($this->logger) { - $this->dispatcher->addSubscriber(new LogPlugin($this->logger)); - } - - if ($this->validator) { - $this->dispatcher->addSubscriber(new ValidatorPlugin($this->validator)); - } - - return $this->clientFactory->factory($soapClient, $this->dispatcher); - } -} diff --git a/src/Phpro/SoapClient/ClientFactory.php b/src/Phpro/SoapClient/ClientFactory.php deleted file mode 100644 index c95c9e12..00000000 --- a/src/Phpro/SoapClient/ClientFactory.php +++ /dev/null @@ -1,42 +0,0 @@ -className = $className; - } - - /** - * @param SoapClient $soapClient - * @param EventDispatcherInterface $dispatcher - * - * @return object - */ - public function factory(SoapClient $soapClient, EventDispatcherInterface $dispatcher) - { - $rc = new ReflectionClass($this->className); - - return $rc->newInstance($soapClient, $dispatcher); - } -} diff --git a/src/Phpro/SoapClient/ClientFactoryInterface.php b/src/Phpro/SoapClient/ClientFactoryInterface.php deleted file mode 100644 index 645b70a8..00000000 --- a/src/Phpro/SoapClient/ClientFactoryInterface.php +++ /dev/null @@ -1,23 +0,0 @@ -withClassMaps(%2\$s::getCollection()); +\$engine = ExtSoapEngineFactory::fromOptions( + ExtSoapOptions::defaults(\$wsdl, []) + ->withClassMap(%2\$s::getCollection()) +); +\$eventDispatcher = new EventDispatcher(); -return \$clientBuilder->build(); +return new %1\$s(\$engine, \$eventDispatcher); BODY; @@ -37,8 +40,9 @@ public function generate(FileGenerator $file, $context): string $class->setNamespaceName($context->getClientNamespace()); $class->addUse($context->getClientFqcn()); $class->addUse($context->getClassmapFqcn()); - $class->addUse(ClientFactory::class, 'PhproClientFactory'); - $class->addUse(ClientBuilder::class); + $class->addUse(EventDispatcher::class); + $class->addUse(ExtSoapEngineFactory::class); + $class->addUse(ExtSoapOptions::class); $class->addMethodFromGenerator( MethodGenerator::fromArray( [ diff --git a/src/Phpro/SoapClient/CodeGenerator/Config/Config.php b/src/Phpro/SoapClient/CodeGenerator/Config/Config.php index ac5e2411..614ecc07 100644 --- a/src/Phpro/SoapClient/CodeGenerator/Config/Config.php +++ b/src/Phpro/SoapClient/CodeGenerator/Config/Config.php @@ -10,9 +10,7 @@ use Phpro\SoapClient\CodeGenerator\Rules\RuleSetInterface; use Phpro\SoapClient\CodeGenerator\Util\Normalizer; use Phpro\SoapClient\Exception\InvalidArgumentException; -use Phpro\SoapClient\Exception\WsdlException; -use Phpro\SoapClient\Wsdl\Provider\MixedWsdlProvider; -use Phpro\SoapClient\Wsdl\Provider\WsdlProviderInterface; +use Phpro\SoapClient\Soap\Engine\EngineInterface; /** * Class Config @@ -31,25 +29,15 @@ class Config implements ConfigInterface */ protected $typeNamespace = ''; - /** - * @var - */ - protected $clientNamespace = ''; - /** * @var string */ - protected $wsdl = ''; + protected $clientNamespace = ''; /** - * @var array + * @var EngineInterface */ - protected $soapOptions = [ - 'trace' => false, - 'exceptions' => true, - 'keep_alive' => true, - 'cache_wsdl' => WSDL_CACHE_NONE, - ]; + protected $engine; /** * @var string @@ -66,11 +54,6 @@ class Config implements ConfigInterface */ protected $ruleSet; - /** - * @var WsdlProviderInterface - */ - protected $wsdlProvider; - /** * @var string */ @@ -86,22 +69,13 @@ class Config implements ConfigInterface */ protected $classMapDestination; - /** - * Config constructor. - * - * @param string $wsdl - * @param string $destination - */ - public function __construct(string $wsdl = '', string $destination = '') + public function __construct() { - $this->setWsdl($wsdl); - $this->setTypeDestination($destination); $this->ruleSet = new RuleSet([ new Rules\AssembleRule(new Assembler\PropertyAssembler()), new Rules\AssembleRule(new Assembler\ClassMapAssembler()), new Rules\AssembleRule(new ClientMethodAssembler()) ]); - $this->wsdlProvider = new MixedWsdlProvider(); } /** @@ -133,65 +107,24 @@ public function setTypeNamespace($namespace): self } /** - * @return string - * @throws InvalidArgumentException + * @return EngineInterface */ - public function getWsdl(): string + public function getEngine(): EngineInterface { - if (!$this->wsdl) { - throw InvalidArgumentException::wsdlConfigurationIsMissing(); - } - - try { - $wsdl = $this->wsdlProvider->provide($this->wsdl); - } catch (WsdlException $e) { - throw InvalidArgumentException::wsdlCouldNotBeProvided($e); + if (!$this->engine instanceof EngineInterface) { + throw InvalidArgumentException::engineNotConfigured(); } - - return $wsdl; + return $this->engine; } /** - * @param string $wsdl + * @param EngineInterface $engine * * @return Config */ - public function setWsdl($wsdl): self + public function setEngine(EngineInterface $engine): self { - $this->wsdl = $wsdl; - - return $this; - } - - /** - * @param string $key - * @param mixed $value - * - * @return $this - */ - public function addSoapOption(string $key, $value): self - { - $this->soapOptions[$key] = $value; - - return $this; - } - - /** - * @return array - */ - public function getSoapOptions(): array - { - return $this->soapOptions; - } - - /** - * @param array $soapOptions - * - * @return $this - */ - public function setSoapOptions(array $soapOptions) - { - $this->soapOptions = $soapOptions; + $this->engine = $engine; return $this; } @@ -316,25 +249,6 @@ public function setTypeDestination($typeDestination): self return $this; } - /** - * @return WsdlProviderInterface - */ - public function getWsdlProvider(): WsdlProviderInterface - { - return $this->wsdlProvider; - } - - /** - * @param WsdlProviderInterface $wsdlProvider - * @return Config - */ - public function setWsdlProvider(WsdlProviderInterface $wsdlProvider): self - { - $this->wsdlProvider = $wsdlProvider; - - return $this; - } - /** * @return string */ diff --git a/src/Phpro/SoapClient/CodeGenerator/Config/ConfigInterface.php b/src/Phpro/SoapClient/CodeGenerator/Config/ConfigInterface.php index c2dd06c4..d3451a82 100644 --- a/src/Phpro/SoapClient/CodeGenerator/Config/ConfigInterface.php +++ b/src/Phpro/SoapClient/CodeGenerator/Config/ConfigInterface.php @@ -3,7 +3,7 @@ namespace Phpro\SoapClient\CodeGenerator\Config; use Phpro\SoapClient\CodeGenerator\Rules\RuleSetInterface; -use Phpro\SoapClient\Wsdl\Provider\WsdlProviderInterface; +use Phpro\SoapClient\Soap\Engine\EngineInterface; /** * Interface ConfigInterface @@ -12,15 +12,11 @@ */ interface ConfigInterface { - /** - * @return string - */ - public function getWsdl(): string; /** - * array + * @return EngineInterface */ - public function getSoapOptions(): array; + public function getEngine(): EngineInterface; /** * @return string @@ -47,11 +43,6 @@ public function getClientNamespace(); */ public function getTypeNamespace(); - /** - * @return WsdlProviderInterface - */ - public function getWsdlProvider(): WsdlProviderInterface; - /** * @return string */ diff --git a/src/Phpro/SoapClient/CodeGenerator/ConfigGenerator.php b/src/Phpro/SoapClient/CodeGenerator/ConfigGenerator.php index 86955859..73643e8f 100644 --- a/src/Phpro/SoapClient/CodeGenerator/ConfigGenerator.php +++ b/src/Phpro/SoapClient/CodeGenerator/ConfigGenerator.php @@ -4,6 +4,11 @@ use Phpro\SoapClient\CodeGenerator\Config\Config; use Phpro\SoapClient\CodeGenerator\Context\ConfigContext; +use Phpro\SoapClient\Soap\Driver\ExtSoap\ExtSoapDriver; +use Phpro\SoapClient\Soap\Driver\ExtSoap\ExtSoapEngineFactory; +use Phpro\SoapClient\Soap\Driver\ExtSoap\ExtSoapOptions; +use Phpro\SoapClient\Soap\Driver\ExtSoap\Handler\ExtSoapClientHandle; +use Phpro\SoapClient\Soap\Engine\Engine; use Zend\Code\Generator\FileGenerator; /** @@ -44,6 +49,14 @@ class ConfigGenerator implements GeneratorInterface ) RULESET; + const ENGINE_BOILERPLATE = <<setEngine(ExtSoapEngineFactory::fromOptions( + ExtSoapOptions::defaults('%s', []) + ->disableWsdlCache() + )) +EOENGINE; + + /** * @param string $name @@ -66,6 +79,11 @@ private function parseIndentedRuleSet(FileGenerator $file, string $ruleset): str return $file->getIndentation().preg_replace('/\n/', sprintf("\n%s", $file->getIndentation()), $ruleset).PHP_EOL; } + private function parseEngine(FileGenerator $fileGenerator, string $wsdl): string + { + return $fileGenerator->getIndentation().sprintf(self::ENGINE_BOILERPLATE, $wsdl).PHP_EOL; + } + /** * @param FileGenerator $file * @param ConfigContext $context @@ -77,7 +95,10 @@ public function generate(FileGenerator $file, $context): string $file->setUse('Phpro\\SoapClient\\CodeGenerator\\Assembler'); $file->setUse('Phpro\\SoapClient\\CodeGenerator\\Rules'); $file->setUse(Config::class); + $file->setUse(ExtSoapOptions::class); + $file->setUse(ExtSoapEngineFactory::class); + $body .= $this->parseEngine($file, $context->getWsdl()); foreach ($context->getSetters() as $name => $value) { $body .= $this->generateSetter($name, $value, $file); } diff --git a/src/Phpro/SoapClient/CodeGenerator/Context/ConfigContext.php b/src/Phpro/SoapClient/CodeGenerator/Context/ConfigContext.php index a15e1c56..4fa55255 100644 --- a/src/Phpro/SoapClient/CodeGenerator/Context/ConfigContext.php +++ b/src/Phpro/SoapClient/CodeGenerator/Context/ConfigContext.php @@ -6,6 +6,11 @@ class ConfigContext implements ContextInterface { private $setters = []; + /** + * @var string + */ + private $wsdl; + /** * @var string */ @@ -31,6 +36,25 @@ public function getSetters(): array return $this->setters; } + /** + * @return string + */ + public function getWsdl(): string + { + return $this->wsdl; + } + + /** + * @param string $wsdl + * @return ConfigContext + */ + public function setWsdl(string $wsdl): self + { + $this->wsdl = $wsdl; + + return $this; + } + /** * @return string */ diff --git a/src/Phpro/SoapClient/CodeGenerator/Model/ClientMethod.php b/src/Phpro/SoapClient/CodeGenerator/Model/ClientMethod.php index 594bb5d2..fc16b7d8 100644 --- a/src/Phpro/SoapClient/CodeGenerator/Model/ClientMethod.php +++ b/src/Phpro/SoapClient/CodeGenerator/Model/ClientMethod.php @@ -2,8 +2,9 @@ namespace Phpro\SoapClient\CodeGenerator\Model; -use Phpro\SoapClient\CodeGenerator\Parser\FunctionStringParser; use Phpro\SoapClient\CodeGenerator\Util\Normalizer; +use Phpro\SoapClient\Soap\Engine\Metadata\Model\Method as MetadataMethod; +use Phpro\SoapClient\Soap\Engine\Metadata\Model\Parameter as MetadataParameter; /** * Class ClientMethod @@ -48,24 +49,19 @@ public function __construct(string $name, array $params, string $returnType, str $this->returnType = $returnType; } - /** - * Creates an instance from parsing a soap function string - * - * @param string $functionString - * @param string $parameterNamespace - * - * @return ClientMethod - */ - public static function createFromExtSoapFunctionString( - string $functionString, - string $parameterNamespace - ): ClientMethod { - $parser = new FunctionStringParser($functionString, $parameterNamespace); - + public static function fromMetadata( + string $parameterNamespace, + MetadataMethod $method + ): self { return new self( - $parser->parseName(), - $parser->parseParameters(), - $parser->parseReturnType(), + $method->getName(), + array_map( + function (MetadataParameter $parameter) use ($parameterNamespace) { + return Parameter::fromMetadata($parameterNamespace, $parameter); + }, + $method->getParameters() + ), + $method->getReturnType()->getBaseTypeOrFallbackToName(), $parameterNamespace ); } diff --git a/src/Phpro/SoapClient/CodeGenerator/Model/ClientMethodMap.php b/src/Phpro/SoapClient/CodeGenerator/Model/ClientMethodMap.php index e62103d8..23cc5aee 100644 --- a/src/Phpro/SoapClient/CodeGenerator/Model/ClientMethodMap.php +++ b/src/Phpro/SoapClient/CodeGenerator/Model/ClientMethodMap.php @@ -2,7 +2,8 @@ namespace Phpro\SoapClient\CodeGenerator\Model; -use Phpro\SoapClient\Soap\SoapClient; +use Phpro\SoapClient\Soap\Engine\Metadata\Collection\MethodCollection; +use Phpro\SoapClient\Soap\Engine\Metadata\Model\Method; /** * Class ClientMethodMap @@ -16,21 +17,26 @@ class ClientMethodMap */ private $methods; + /** + * ClientMethodMap constructor. + * + * @param array|ClientMethod[] $methods + */ public function __construct(array $methods) { $this->methods = $methods; } - public static function fromSoapClient(SoapClient $client, $parameterNamespace = '') : ClientMethodMap + public static function fromMetadata(string $parameterNamespace, MethodCollection $collection): self { - $clientMethods = []; - foreach ($client->__getFunctions() as $method) { - $clientMethods[] = ClientMethod::createFromExtSoapFunctionString($method, $parameterNamespace); - } - - return new self($clientMethods); + return new self($collection->map(function (Method $method) use ($parameterNamespace) { + return ClientMethod::fromMetadata($parameterNamespace, $method); + })); } + /** + * @return ClientMethod[] + */ public function getMethods() : array { return $this->methods; diff --git a/src/Phpro/SoapClient/CodeGenerator/Model/Parameter.php b/src/Phpro/SoapClient/CodeGenerator/Model/Parameter.php index c1073ead..1a5b283f 100644 --- a/src/Phpro/SoapClient/CodeGenerator/Model/Parameter.php +++ b/src/Phpro/SoapClient/CodeGenerator/Model/Parameter.php @@ -2,6 +2,9 @@ namespace Phpro\SoapClient\CodeGenerator\Model; +use Phpro\SoapClient\CodeGenerator\Util\Normalizer; +use Phpro\SoapClient\Soap\Engine\Metadata\Model\Parameter as MetadataParameter; + class Parameter { /** @@ -22,8 +25,20 @@ class Parameter */ public function __construct(string $name, string $type) { - $this->name = $name; - $this->type = $type; + $this->name = Normalizer::normalizeProperty($name); + $this->type = Normalizer::normalizeClassnameInFQN($type); + } + + public static function fromMetadata(string $parameterNamespace, MetadataParameter $parameter) + { + $type = $parameter->getType()->getBaseTypeOrFallbackToName(); + + return new self( + $parameter->getName(), + Normalizer::isKnownType($type) + ? $type + : $parameterNamespace.'\\'.$type + ); } /** diff --git a/src/Phpro/SoapClient/CodeGenerator/Model/Property.php b/src/Phpro/SoapClient/CodeGenerator/Model/Property.php index c08ddcc0..7f8a3628 100644 --- a/src/Phpro/SoapClient/CodeGenerator/Model/Property.php +++ b/src/Phpro/SoapClient/CodeGenerator/Model/Property.php @@ -3,6 +3,7 @@ namespace Phpro\SoapClient\CodeGenerator\Model; use Phpro\SoapClient\CodeGenerator\Util\Normalizer; +use Phpro\SoapClient\Soap\Engine\Metadata\Model\Property as MetadataProperty; /** * Class Property @@ -40,6 +41,15 @@ public function __construct(string $name, string $type, string $namespace) $this->namespace = Normalizer::normalizeNamespace($namespace); } + public static function fromMetaData(string $namespace, MetadataProperty $property) + { + return new self( + $property->getName(), + $property->getType()->getBaseTypeOrFallbackToName(), + $namespace + ); + } + /** * @return string */ diff --git a/src/Phpro/SoapClient/CodeGenerator/Model/Type.php b/src/Phpro/SoapClient/CodeGenerator/Model/Type.php index 4cc483d7..bbd41287 100644 --- a/src/Phpro/SoapClient/CodeGenerator/Model/Type.php +++ b/src/Phpro/SoapClient/CodeGenerator/Model/Type.php @@ -3,6 +3,8 @@ namespace Phpro\SoapClient\CodeGenerator\Model; use Phpro\SoapClient\CodeGenerator\Util\Normalizer; +use Phpro\SoapClient\Soap\Engine\Metadata\Model\Property as MetadataProperty; +use Phpro\SoapClient\Soap\Engine\Metadata\Model\Type as MetadataType; use SplFileInfo; /** @@ -12,7 +14,6 @@ */ class Type { - /** * @var string */ @@ -46,10 +47,24 @@ public function __construct(string $namespace, string $xsdName, array $propertie $this->namespace = Normalizer::normalizeNamespace($namespace); $this->xsdName = $xsdName; $this->name = Normalizer::normalizeClassname($xsdName); + $this->properties = $properties; + } - foreach ($properties as $property => $type) { - $this->properties[] = new Property($property, $type, $this->namespace); - } + public static function fromMetadata(string $namespace, MetadataType $type): self + { + return new self( + $namespace, + $type->getName(), + array_map( + function (MetadataProperty $property) use ($namespace) { + return Property::fromMetaData( + $namespace, + $property + ); + }, + $type->getProperties() + ) + ); } /** diff --git a/src/Phpro/SoapClient/CodeGenerator/Model/TypeMap.php b/src/Phpro/SoapClient/CodeGenerator/Model/TypeMap.php index 470a15e9..198f172e 100644 --- a/src/Phpro/SoapClient/CodeGenerator/Model/TypeMap.php +++ b/src/Phpro/SoapClient/CodeGenerator/Model/TypeMap.php @@ -3,7 +3,8 @@ namespace Phpro\SoapClient\CodeGenerator\Model; use Phpro\SoapClient\CodeGenerator\Util\Normalizer; -use Phpro\SoapClient\Soap\SoapClient; +use Phpro\SoapClient\Soap\Engine\Metadata\Collection\TypeCollection; +use Phpro\SoapClient\Soap\Engine\Metadata\Model\Type as MetadataType; /** * Class TypeMap @@ -14,9 +15,9 @@ class TypeMap { /** - * @var array + * @var array|Type[] */ - private $types = []; + private $types; /** * @var string @@ -27,26 +28,22 @@ class TypeMap * TypeMap constructor. * * @param string $namespace - * @param array $types + * @param array|Type[] $types */ public function __construct(string $namespace, array $types) { $this->namespace = Normalizer::normalizeNamespace($namespace); - - foreach ($types as $type => $properties) { - $this->types[] = new Type($namespace, $type, $properties); - } + $this->types = $types; } - /** - * @param string $namespace - * @param SoapClient $client - * - * @return TypeMap - */ - public static function fromSoapClient(string $namespace, SoapClient $client): self + public static function fromMetadata(string $namespace, TypeCollection $types): self { - return new self($namespace, $client->getSoapTypes()); + return new self( + $namespace, + $types->map(function (MetadataType $type) use ($namespace) { + return Type::fromMetadata($namespace, $type); + }) + ); } /** diff --git a/src/Phpro/SoapClient/CodeGenerator/Parser/FunctionStringParser.php b/src/Phpro/SoapClient/CodeGenerator/Parser/FunctionStringParser.php deleted file mode 100644 index 075e0238..00000000 --- a/src/Phpro/SoapClient/CodeGenerator/Parser/FunctionStringParser.php +++ /dev/null @@ -1,71 +0,0 @@ -functionString = $functionString; - $this->parameterNamespace = $parameterNamespace; - } - - /** - * @return Parameter[] - */ - public function parseParameters(): array - { - preg_match('/\((.*)\)/', $this->functionString, $properties); - $parameters = []; - $properties = preg_split('/,\s?/', $properties[1]); - foreach ($properties as $property) { - list($type, $name) = explode(' ', trim($property)); - $name = Normalizer::normalizeProperty($name); - $type = Normalizer::normalizeClassname($type); - $parameters[] = new Parameter($name, $this->parameterNamespace.'\\'.$type); - } - - return $parameters; - } - - /** - * @return string - */ - public function parseName(): string - { - preg_match('/^\w+ (\w+)/', $this->functionString, $matches); - - return $matches[1]; - } - - /** - * @return mixed - */ - public function parseReturnType() - { - preg_match('/^(\w+)/', $this->functionString, $matches); - - return $matches[1]; - } -} diff --git a/src/Phpro/SoapClient/CodeGenerator/Util/Normalizer.php b/src/Phpro/SoapClient/CodeGenerator/Util/Normalizer.php index 93fe2e96..ae6872dc 100644 --- a/src/Phpro/SoapClient/CodeGenerator/Util/Normalizer.php +++ b/src/Phpro/SoapClient/CodeGenerator/Util/Normalizer.php @@ -11,13 +11,16 @@ class Normalizer { private static $normalizations = [ + 'any' => 'mixed', + 'anytype' => 'mixed', 'long' => 'int', 'short' => 'int', - 'datetime' => '\\DateTime', - 'date' => '\\DateTime', + 'datetime' => '\\DateTimeInterface', + 'date' => '\\DateTimeInterface', 'boolean' => 'bool', 'decimal' => 'float', 'double' => 'float', + 'integer' => 'int', 'string' => 'string', 'self' => 'self', 'callable' => 'callable', @@ -173,6 +176,17 @@ public static function normalizeClassname(string $name): string return ucfirst(self::camelCase($name, '{[^a-z0-9]+}i')); } + public static function normalizeClassnameInFQN(string $fqn): string + { + if (self::isKnownType($fqn)) { + return $fqn; + } + + $className = self::getClassNameFromFQN($fqn); + + return substr($fqn, 0, -1 * \strlen($className)).self::normalizeClassname($className); + } + /** * @param string $property * diff --git a/src/Phpro/SoapClient/Console/Application.php b/src/Phpro/SoapClient/Console/Application.php index 59e86847..0c2106a2 100644 --- a/src/Phpro/SoapClient/Console/Application.php +++ b/src/Phpro/SoapClient/Console/Application.php @@ -4,8 +4,8 @@ namespace Phpro\SoapClient\Console; use Phpro\SoapClient\Console\Command; +use Phpro\SoapClient\Console\Event\Subscriber\ZendCodeValidationSubscriber; use Phpro\SoapClient\Console\Helper\ConfigHelper; -use Phpro\SoapClient\Event\Subscriber\ZendCodeValidationSubscriber; use Phpro\SoapClient\Util\Filesystem; use Symfony\Component\Console\Application as SymfonyApplication; use Symfony\Component\Console\Helper\HelperSet; diff --git a/src/Phpro/SoapClient/Console/Command/GenerateClassmapCommand.php b/src/Phpro/SoapClient/Console/Command/GenerateClassmapCommand.php index f6249590..0091c343 100644 --- a/src/Phpro/SoapClient/Console/Command/GenerateClassmapCommand.php +++ b/src/Phpro/SoapClient/Console/Command/GenerateClassmapCommand.php @@ -5,7 +5,6 @@ use Phpro\SoapClient\CodeGenerator\ClassMapGenerator; use Phpro\SoapClient\CodeGenerator\Model\TypeMap; use Phpro\SoapClient\Console\Helper\ConfigHelper; -use Phpro\SoapClient\Soap\SoapClient; use Phpro\SoapClient\Util\Filesystem; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; @@ -79,8 +78,10 @@ protected function execute(InputInterface $input, OutputInterface $output) $io = new SymfonyStyle($input, $output); $config = $this->getConfigHelper()->load($input); - $soapClient = new SoapClient($config->getWsdl(), $config->getSoapOptions()); - $typeMap = TypeMap::fromSoapClient($config->getTypeNamespace(), $soapClient); + $typeMap = TypeMap::fromMetadata( + $config->getTypeNamespace(), + $config->getEngine()->getMetadata()->getTypes() + ); $generator = new ClassMapGenerator( $config->getRuleSet(), diff --git a/src/Phpro/SoapClient/Console/Command/GenerateClientCommand.php b/src/Phpro/SoapClient/Console/Command/GenerateClientCommand.php index 7e7fc2d3..86f3ec4e 100644 --- a/src/Phpro/SoapClient/Console/Command/GenerateClientCommand.php +++ b/src/Phpro/SoapClient/Console/Command/GenerateClientCommand.php @@ -7,7 +7,6 @@ use Phpro\SoapClient\CodeGenerator\Model\ClientMethodMap; use Phpro\SoapClient\CodeGenerator\TypeGenerator; use Phpro\SoapClient\Console\Helper\ConfigHelper; -use Phpro\SoapClient\Soap\SoapClient; use Phpro\SoapClient\Util\Filesystem; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; @@ -80,8 +79,11 @@ protected function execute(InputInterface $input, OutputInterface $output) $config = $this->getConfigHelper()->load($input); $destination = $config->getClientDestination().'/'.$config->getClientName().'.php'; - $soapClient = new SoapClient($config->getWsdl(), $config->getSoapOptions()); - $methodMap = ClientMethodMap::fromSoapClient($soapClient, $config->getTypeNamespace()); + $methodMap = ClientMethodMap::fromMetadata( + $config->getTypeNamespace(), + $config->getEngine()->getMetadata()->getMethods() + ); + $client = new Client($config->getClientName(), $config->getClientNamespace(), $methodMap); $generator = new ClientGenerator($config->getRuleSet()); $fileGenerator = new FileGenerator(); diff --git a/src/Phpro/SoapClient/Console/Command/GenerateConfigCommand.php b/src/Phpro/SoapClient/Console/Command/GenerateConfigCommand.php index 437c56d0..7f251a2d 100644 --- a/src/Phpro/SoapClient/Console/Command/GenerateConfigCommand.php +++ b/src/Phpro/SoapClient/Console/Command/GenerateConfigCommand.php @@ -64,7 +64,7 @@ protected function execute(InputInterface $input, OutputInterface $output) ); } - $context->addSetter('setWsdl', $io->ask('Wsdl location (URL or path to file)')); + $context->setWsdl($io->ask('Wsdl location (URL or path to file)')); $name = $io->ask('Generic name used to name this client (Results in Client Classmap etc.)'); $baseDir = $io->ask('Directory where the client should be generated in'); $namespace = $io->ask('Namespace for your client'); diff --git a/src/Phpro/SoapClient/Console/Command/GenerateTypesCommand.php b/src/Phpro/SoapClient/Console/Command/GenerateTypesCommand.php index 5b9aa999..aa8b05a7 100644 --- a/src/Phpro/SoapClient/Console/Command/GenerateTypesCommand.php +++ b/src/Phpro/SoapClient/Console/Command/GenerateTypesCommand.php @@ -6,7 +6,6 @@ use Phpro\SoapClient\CodeGenerator\Model\TypeMap; use Phpro\SoapClient\CodeGenerator\TypeGenerator; use Phpro\SoapClient\Console\Helper\ConfigHelper; -use Phpro\SoapClient\Soap\SoapClient; use Phpro\SoapClient\Util\Filesystem; use SplFileInfo; use Symfony\Component\Console\Command\Command; @@ -78,8 +77,10 @@ protected function execute(InputInterface $input, OutputInterface $output) $io = new SymfonyStyle($input, $output); $config = $this->getConfigHelper()->load($input); - $soapClient = new SoapClient($config->getWsdl(), $config->getSoapOptions()); - $typeMap = TypeMap::fromSoapClient($config->getTypeNamespace(), $soapClient); + $typeMap = TypeMap::fromMetadata( + $config->getTypeNamespace(), + $config->getEngine()->getMetadata()->getTypes() + ); $generator = new TypeGenerator($config->getRuleSet()); foreach ($typeMap->getTypes() as $type) { diff --git a/src/Phpro/SoapClient/Event/Subscriber/ZendCodeValidationSubscriber.php b/src/Phpro/SoapClient/Console/Event/Subscriber/ZendCodeValidationSubscriber.php similarity index 96% rename from src/Phpro/SoapClient/Event/Subscriber/ZendCodeValidationSubscriber.php rename to src/Phpro/SoapClient/Console/Event/Subscriber/ZendCodeValidationSubscriber.php index c7352d40..8605a3b0 100644 --- a/src/Phpro/SoapClient/Event/Subscriber/ZendCodeValidationSubscriber.php +++ b/src/Phpro/SoapClient/Console/Event/Subscriber/ZendCodeValidationSubscriber.php @@ -1,6 +1,6 @@ getMessage(), 0, $e); + return new static('You did not configure a soap engine'); } /** diff --git a/src/Phpro/SoapClient/Exception/MetadataException.php b/src/Phpro/SoapClient/Exception/MetadataException.php new file mode 100644 index 00000000..b6015237 --- /dev/null +++ b/src/Phpro/SoapClient/Exception/MetadataException.php @@ -0,0 +1,18 @@ +lastRequest, $this->lastResponse); + return (new Psr7ToLastRequestInfoConverter())->convert($this->lastRequest, $this->lastResponse); } } diff --git a/src/Phpro/SoapClient/Soap/ClassMap/ClassMapCollection.php b/src/Phpro/SoapClient/Soap/ClassMap/ClassMapCollection.php index 19c42a12..30e37dcc 100644 --- a/src/Phpro/SoapClient/Soap/ClassMap/ClassMapCollection.php +++ b/src/Phpro/SoapClient/Soap/ClassMap/ClassMapCollection.php @@ -2,6 +2,7 @@ namespace Phpro\SoapClient\Soap\ClassMap; +use IteratorAggregate; use Phpro\SoapClient\Exception\InvalidArgumentException; /** @@ -9,7 +10,7 @@ * * @package Phpro\SoapClient\Soap\ClassMap */ -class ClassMapCollection +class ClassMapCollection implements IteratorAggregate { /** @@ -64,15 +65,10 @@ public function has(ClassMapInterface $classMap): bool } /** - * @return array + * @return \ArrayIterator|ClassMapInterface[] */ - public function toSoapClassMap(): array + public function getIterator(): \ArrayIterator { - $map = []; - foreach ($this->classMaps as $classMap) { - $map[$classMap->getWsdlType()] = $classMap->getPhpClassName(); - } - - return $map; + return new \ArrayIterator($this->classMaps); } } diff --git a/src/Phpro/SoapClient/Soap/Driver/ExtSoap/AbusedClient.php b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/AbusedClient.php new file mode 100644 index 00000000..f3002dc4 --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/AbusedClient.php @@ -0,0 +1,69 @@ +resolve($options); + parent::__construct($wsdl, $options); + } + + public static function createFromOptions(ExtSoapOptions $options): self + { + return new self($options->getWsdl(), $options->getOptions()); + } + + public function __doRequest($request, $location, $action, $version, $oneWay = 0) + { + $this->storedRequest = new SoapRequest($request, $location, $action, $version, $oneWay); + + return $this->storedResponse ? $this->storedResponse->getResponse() : ''; + } + + public function doActualRequest( + string $request, + string $location, + string $action, + int $version, + int $oneWay = 0 + ): string { + return (string) parent::__doRequest($request, $location, $action, $version, $oneWay); + } + + public function collectRequest(): SoapRequest + { + if (!$this->storedRequest) { + throw new \RuntimeException('No request has been registered yet.'); + } + + return $this->storedRequest; + } + + public function registerResponse(SoapResponse $response) + { + $this->storedResponse = $response; + } + + public function cleanUpTemporaryState() + { + $this->storedRequest = null; + $this->storedResponse = null; + } +} diff --git a/src/Phpro/SoapClient/Soap/Driver/ExtSoap/ExtSoapDecoder.php b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/ExtSoapDecoder.php new file mode 100644 index 00000000..b5a91216 --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/ExtSoapDecoder.php @@ -0,0 +1,37 @@ +client = $client; + $this->argumentsGenerator = $argumentsGenerator; + } + + public function decode(string $method, SoapResponse $response) + { + $this->client->registerResponse($response); + $decoded = $this->client->__soapCall($method, $this->argumentsGenerator->generateForSoapCall($method)); + $this->client->cleanUpTemporaryState(); + + return $decoded; + } +} diff --git a/src/Phpro/SoapClient/Soap/Driver/ExtSoap/ExtSoapDriver.php b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/ExtSoapDriver.php new file mode 100644 index 00000000..260cc5e4 --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/ExtSoapDriver.php @@ -0,0 +1,89 @@ +client = $client; + $this->encoder = $encoder; + $this->decoder = $decoder; + $this->metadata = $metadata; + } + + public static function createFromOptions(ExtSoapOptions $options): self + { + $client = AbusedClient::createFromOptions($options); + + return self::createFromClient($client); + } + + public static function createFromClient(AbusedClient $client): self + { + $metadata = new LazyInMemoryMetadata(new ExtSoapMetadata($client)); + + return new self( + $client, + new ExtSoapEncoder($client), + new ExtSoapDecoder($client, new DummyMethodArgumentsGenerator($metadata)), + $metadata + ); + } + + public function decode(string $method, SoapResponse $response) + { + return $this->decoder->decode($method, $response); + } + + public function encode(string $method, array $arguments): SoapRequest + { + return $this->encoder->encode($method, $arguments); + } + + public function getMetadata(): MetadataInterface + { + return $this->metadata; + } + + public function getClient(): AbusedClient + { + return $this->client; + } +} diff --git a/src/Phpro/SoapClient/Soap/Driver/ExtSoap/ExtSoapEncoder.php b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/ExtSoapEncoder.php new file mode 100644 index 00000000..f7305829 --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/ExtSoapEncoder.php @@ -0,0 +1,30 @@ +client = $client; + } + + public function encode(string $method, array $arguments): SoapRequest + { + $this->client->__soapCall($method, $arguments); + $encoded = $this->client->collectRequest(); + $this->client->cleanUpTemporaryState(); + + return $encoded; + } +} diff --git a/src/Phpro/SoapClient/Soap/Driver/ExtSoap/ExtSoapEngineFactory.php b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/ExtSoapEngineFactory.php new file mode 100644 index 00000000..c85e17ea --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/ExtSoapEngineFactory.php @@ -0,0 +1,27 @@ +getClient()); + + return new Engine($driver, $handler); + } + + public static function fromOptionsWithHandler(ExtSoapOptions $options, HandlerInterface $handler): Engine + { + $driver = ExtSoapDriver::createFromOptions($options); + + return new Engine($driver, $handler); + } +} diff --git a/src/Phpro/SoapClient/Soap/Driver/ExtSoap/ExtSoapMetadata.php b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/ExtSoapMetadata.php new file mode 100644 index 00000000..8c30c81f --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/ExtSoapMetadata.php @@ -0,0 +1,50 @@ +abusedClient = $abusedClient; + } + + public function getMethods(): MethodCollection + { + return (new MethodsParser($this->getXsdTypes()))->parse($this->abusedClient); + } + + public function getTypes(): TypeCollection + { + return (new TypesParser($this->getXsdTypes()))->parse($this->abusedClient); + } + + private function getXsdTypes(): XsdTypeCollection + { + if (null === $this->xsdTypes) { + $this->xsdTypes = XsdTypesParser::default()->parse($this->abusedClient); + } + + return $this->xsdTypes; + } +} diff --git a/src/Phpro/SoapClient/Soap/Driver/ExtSoap/ExtSoapOptions.php b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/ExtSoapOptions.php new file mode 100644 index 00000000..e0eff2f1 --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/ExtSoapOptions.php @@ -0,0 +1,127 @@ +wsdl = $wsdl; + $this->options = $options; + $this->wsdlProvider = new MixedWsdlProvider(); + } + + public static function defaults(string $wsdl, array $options = []): self + { + return new self( + $wsdl, + array_merge( + [ + 'trace' => true, + 'exceptions' => true, + 'keep_alive' => true, + 'cache_wsdl' => WSDL_CACHE_DISK, // Avoid memory cache: this causes SegFaults from time to time. + 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, + 'typemap' => new TypeConverterCollection([ + new TypeConverter\DateTimeTypeConverter(), + new TypeConverter\DateTypeConverter(), + new TypeConverter\DecimalTypeConverter(), + new TypeConverter\DoubleTypeConverter() + ]), + ], + $options + ) + ); + } + + public function getWsdl(): string + { + return $this->wsdlProvider->provide($this->wsdl); + } + + public function getOptions(): array + { + return $this->options; + } + + public function withWsdlProvider(WsdlProviderInterface $wsdlProvider): self + { + $this->wsdlProvider = $wsdlProvider; + + return $this; + } + + public function getClassMap(): ClassMapCollection + { + return $this->fetchOptionOfTypeWithDefault( + 'classmap', + ClassMapCollection::class, + new ClassMapCollection() + ); + } + + public function withClassMap(ClassMapCollection $classMapCollection): self + { + $this->options['classmap'] = $classMapCollection; + + return $this; + } + + public function getTypeMap(): TypeConverterCollection + { + return $this->fetchOptionOfTypeWithDefault( + 'typemap', + TypeConverterCollection::class, + new TypeConverterCollection() + ); + } + + public function withTypeMap(TypeConverterCollection $typeConverterCollection): self + { + $this->options['typemap'] = $typeConverterCollection; + + return $this; + } + + public function disableWsdlCache(): self + { + $this->options['cache_wsdl'] = WSDL_CACHE_NONE; + + return $this; + } + + private function fetchOptionOfTypeWithDefault(string $key, string $type, $default) + { + $this->options[$key] = $this->options[$key] ?? $default; + + if (!$this->options[$key] instanceof $type) { + throw UnexpectedConfigurationException::expectedTypeButGot($key, $type, $this->options[$key]); + } + + return $this->options[$key]; + } +} diff --git a/src/Phpro/SoapClient/Soap/Driver/ExtSoap/ExtSoapOptionsResolverFactory.php b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/ExtSoapOptionsResolverFactory.php new file mode 100644 index 00000000..fe1c801a --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/ExtSoapOptionsResolverFactory.php @@ -0,0 +1,185 @@ +setRequired(['uri', 'location']); + } + + return $resolver; + } + + public static function create(): OptionsResolver + { + static $resolver; + if ($resolver) { + return $resolver; + } + + $resolver = new OptionsResolver(); + + // Override HTTP info + $resolver->setDefined(['uri', 'location']); + $resolver->setAllowedTypes('uri', ['string']); + $resolver->setAllowedTypes('location', ['string']); + + // Specify SOAP version + $resolver->setDefault('soap_version', SOAP_1_1); + $resolver->setAllowedTypes('soap_version', 'int'); + $resolver->setAllowedValues('soap_version', [SOAP_1_1, SOAP_1_2]); + + // HTTP AUthentication + $resolver->setDefined(['login', 'password', 'authentication']); + $resolver->setAllowedTypes('login', ['string']); + $resolver->setAllowedTypes('password', ['string']); + $resolver->setAllowedTypes('authentication', ['int']); + $resolver->setAllowedValues('authentication', [SOAP_AUTHENTICATION_BASIC, SOAP_AUTHENTICATION_DIGEST]); + + // HTTP Proxy + $resolver->setDefined(['proxy_host', 'proxy_port', 'proxy_login', 'proxy_password']); + $resolver->setAllowedTypes('proxy_host', ['string']); + $resolver->setAllowedTypes('proxy_port', ['string', 'int']); + $resolver->setAllowedTypes('proxy_login', ['string']); + $resolver->setAllowedTypes('proxy_password', ['string']); + + // SSL Certificates + $resolver->setDefined(['local_cert', 'passphrase']); + $resolver->setAllowedTypes('local_cert', ['string']); + $resolver->setAllowedTypes('passphrase', ['string', 'int']); + + // Compression + $resolver->setDefined(['compression']); + $resolver->setAllowedTypes('compression', ['int']); + $resolver->setAllowedValues('compression', function ($value): bool { + // Levels 0-9 Specify GZIP compression + // @see: https://bugs.php.net/bug.php?id=36283 + return $value >= 0 + && $value <= ( + SOAP_COMPRESSION_ACCEPT + | SOAP_COMPRESSION_DEFLATE + | SOAP_COMPRESSION_GZIP + | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 + ); + }); + + // Encoding + $resolver->setDefined(['encoding']); + $resolver->setAllowedTypes('encoding', ['string']); + + // Trace + $resolver->setDefault('trace', true); + $resolver->setAllowedTypes('trace', ['bool']); + + // Classmaps + $resolver->setDefault('classmap', new ClassMapCollection()); + $resolver->setAllowedTypes('classmap', [ClassMapCollection::class, 'array']); + $resolver->setNormalizer('classmap', function (Options $options, $value): array { + // Classic array configuration: + if (!$value instanceof ClassMapCollection) { + return $value; + } + + return array_map( + function (ClassMap $classMap) { + return $classMap->getPhpClassName(); + }, + iterator_to_array($value) + ); + }); + + // Exceptions + $resolver->setDefault('exceptions', true); + $resolver->setAllowedTypes('exceptions', ['bool']); + + // Timeouts + $resolver->setDefined(['connection_timeout', 'default_socket_timeout']); + $resolver->setAllowedTypes('connection_timeout', ['int']); + $resolver->setAllowedTypes('default_socket_timeout', ['int']); + + // Typemaps + $resolver->setDefault('typemap', new TypeConverterCollection()); + $resolver->setAllowedTypes('typemap', [TypeConverterCollection::class, 'array']); + + $resolver->setDefined(['typemap']); + $resolver->setAllowedTypes('typemap', ['array', TypeConverterCollection::class]); + $resolver->setNormalizer('typemap', function (Options $options, $value): array { + // Classic array configuration: + if (!$value instanceof TypeConverterCollection) { + return $value; + } + + return array_values(array_map( + function (TypeConverterInterface $converter) { + return [ + 'type_name' => $converter->getTypeName(), + 'type_ns' => $converter->getTypeNamespace(), + 'from_xml' => function ($input) use ($converter) { + return $converter->convertXmlToPhp($input); + }, + 'to_xml' => function ($input) use ($converter) { + return $converter->convertPhpToXml($input); + }, + ]; + }, + iterator_to_array($value) + )); + }); + + // WSDL Caching + $resolver->setDefault('cache_wsdl', WSDL_CACHE_NONE); + $resolver->setAllowedTypes('cache_wsdl', ['int']); + $resolver->setAllowedValues('cache_wsdl', [ + WSDL_CACHE_NONE, + WSDL_CACHE_DISK, + WSDL_CACHE_MEMORY, + WSDL_CACHE_BOTH + ]); + + // User agent + $resolver->setDefined(['user_agent']); + $resolver->setAllowedTypes('user_agent', ['string']); + + // Stream context + $resolver->setDefined(['stream_context']); + $resolver->setAllowedTypes('stream_context', ['resource']); + + // Features + $resolver->setDefined(['features']); + $resolver->setAllowedTypes('features', ['int']); + $resolver->setAllowedValues('features', function ($value): bool { + return $value >= 0 + && $value <= (SOAP_SINGLE_ELEMENT_ARRAYS | SOAP_USE_XSI_ARRAY_TYPE | SOAP_WAIT_ONE_WAY_CALLS); + }); + + // Keep alive + $resolver->setDefined(['keep_alive']); + $resolver->setAllowedTypes('keep_alive', ['bool']); + + // SSL Method + $resolver->setDefined(['ssl_method']); + $resolver->setAllowedTypes('ssl_method', ['int']); + $resolver->setAllowedValues('ssl_method', [ + SOAP_SSL_METHOD_TLS, + SOAP_SSL_METHOD_SSLv2, + SOAP_SSL_METHOD_SSLv3, + SOAP_SSL_METHOD_SSLv23 + ]); + + return $resolver; + } +} diff --git a/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Generator/DummyMethodArgumentsGenerator.php b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Generator/DummyMethodArgumentsGenerator.php new file mode 100644 index 00000000..b16bb3de --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Generator/DummyMethodArgumentsGenerator.php @@ -0,0 +1,32 @@ +metadata = $metadata; + } + + public function generateForSoapCall(string $method): array + { + $methods = $this->metadata->getMethods(); + $method = $methods->fetchOneByName($method); + + return array_fill(0, \count($method->getParameters()), null); + } +} diff --git a/src/Phpro/SoapClient/Soap/Handler/SoapHandle.php b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Handler/ExtSoapClientHandle.php similarity index 55% rename from src/Phpro/SoapClient/Soap/Handler/SoapHandle.php rename to src/Phpro/SoapClient/Soap/Driver/ExtSoap/Handler/ExtSoapClientHandle.php index fc9bc02e..0658cb85 100644 --- a/src/Phpro/SoapClient/Soap/Handler/SoapHandle.php +++ b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Handler/ExtSoapClientHandle.php @@ -1,21 +1,17 @@ client = $client; $this->lastRequestInfo = LastRequestInfo::createEmpty(); } - /** - * @param SoapRequest $request - * - * @return SoapResponse - */ public function request(SoapRequest $request): SoapResponse { - $response = $this->client->doInternalRequest( + $response = $this->client->doActualRequest( $request->getRequest(), $request->getLocation(), $request->getAction(), @@ -50,14 +36,16 @@ public function request(SoapRequest $request): SoapResponse $request->getOneWay() ); - $this->lastRequestInfo = LastRequestInfo::createFromSoapClient($this->client); + $this->lastRequestInfo = new LastRequestInfo( + (string) $this->client->__getLastRequestHeaders(), + (string) $this->client->__getLastRequest(), + (string) $this->client->__getLastResponseHeaders(), + (string) $this->client->__getLastResponse() + ); return new SoapResponse($response); } - /** - * @return LastRequestInfo - */ public function collectLastRequestInfo(): LastRequestInfo { return $this->lastRequestInfo; diff --git a/src/Phpro/SoapClient/Soap/Handler/LocalSoapServerHandle.php b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Handler/ExtSoapServerHandle.php similarity index 87% rename from src/Phpro/SoapClient/Soap/Handler/LocalSoapServerHandle.php rename to src/Phpro/SoapClient/Soap/Driver/ExtSoap/Handler/ExtSoapServerHandle.php index 59e11562..daa6342c 100644 --- a/src/Phpro/SoapClient/Soap/Handler/LocalSoapServerHandle.php +++ b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Handler/ExtSoapServerHandle.php @@ -1,13 +1,14 @@ xsdTypes = $xsdTypes; + } + + public function parse(AbusedClient $abusedClient): MethodCollection + { + return new MethodCollection(...array_map( + function (string $methodString) { + return $this->parseMethodFromString($methodString); + }, + $abusedClient->__getFunctions() + )); + } + + private function parseMethodFromString(string $methodString): Method + { + $methodString = $this->transformListResponseToArray($methodString); + return new Method( + $this->parseName($methodString), + $this->parseParameters($methodString), + $this->parseReturnType($methodString) + ); + } + + private function transformListResponseToArray(string $methodString): string + { + return preg_replace('/^list\(([^\)]*)\)(.*)/i', 'array$2', $methodString); + } + + /** + * @return Parameter[] + */ + private function parseParameters(string $methodString): array + { + preg_match('/\((.*)\)/', $methodString, $properties); + if (!$properties[1]) { + return []; + } + + $parameters = preg_split('/,\s?/', $properties[1]); + + return array_map( + function (string $parameter): Parameter { + list($type, $name) = explode(' ', trim($parameter)); + + return new Parameter( + ltrim($name, '$'), + $this->xsdTypes->fetchByNameWithFallback($type) + ); + }, + $parameters + ); + } + + private function parseName(string $methodString): string + { + preg_match('/^\w+ (?P\w+)/', $methodString, $matches); + + return (string) $matches['name']; + } + + private function parseReturnType(string $methodString): XsdType + { + preg_match('/^(?P\w+)/', $methodString, $matches); + + return $this->xsdTypes->fetchByNameWithFallback((string) $matches['returnType']); + } +} diff --git a/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/TypesParser.php b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/TypesParser.php new file mode 100644 index 00000000..e1eefcc9 --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/TypesParser.php @@ -0,0 +1,54 @@ +xsdTypes = $xsdTypes; + } + + public function parse(AbusedClient $abusedClient): TypeCollection + { + $collection = new TypeCollection(); + $soapTypes = $abusedClient->__getTypes(); + foreach ($soapTypes as $soapType) { + $properties = []; + $lines = explode("\n", $soapType); + if (!preg_match('/struct (?P.*) {/', $lines[0], $matches)) { + continue; + } + $xsdType = XsdType::create($matches['typeName']); + + foreach (array_slice($lines, 1) as $line) { + if ($line === '}') { + continue; + } + preg_match('/\s* (?P.*) (?P.*);/', $line, $matches); + $properties[] = new Property( + $matches['propertyName'], + $this->xsdTypes->fetchByNameWithFallback($matches['propertyType']) + ); + } + + $collection->add(new Type($xsdType, $properties)); + } + + return $collection; + } +} diff --git a/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/Visitor/ListVisitor.php b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/Visitor/ListVisitor.php new file mode 100644 index 00000000..ed9c17e6 --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/Visitor/ListVisitor.php @@ -0,0 +1,26 @@ +\w+)( \{(?P[^\}]+)\})?$/', $soapType, $matches)) { + return null; + } + + $type = XsdType::create($matches['typeName']) + ->withBaseType('array'); + + if ($memberTypes = $matches['memberTypes'] ?? '') { + $type = $type->withMemberTypes(explode(',', $memberTypes)); + } + + return $type; + } +} diff --git a/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/Visitor/SimpleTypeVisitor.php b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/Visitor/SimpleTypeVisitor.php new file mode 100644 index 00000000..247a08a2 --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/Visitor/SimpleTypeVisitor.php @@ -0,0 +1,20 @@ +\w+) (?P\w+)/', $soapType, $matches)) { + return null; + } + + return XsdType::create($matches['typeName']) + ->withBaseType($matches['baseType']); + } +} diff --git a/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/Visitor/UnionVisitor.php b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/Visitor/UnionVisitor.php new file mode 100644 index 00000000..5a81c806 --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/Visitor/UnionVisitor.php @@ -0,0 +1,26 @@ +\w+)( \{(?P[^\}]+)\})?$/', $soapType, $matches)) { + return null; + } + + $type = XsdType::create($matches['typeName']) + ->withBaseType('anyType'); + + if ($memberTypes = $matches['memberTypes'] ?? '') { + $type = $type->withMemberTypes(explode(',', $memberTypes)); + } + + return $type; + } +} diff --git a/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/Visitor/XsdTypeVisitorInterface.php b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/Visitor/XsdTypeVisitorInterface.php new file mode 100644 index 00000000..772dbb0d --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Driver/ExtSoap/Metadata/Visitor/XsdTypeVisitorInterface.php @@ -0,0 +1,12 @@ +visitors = $visitors; + } + + public static function default(): self + { + return new self( + new ListVisitor(), + new UnionVisitor(), + new SimpleTypeVisitor() + ); + } + + public function parse(AbusedClient $abusedClient): XsdTypeCollection + { + $collection = new XsdTypeCollection(); + $soapTypes = $abusedClient->__getTypes(); + foreach ($soapTypes as $soapType) { + if ($type = $this->detectXsdType($soapType)) { + $collection->add($type); + } + } + + return $collection; + } + + private function detectXsdType(string $soapType): ?XsdType + { + foreach ($this->visitors as $visitor) { + if ($type = $visitor($soapType)) { + return $type; + } + } + + return null; + } +} diff --git a/src/Phpro/SoapClient/Soap/Engine/DecoderInterface.php b/src/Phpro/SoapClient/Soap/Engine/DecoderInterface.php new file mode 100644 index 00000000..6accc957 --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Engine/DecoderInterface.php @@ -0,0 +1,13 @@ +driver = $driver; + $this->handler = $handler; + } + + public function getMetadata(): MetadataInterface + { + return $this->driver->getMetadata(); + } + + public function request(string $method, array $arguments) + { + $request = $this->driver->encode($method, $arguments); + $response = $this->handler->request($request); + + return $this->driver->decode($method, $response); + } + + public function collectLastRequestInfo(): LastRequestInfo + { + return $this->handler->collectLastRequestInfo(); + } +} diff --git a/src/Phpro/SoapClient/Soap/Engine/EngineInterface.php b/src/Phpro/SoapClient/Soap/Engine/EngineInterface.php new file mode 100644 index 00000000..06dafb5e --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Engine/EngineInterface.php @@ -0,0 +1,13 @@ +methods = $methods; + } + + /** + * @return \ArrayIterator|Method[] + */ + public function getIterator(): \ArrayIterator + { + return new \ArrayIterator($this->methods); + } + + public function count(): int + { + return count($this->methods); + } + + public function add(Method $method) + { + $this->methods[] = $method; + } + + public function map(callable $callback): array + { + return array_map($callback, $this->methods); + } + + public function fetchOneByName(string $name): Method + { + foreach ($this->methods as $method) { + if ($name === $method->getName()) { + return $method; + } + } + + throw MetadataException::methodNotFound($name); + } +} diff --git a/src/Phpro/SoapClient/Soap/Engine/Metadata/Collection/TypeCollection.php b/src/Phpro/SoapClient/Soap/Engine/Metadata/Collection/TypeCollection.php new file mode 100644 index 00000000..45f1ff47 --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Engine/Metadata/Collection/TypeCollection.php @@ -0,0 +1,62 @@ +types = $types; + } + + /** + * @return \ArrayIterator|Type[] + */ + public function getIterator(): \ArrayIterator + { + return new \ArrayIterator($this->types); + } + + public function count(): int + { + return count($this->types); + } + + public function add(Type $type) + { + $this->types[] = $type; + } + + public function addMany(TypeCollection $types) + { + foreach ($types as $type) { + $this->add($type); + } + } + + public function map(callable $callback): array + { + return array_map($callback, $this->types); + } + + public function fetchOneByName(string $name): Type + { + foreach ($this->types as $type) { + if ($name === $type->getName()) { + return $type; + } + } + + throw MetadataException::typeNotFound($name); + } +} diff --git a/src/Phpro/SoapClient/Soap/Engine/Metadata/Collection/XsdTypeCollection.php b/src/Phpro/SoapClient/Soap/Engine/Metadata/Collection/XsdTypeCollection.php new file mode 100644 index 00000000..924a5366 --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Engine/Metadata/Collection/XsdTypeCollection.php @@ -0,0 +1,54 @@ +types = $types; + } + + /** + * @return \ArrayIterator|XsdType[] + */ + public function getIterator(): \ArrayIterator + { + return new \ArrayIterator($this->types); + } + + public function count(): int + { + return count($this->types); + } + + public function add(XsdType $type) + { + $this->types[] = $type; + } + + public function map(callable $callback): array + { + return array_map($callback, $this->types); + } + + public function fetchByNameWithFallback(string $name): XsdType + { + foreach ($this->types as $type) { + if ($name === $type->getName()) { + return $type; + } + } + + return XsdType::guess($name); + } +} diff --git a/src/Phpro/SoapClient/Soap/Engine/Metadata/LazyInMemoryMetadata.php b/src/Phpro/SoapClient/Soap/Engine/Metadata/LazyInMemoryMetadata.php new file mode 100644 index 00000000..543966c1 --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Engine/Metadata/LazyInMemoryMetadata.php @@ -0,0 +1,49 @@ +metadata = $metadata; + } + + public function getTypes(): TypeCollection + { + if (!$this->types) { + $this->types = $this->metadata->getTypes(); + } + + return $this->types; + } + + public function getMethods(): MethodCollection + { + if (!$this->methods) { + $this->methods = $this->metadata->getMethods(); + } + + return $this->methods; + } +} diff --git a/src/Phpro/SoapClient/Soap/Engine/Metadata/MetadataInterface.php b/src/Phpro/SoapClient/Soap/Engine/Metadata/MetadataInterface.php new file mode 100644 index 00000000..f2c596d3 --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Engine/Metadata/MetadataInterface.php @@ -0,0 +1,14 @@ +name = $name; + $this->returnType = $returnType; + foreach ($parameters as $parameter) { + $this->addParameter($parameter); + } + } + + /** + * @return array|Parameter[] + */ + public function getParameters(): array + { + return $this->parameters; + } + + public function getName(): string + { + return $this->name; + } + + public function getReturnType(): XsdType + { + return $this->returnType; + } + + public function addParameter(Parameter $parameter): void + { + $this->parameters[] = $parameter; + } +} diff --git a/src/Phpro/SoapClient/Soap/Engine/Metadata/Model/Parameter.php b/src/Phpro/SoapClient/Soap/Engine/Metadata/Model/Parameter.php new file mode 100644 index 00000000..e7f4e13d --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Engine/Metadata/Model/Parameter.php @@ -0,0 +1,34 @@ +name = $name; + $this->type = $type; + } + + public function getName(): string + { + return $this->name; + } + + public function getType(): XsdType + { + return $this->type; + } +} diff --git a/src/Phpro/SoapClient/Soap/Engine/Metadata/Model/Property.php b/src/Phpro/SoapClient/Soap/Engine/Metadata/Model/Property.php new file mode 100644 index 00000000..e9feaebd --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Engine/Metadata/Model/Property.php @@ -0,0 +1,34 @@ +name = $name; + $this->type = $type; + } + + public function getName(): string + { + return $this->name; + } + + public function getType(): XsdType + { + return $this->type; + } +} diff --git a/src/Phpro/SoapClient/Soap/Engine/Metadata/Model/Type.php b/src/Phpro/SoapClient/Soap/Engine/Metadata/Model/Type.php new file mode 100644 index 00000000..0637b433 --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Engine/Metadata/Model/Type.php @@ -0,0 +1,49 @@ +xsdType = $xsdType; + foreach ($properties as $property) { + $this->addProperty($property); + } + } + + public function getName(): string + { + return $this->xsdType->getName(); + } + + public function getXsdType(): XsdType + { + return $this->xsdType; + } + + /** + * @return array|Property[] + */ + public function getProperties(): array + { + return $this->properties; + } + + public function addProperty(Property $property) + { + $this->properties[] = $property; + } +} diff --git a/src/Phpro/SoapClient/Soap/Engine/Metadata/Model/XsdType.php b/src/Phpro/SoapClient/Soap/Engine/Metadata/Model/XsdType.php new file mode 100644 index 00000000..fda3434d --- /dev/null +++ b/src/Phpro/SoapClient/Soap/Engine/Metadata/Model/XsdType.php @@ -0,0 +1,174 @@ +name = $name; + } + + public static function create(string $name): self + { + return new self($name); + } + + public static function guess(string $name): self + { + return self::create($name) + ->withBaseType(self::convertBaseType($name, '')); + } + + public static function fetchAllKnownBaseTypeMappings(): array + { + return [ + 'anyuri' => 'string', + 'base64binary' => 'string', + 'byte' => 'integer', + 'decimal' => 'float', + 'double' => 'float', + 'duration' => 'string', + 'entities' => 'string', + 'entity' => 'string', + 'gday' => 'string', + 'gmonth' => 'string', + 'gmonthday' => 'string', + 'gyear' => 'string', + 'gyearmonth' => 'string', + 'hexbinary' => 'string', + 'id' => 'string', + 'idref' => 'string', + 'idrefs' => 'string', + 'int' => 'integer', + 'language' => 'string', + 'long' => 'integer', + 'map' => 'array', + 'name' => 'string', + 'ncname' => 'string', + 'ncnames' => 'string', + 'negativeinteger' => 'integer', + 'nmtoken' => 'string', + 'nmtokens' => 'string', + 'nonnegativeinteger' => 'integer', + 'nonpositiveinteger' => 'integer', + 'normalizedstring' => 'string', + 'notation' => 'string', + 'positiveinteger' => 'integer', + 'qname' => 'string', + 'short' => 'integer', + 'struct' => 'object', + 'time' => 'string', + 'timeinstant' => 'string', + 'token' => 'string', + 'unknown' => 'anyType', + 'unsignedbyte' => 'integer', + 'unsignedint' => 'integer', + 'unsignedlong' => 'integer', + 'unsignedshort' => 'integer', + ]; + } + + public function getName(): string + { + return $this->name; + } + + public function getBaseType(): string + { + return $this->baseType; + } + + public function getBaseTypeOrFallbackToName(): string + { + return $this->baseType ?: $this->name; + } + + public function getMemberTypes(): array + { + return $this->memberTypes; + } + + public function getXmlNamespace(): string + { + return $this->xmlNamespace; + } + + public function getXmlNamespaceName(): string + { + return $this->xmlNamespaceName; + } + + public function withXmlNamespace(string $xmlNamespace): self + { + $new = clone $this; + $new->xmlNamespace = $xmlNamespace; + + return $new; + } + + public function withXmlNamespaceName(string $xmlNamespaceName): self + { + $new = clone $this; + $new->xmlNamespaceName = $xmlNamespaceName; + + return $new; + } + + public function withBaseType(string $baseType): self + { + $new = clone $this; + $new->baseType = self::convertBaseType($baseType, $baseType); + + if ($new->baseType !== $baseType) { + $new->memberTypes[] = $baseType; + } + + return $new; + } + + public function withMemberTypes(array $memberTypes): self + { + $new = clone $this; + $new->memberTypes = array_values(array_filter($memberTypes)); + + return $new; + } + + public function __toString(): string + { + return $this->name; + } + + private static function convertBaseType(string $baseType, string $fallback): string + { + return self::fetchAllKnownBaseTypeMappings()[strtolower($baseType)] ?? $fallback; + } +} diff --git a/src/Phpro/SoapClient/Soap/Handler/HandlerInterface.php b/src/Phpro/SoapClient/Soap/Handler/HandlerInterface.php index e76de0aa..a1b89861 100644 --- a/src/Phpro/SoapClient/Soap/Handler/HandlerInterface.php +++ b/src/Phpro/SoapClient/Soap/Handler/HandlerInterface.php @@ -10,9 +10,8 @@ * * @package Phpro\SoapClient\Soap\Handler */ -interface HandlerInterface +interface HandlerInterface extends LastRequestInfoCollectorInterface { - /** * @param SoapRequest $request * diff --git a/src/Phpro/SoapClient/Soap/Handler/HttPlugHandle.php b/src/Phpro/SoapClient/Soap/Handler/HttPlugHandle.php index 9350d049..f84066ba 100644 --- a/src/Phpro/SoapClient/Soap/Handler/HttPlugHandle.php +++ b/src/Phpro/SoapClient/Soap/Handler/HttPlugHandle.php @@ -17,7 +17,7 @@ use Phpro\SoapClient\Soap\HttpBinding\SoapRequest; use Phpro\SoapClient\Soap\HttpBinding\SoapResponse; -class HttPlugHandle implements HandlerInterface, MiddlewareSupportingInterface, LastRequestInfoCollectorInterface +class HttPlugHandle implements HandlerInterface, MiddlewareSupportingInterface { /** * @var HttpClient diff --git a/src/Phpro/SoapClient/Soap/HttpBinding/Converter/Psr7ToLastRequestInfoConverter.php b/src/Phpro/SoapClient/Soap/HttpBinding/Converter/Psr7ToLastRequestInfoConverter.php new file mode 100644 index 00000000..db21eeb2 --- /dev/null +++ b/src/Phpro/SoapClient/Soap/HttpBinding/Converter/Psr7ToLastRequestInfoConverter.php @@ -0,0 +1,64 @@ +getBody()->rewind(); + $response->getBody()->rewind(); + + $formatter = new FullHttpMessageFormatter(null); + $requestString = $formatter->formatRequest($request); + $responseString = $formatter->formatResponse($response); + + $requestHeaders = ''; + $requestBody = ''; + $responseHeaders = ''; + $responseBody = ''; + + if ($requestString) { + $requestParts = explode( + "\n\n", + substr($requestString, strpos($requestString, "\n") + 1), + 2 + ); + + $requestHeaders = trim($requestParts[0] ?? ''); + $requestBody = $requestParts[1] ?? ''; + } + + if ($responseString) { + $responseParts = explode( + "\n\n", + substr($responseString, strpos($responseString, "\n") + 1), + 2 + ); + + $responseHeaders = trim($responseParts[0] ?? ''); + $responseBody = $responseParts[1] ?? ''; + } + + // Reset the bodies: + $request->getBody()->rewind(); + $response->getBody()->rewind(); + + return new LastRequestInfo( + $requestHeaders, + $requestBody, + $responseHeaders, + $responseBody + ); + } +} diff --git a/src/Phpro/SoapClient/Soap/HttpBinding/LastRequestInfo.php b/src/Phpro/SoapClient/Soap/HttpBinding/LastRequestInfo.php index 823f2d12..90c903b9 100644 --- a/src/Phpro/SoapClient/Soap/HttpBinding/LastRequestInfo.php +++ b/src/Phpro/SoapClient/Soap/HttpBinding/LastRequestInfo.php @@ -2,10 +2,6 @@ namespace Phpro\SoapClient\Soap\HttpBinding; -use Http\Message\Formatter\FullHttpMessageFormatter; -use Psr\Http\Message\RequestInterface; -use Psr\Http\Message\ResponseInterface; - /** * Class LastRequestInfo * @@ -53,78 +49,6 @@ public function __construct( $this->lastResponse = $lastResponse; } - /** - * @param \SoapClient $soapClient - * - * @return LastRequestInfo - */ - public static function createFromSoapClient(\SoapClient $soapClient): self - { - return new self( - (string) $soapClient->__getLastRequestHeaders(), - (string) $soapClient->__getLastRequest(), - (string) $soapClient->__getLastResponseHeaders(), - (string) $soapClient->__getLastResponse() - ); - } - - /** - * @param RequestInterface $request - * @param ResponseInterface $response - * - * @return LastRequestInfo - */ - public static function createFromPsr7RequestAndResponse( - RequestInterface $request, - ResponseInterface $response - ): self { - // Reset the bodies: - $request->getBody()->rewind(); - $response->getBody()->rewind(); - - $formatter = new FullHttpMessageFormatter(null); - $requestString = $formatter->formatRequest($request); - $responseString = $formatter->formatResponse($response); - - $requestHeaders = ''; - $requestBody = ''; - $responseHeaders = ''; - $responseBody = ''; - - if ($requestString) { - $requestParts = explode( - "\n\n", - substr($requestString, strpos($requestString, "\n") + 1), - 2 - ); - - $requestHeaders = trim($requestParts[0] ?? ''); - $requestBody = $requestParts[1] ?? ''; - } - - if ($responseString) { - $responseParts = explode( - "\n\n", - substr($responseString, strpos($responseString, "\n") + 1), - 2 - ); - - $responseHeaders = trim($responseParts[0] ?? ''); - $responseBody = $responseParts[1] ?? ''; - } - - // Reset the bodies: - $request->getBody()->rewind(); - $response->getBody()->rewind(); - - return new self( - $requestHeaders, - $requestBody, - $responseHeaders, - $responseBody - ); - } - /** * @return LastRequestInfo */ diff --git a/src/Phpro/SoapClient/Soap/SoapClient.php b/src/Phpro/SoapClient/Soap/SoapClient.php deleted file mode 100644 index d2a37303..00000000 --- a/src/Phpro/SoapClient/Soap/SoapClient.php +++ /dev/null @@ -1,228 +0,0 @@ -handler = new SoapHandle($this); - $this->options = $options; - } - - /** - * @param HandlerInterface $handler - */ - public function setHandler(HandlerInterface $handler) - { - $this->handler = $handler; - } - - /** - * Retrieve SOAP types from the WSDL and parse them - * - * @return array Array of types and their properties - */ - public function getSoapTypes(): array - { - if ($this->types) { - return $this->types; - } - - $soapTypes = $this->__getTypes(); - foreach ($soapTypes as $soapType) { - $properties = []; - $lines = explode("\n", $soapType); - if (!preg_match('/struct (.*) {/', $lines[0], $matches)) { - continue; - } - $typeName = $matches[1]; - - foreach (array_slice($lines, 1) as $line) { - if ($line === '}') { - continue; - } - preg_match('/\s* (.*) (.*);/', $line, $matches); - $properties[$matches[2]] = $matches[1]; - } - - $this->types[$typeName] = $properties; - } - - return $this->types; - } - - /** - * Get SOAP elements for a complexType - * - * @param string $complexType Name of SOAP complexType - * - * @return array Names of elements and their types - */ - public function getSoapElements(string $complexType): array - { - $types = $this->getSoapTypes(); - if (isset($types[$complexType])) { - return $types[$complexType]; - } - } - - /** - * Get a SOAP type’s element - * - * @param string $complexType Name of SOAP complexType - * @param string $element Name of element belonging to SOAP complexType - * - * @return string - */ - public function getSoapElementType(string $complexType, string $element): string - { - $elements = $this->getSoapElements($complexType); - if ($elements && isset($elements[$element])) { - return $elements[$element]; - } - } - - /** - * @param string $request - * @param string $location - * @param string $action - * @param int $version - * @param int $oneWay - * - * @return string - */ - public function doInternalRequest( - string $request, - string $location, - string $action, - int $version, - int $oneWay = 0 - ): string { - return (string)parent::__doRequest($request, $location, $action, $version, $oneWay); - } - - /** - * @param string $request - * @param string $location - * @param string $action - * @param int $version - * @param int $oneWay - * - * @return string|null - */ - public function __doRequest($request, $location, $action, $version, $oneWay = 0) - { - $request = new SoapRequest($request, $location, $action, $version, $oneWay); - $response = $this->handler->request($request); - - // Fecth the last request information: - $lastRequestInfo = LastRequestInfo::createEmpty(); - if ($this->handler instanceof LastRequestInfoCollectorInterface) { - $lastRequestInfo = $this->handler->collectLastRequestInfo(); - } - - // Copy the request info in the correct internal __last_* parameters: - // We don't need the trace option: always remember the last response @ request - $this->__last_request = (string)$lastRequestInfo->getLastRequest() ?? $request; - $this->__last_response = (string)$lastRequestInfo->getLastResponse() ?? $response->getResponse(); - $this->__last_request_headers = (string)$lastRequestInfo->getLastRequestHeaders(); - $this->__last_response_headers = (string)$lastRequestInfo->getLastResponseHeaders(); - - // Return the response or an empty response when oneWay is enabled. - return $oneWay ? null : $response->getResponse(); - } - - /*** - * @return string - */ - public function __getLastRequest(): string - { - return $this->__last_request ?: (string)parent::__getLastRequest(); - } - - /** - * @return string - */ - public function __getLastResponse(): string - { - return $this->__last_response ?: (string)parent::__getLastResponse(); - } - - /** - * @return string - */ - public function __getLastRequestHeaders(): string - { - return $this->__last_request_headers ?: (string)parent::__getLastRequestHeaders(); - } - - /** - * @return string - */ - public function __getLastResponseHeaders(): string - { - return $this->__last_response_headers ?: (string)parent::__getLastResponseHeaders(); - } -} diff --git a/src/Phpro/SoapClient/Soap/SoapClientFactory.php b/src/Phpro/SoapClient/Soap/SoapClientFactory.php deleted file mode 100644 index b94afda8..00000000 --- a/src/Phpro/SoapClient/Soap/SoapClientFactory.php +++ /dev/null @@ -1,60 +0,0 @@ -classMap = $classMap; - $this->typeConverters = $typeConverters; - } - - /** - * @param string $wsdl - * @param array $soapOptions - * - * @return SoapClient - */ - public function factory(string $wsdl, array $soapOptions = []): SoapClient - { - $defaults = [ - 'trace' => true, - 'exceptions' => true, - 'keep_alive' => true, - 'cache_wsdl' => WSDL_CACHE_BOTH, - 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, - 'classmap' => $this->classMap->toSoapClassMap(), - 'typemap' => $this->typeConverters->toSoapTypeMap(), - ]; - - $options = array_merge($defaults, $soapOptions); - - return new PhproSoapClient($wsdl, $options); - } -} diff --git a/src/Phpro/SoapClient/Soap/TypeConverter/DateTimeTypeConverter.php b/src/Phpro/SoapClient/Soap/TypeConverter/DateTimeTypeConverter.php index 3d1875d0..d302eb83 100644 --- a/src/Phpro/SoapClient/Soap/TypeConverter/DateTimeTypeConverter.php +++ b/src/Phpro/SoapClient/Soap/TypeConverter/DateTimeTypeConverter.php @@ -2,7 +2,7 @@ namespace Phpro\SoapClient\Soap\TypeConverter; -use DateTime; +use DateTimeImmutable; use DateTimeInterface; use DateTimeZone; use DOMDocument; @@ -44,7 +44,7 @@ public function convertXmlToPhp(string $data) return null; } - $dateTime = new DateTime($doc->textContent); + $dateTime = new DateTimeImmutable($doc->textContent); $dateTime->setTimezone(new DateTimeZone(date_default_timezone_get())); return $dateTime; diff --git a/src/Phpro/SoapClient/Soap/TypeConverter/DateTypeConverter.php b/src/Phpro/SoapClient/Soap/TypeConverter/DateTypeConverter.php index 11495eb0..d4fda13d 100644 --- a/src/Phpro/SoapClient/Soap/TypeConverter/DateTypeConverter.php +++ b/src/Phpro/SoapClient/Soap/TypeConverter/DateTypeConverter.php @@ -2,7 +2,7 @@ namespace Phpro\SoapClient\Soap\TypeConverter; -use DateTime; +use DateTimeImmutable; use DateTimeInterface; use DOMDocument; @@ -43,9 +43,7 @@ public function convertXmlToPhp(string $data) return null; } - $dateTime = new DateTime($doc->textContent); - - return $dateTime; + return new DateTimeImmutable($doc->textContent); } /** diff --git a/src/Phpro/SoapClient/Soap/TypeConverter/TypeConverterCollection.php b/src/Phpro/SoapClient/Soap/TypeConverter/TypeConverterCollection.php index c8ac9132..81f9bd58 100644 --- a/src/Phpro/SoapClient/Soap/TypeConverter/TypeConverterCollection.php +++ b/src/Phpro/SoapClient/Soap/TypeConverter/TypeConverterCollection.php @@ -2,16 +2,11 @@ namespace Phpro\SoapClient\Soap\TypeConverter; +use IteratorAggregate; use Phpro\SoapClient\Exception\InvalidArgumentException; +use Traversable; -/** - * Class TypeConverterCollection - * - * A collection of type converters - * - * @package Phpro\SoapClient\Soap\TypeConverter - */ -class TypeConverterCollection +class TypeConverterCollection implements IteratorAggregate { /** * @var array|TypeConverterInterface[] @@ -93,27 +88,10 @@ public function has(TypeConverterInterface $converter): bool } /** - * Get this collection as a typemap that can be used in PHP's \SoapClient - * - * @return array + * @return \ArrayIterator|TypeConverterInterface[] */ - public function toSoapTypeMap(): array + public function getIterator(): \ArrayIterator { - $typemap = []; - - foreach ($this->converters as $converter) { - $typemap[] = [ - 'type_name' => $converter->getTypeName(), - 'type_ns' => $converter->getTypeNamespace(), - 'from_xml' => function ($input) use ($converter) { - return $converter->convertXmlToPhp($input); - }, - 'to_xml' => function ($input) use ($converter) { - return $converter->convertPhpToXml($input); - }, - ]; - } - - return $typemap; + return new \ArrayIterator($this->converters); } } diff --git a/src/Phpro/SoapClient/Xml/SoapXml.php b/src/Phpro/SoapClient/Xml/SoapXml.php index db9a684d..d1a433b3 100644 --- a/src/Phpro/SoapClient/Xml/SoapXml.php +++ b/src/Phpro/SoapClient/Xml/SoapXml.php @@ -25,6 +25,10 @@ public function __construct(DOMDocument $xml) // Register some default namespaces for easy access: $this->registerNamespace('soap', $this->getSoapNamespaceUri()); + + if ($bodyNamespace = $this->detectBodyContentsNamespace()) { + $this->registerNamespace('application', $bodyNamespace); + } } /** @@ -35,6 +39,15 @@ public function getSoapNamespaceUri(): string return $this->getEnvelope()->namespaceURI; } + public function detectBodyContentsNamespace(): ?string + { + if (!$body = $this->getBody()) { + return null; + } + + return $body->firstChild ? $body->firstChild->namespaceURI : null; + } + /** * @param string $prefix * @param string $namespaceUri @@ -81,7 +94,7 @@ public function prependSoapHeader(DOMElement $header) /** * @return DOMElement|null */ - public function getBody(): DOMElement + public function getBody(): ?DOMElement { $list = $this->xpath('//soap:Envelope/soap:Body'); diff --git a/src/Phpro/SoapClient/Xml/Xml.php b/src/Phpro/SoapClient/Xml/Xml.php index e3f2f582..e57b17ea 100644 --- a/src/Phpro/SoapClient/Xml/Xml.php +++ b/src/Phpro/SoapClient/Xml/Xml.php @@ -71,12 +71,13 @@ public function getRootElement(): DOMElement /** * @param string $expression + * @param DOMNode|null $contextNode * * @return \DOMNodeList */ - public function xpath(string $expression): \DOMNodeList + public function xpath(string $expression, \DOMNode $contextNode = null): \DOMNodeList { - return $this->xpath->query($expression); + return $this->xpath->query($expression, $contextNode); } /** @@ -96,9 +97,9 @@ public static function fromStream(StreamInterface $stream): Xml /** * @param string $content * - * @return Xml + * @return static */ - public static function fromString(string $content): Xml + public static function fromString(string $content) { $xml = new DOMDocument(); $xml->loadXML($content); diff --git a/test/PhproTest/SoapClient/Functional/AbstractSoapTestCase.php b/test/PhproTest/SoapClient/Functional/AbstractSoapTestCase.php deleted file mode 100644 index a63b6236..00000000 --- a/test/PhproTest/SoapClient/Functional/AbstractSoapTestCase.php +++ /dev/null @@ -1,74 +0,0 @@ -getWsdl(); - $options = $this->getSoapOptions(); - - $this->server = new SoapServer($wsdl, $options); - $this->configureServer($this->server); - $this->configureSoapClient($wsdl, $options); - } - - protected function configureSoapClient($wsdl, $options) - { - $this->client = new PhproSoapClient($wsdl, $options); - $this->client->setHandler(new LocalSoapServerHandle($this->server)); - } - - protected function generateInMemoryWsdl(string $wsdl): string - { - return (new InMemoryWsdlProvider())->provide($wsdl); - } - - protected function provideBasicNonWsdlOptions(): array { - return [ - 'soap_version' => SOAP_1_2, - 'uri' => 'http://localhost/dummysoap', - 'location' => 'http://localhost/dummysoap', - 'cache_wsdl' => WSDL_CACHE_NONE - ]; - } - - protected function provideBasicWsdlOptions(array $additionalOptions = []): array { - return array_merge( - [ - 'soap_version' => SOAP_1_2, - 'cache_wsdl' => WSDL_CACHE_NONE - ], - $additionalOptions - ); - } -} diff --git a/test/PhproTest/SoapClient/Functional/Encoding/Base64BinaryTest.php b/test/PhproTest/SoapClient/Functional/Encoding/Base64BinaryTest.php deleted file mode 100644 index 2f50ac2f..00000000 --- a/test/PhproTest/SoapClient/Functional/Encoding/Base64BinaryTest.php +++ /dev/null @@ -1,104 +0,0 @@ -setObject(new class() { - public function validate($input) - { - return [ - 'input' => $input, - 'output' => 'output', - ]; - } - }); - } - - protected function getWsdl() - { - return FIXTURE_DIR . '/wsdl/functional/base64Binary.wsdl'; - } - - protected function getSoapOptions(): array { - return $this->provideBasicNonWsdlOptions(); - } - - /** - * @test - * @runInSeparateProcess - */ - function it_automatically_converts_base64_binary_fields() - { - $input = 'input'; - $output = 'output'; - $response = (array)$this->client->validate($input); - - $this->assertEquals($output, $response['output']); - $this->assertEquals($input, $response['input']); - $this->assertContains(base64_encode($input), $this->client->__getLastRequest()); - $this->assertContains(base64_encode($output), $this->client->__getLastResponse()); - } - - /** - * @test - * @runInSeparateProcess - */ - function it_automatically_converts_base64_binary_internal_types() - { - $input = 'input'; - $output = 'output'; - $response = (array)$this->client->validate(new SoapVar('input', XSD_BASE64BINARY)); - - $this->assertEquals($output, $response['output']); - $this->assertEquals($input, $response['input']); - $this->assertContains(base64_encode($input), $this->client->__getLastRequest()); - $this->assertContains(base64_encode($output), $this->client->__getLastResponse()); - } - - /** - * @test - * @runInSeparateProcess - */ - function it_is_possible_to_get_the_raw_value_with_type_converter() - { - $this->configureSoapClient($this->getWsdl(), $this->provideBasicWsdlOptions([ - 'typemap' => [ - [ - 'type_name' => 'base64Binary', - 'type_ns' => 'http://www.w3.org/2001/XMLSchema', - 'from_xml' => function($xml) { - $doc = new \DOMDocument(); - $doc->loadXML($xml); - - if ('' === $doc->textContent) { - return null; - } - - return $doc->textContent; - }, - 'to_xml' => function($raw) { - return sprintf('%s', $raw); - }, - ], - ], - ])); - - $input = base64_encode('input'); - $output = base64_encode('output'); - $response = (array)$this->client->validate($input); - - $this->assertEquals($output, $response['output']); - $this->assertEquals(base64_decode($input), $response['input']); - $this->assertContains($input, $this->client->__getLastRequest()); - $this->assertContains($output, $this->client->__getLastResponse()); - } -} diff --git a/test/PhproTest/SoapClient/Functional/Encoding/DuplicateTypenamesTest.php b/test/PhproTest/SoapClient/Functional/Encoding/DuplicateTypenamesTest.php deleted file mode 100644 index fa2e958e..00000000 --- a/test/PhproTest/SoapClient/Functional/Encoding/DuplicateTypenamesTest.php +++ /dev/null @@ -1,162 +0,0 @@ -setObject(new class() { - public function validate($store1, $store2) - { - return ['output1' => $store1, 'output2' => $store2]; - } - }); - } - - protected function getWsdl(): string - { - return FIXTURE_DIR . '/wsdl/functional/duplicate-typenames.wsdl'; - } - - protected function getSoapOptions(): array { - return $this->provideBasicWsdlOptions(); - } - - /** @test */ - function it_does_only_register_the_last_type() - { - $types = $this->client->getSoapTypes(); - $this->assertCount(1, $types); - - $type = $types['Store']; - - $this->assertEquals($type['Attribute2'], 'string'); - } - - /** - * @ test - * @runInSeparateProcess - */ - function it_knows_how_to_encode_both_types() - { - $store1 = (object) ['Attribute1' => 'ok']; - $store2 = (object) ['Attribute2' => 'ok']; - - $response = $this->client->validate($store1, $store2); - - $this->assertEquals($store1, $response['output1']); - $this->assertEquals($store2, $response['output2']); - - $this->assertContains('ok', $this->client->__getLastRequest()); - $this->assertContains('ok', $this->client->__getLastRequest()); - $this->assertContains('ok', $this->client->__getLastResponse()); - $this->assertContains('ok', $this->client->__getLastResponse()); - } - - /** - * @test - * @runInSeparateProcess - */ - function it_uses_same_model_for_both_objects() - { - $this->configureSoapClient($this->getWsdl(), $this->provideBasicWsdlOptions([ - 'classmap' => [ - 'Store' => DuplicateTypeStore::class, - ], - ])); - $this->server->setObject(new class() { - public function validate($store1, $store2) - { - return [ - 'output1' => new DuplicateTypeStore('attr1', null), - 'output2' => new DuplicateTypeStore(null, 'attr2') - ]; - } - }); - - $store1 = new DuplicateTypeStore('attr1', 'attr2'); - $store2 = new DuplicateTypeStore('attr1', 'attr2'); - $response = $this->client->validate($store1, $store2); - - $this->assertEquals(new DuplicateTypeStore('attr1', null), $response['output1']); - $this->assertEquals(new DuplicateTypeStore(null, 'attr2'), $response['output2']); - $this->assertContains('attr1', $this->client->__getLastRequest()); - $this->assertContains('attr1', $this->client->__getLastRequest()); - $this->assertContains('attr1', $this->client->__getLastResponse()); - $this->assertContains('attr2', $this->client->__getLastResponse()); - } - - /** - * @test - * @runInSeparateProcess - */ - function it_is_possible_to_override_a_single_instance_with_typemap() - { - $this->configureSoapClient($this->getWsdl(), $this->provideBasicWsdlOptions([ - 'classmap' => [ - 'Store' => DuplicateTypeStore::class, - ], - 'typemap' => [ - [ - 'type_name' => 'Store', - 'type_ns' => 'http://soapinterop.org/xsd1', - 'from_xml' => function($xml) { - $doc = new \DOMDocument(); - $doc->loadXML($xml); - $attr1 = $doc->childNodes->item(0)->textContent; - - return $this->createStore1Class($attr1); - }, - ], - ], - ])); - $this->server->setObject(new class() { - public function validate($store1, $store2) - { - return [ - 'output1' => new DuplicateTypeStore('attr1', null), - 'output2' => new DuplicateTypeStore(null, 'attr2') - ]; - } - }); - - $store1 = new DuplicateTypeStore('attr1', 'attr2'); - $store2 = new DuplicateTypeStore('attr1', 'attr2'); - $response = $this->client->validate($store1, $store2); - - $this->assertEquals($this->createStore1Class('attr1'), $response['output1']); - $this->assertEquals(new DuplicateTypeStore(null, 'attr2'), $response['output2']); - $this->assertContains('attr1', $this->client->__getLastRequest()); - $this->assertContains('attr1', $this->client->__getLastRequest()); - $this->assertContains('attr1', $this->client->__getLastResponse()); - $this->assertContains('attr2', $this->client->__getLastResponse()); - } - - private function createStore1Class($attr1) { - return new class($attr1) { - private $Attribute1; - public function __construct($Attribute1) - { - $this->Attribute1 = $Attribute1; - } - }; - } -} - - -class DuplicateTypeStore { - public $Attribute1; - public $Attribute2; - - public function __construct($Attribute1, $Attribute2) - { - $this->Attribute1 = $Attribute1; - $this->Attribute2 = $Attribute2; - } -} diff --git a/test/PhproTest/SoapClient/Functional/Encoding/SimpleContentTest.php b/test/PhproTest/SoapClient/Functional/Encoding/SimpleContentTest.php deleted file mode 100644 index 0223d572..00000000 --- a/test/PhproTest/SoapClient/Functional/Encoding/SimpleContentTest.php +++ /dev/null @@ -1,54 +0,0 @@ -setObject(new class() { - public function validate($input) - { - return $input; - } - }); - } - - protected function getWsdl(): string - { - return FIXTURE_DIR . '/wsdl/functional/simpleContent.wsdl'; - } - - protected function getSoapOptions(): array { - return $this->provideBasicWsdlOptions(); - } - - /** @test */ - function it_can_parse_simple_content_types() - { - $types = $this->client->getSoapTypes(); - $type = $types['SimpleContent']; - - $this->assertEquals($type['country'], 'string'); - $this->assertEquals($type['_'], 'integer'); - } - - /** - * @test - * @runInSeparateProcess - */ - function it_uses_underscores_internally_as_node_value_of_simple_content() - { - $input = $output = ['_' => 132, 'country' => 'BE']; - $response = (array) $this->client->validate($input); - - $this->assertEquals($output, $response); - $this->assertContains('132', $this->client->__getLastRequest()); - $this->assertContains('132', $this->client->__getLastResponse()); - } -} diff --git a/test/PhproTest/SoapClient/Functional/Encoding/XmlEntitiesTest.php b/test/PhproTest/SoapClient/Functional/Encoding/XmlEntitiesTest.php deleted file mode 100644 index dc3f4400..00000000 --- a/test/PhproTest/SoapClient/Functional/Encoding/XmlEntitiesTest.php +++ /dev/null @@ -1,50 +0,0 @@ -setObject(new class() { - public function validate($input) - { - return [ - 'input' => $input, - 'output' => '<\'"Sômé Spèçìâl Chàrz"\'>', - ]; - } - }); - } - - protected function getWsdl() - { - return null; - } - - protected function getSoapOptions(): array { - return $this->provideBasicNonWsdlOptions(); - } - - /** - * @test - * @runInSeparateProcess - */ - function it_encodes_special_characters() - { - $input = '<\'"ïnpüt"\'>'; - $output = '<\'"Sômé Spèçìâl Chàrz"\'>'; - - $response = $this->client->validate($input); - $this->assertEquals($input, $response['input']); - $this->assertEquals($output, $response['output']); - - $this->assertContains(htmlspecialchars($input, ENT_NOQUOTES), $this->client->__getLastRequest()); - $this->assertContains(htmlspecialchars($output, ENT_NOQUOTES), $this->client->__getLastResponse()); - } -} diff --git a/test/PhproTest/SoapClient/Functional/ExtSoap/AbstractSoapTestCase.php b/test/PhproTest/SoapClient/Functional/ExtSoap/AbstractSoapTestCase.php new file mode 100644 index 00000000..78f39436 --- /dev/null +++ b/test/PhproTest/SoapClient/Functional/ExtSoap/AbstractSoapTestCase.php @@ -0,0 +1,30 @@ +disableWsdlCache() + ); + } + + protected function configureServer(string $wsdl, array $options, $object): ExtSoapServerHandle + { + $options = ExtSoapOptions::defaults($wsdl, $options)->disableWsdlCache(); + + $server = new \SoapServer($options->getWsdl(), $options->getOptions()); + $server->setObject($object); + + return new ExtSoapServerHandle($server); + } +} diff --git a/test/PhproTest/SoapClient/Functional/ExtSoap/Encoding/DuplicateTypenamesTest.php b/test/PhproTest/SoapClient/Functional/ExtSoap/Encoding/DuplicateTypenamesTest.php new file mode 100644 index 00000000..c157960c --- /dev/null +++ b/test/PhproTest/SoapClient/Functional/ExtSoap/Encoding/DuplicateTypenamesTest.php @@ -0,0 +1,199 @@ +wsdl = FIXTURE_DIR.'/wsdl/functional/duplicate-typenames.wsdl'; + $this->driver = $this->configureSoapDriver($this->wsdl, []); + $this->handler = $this->configureServer( + $this->wsdl, + [], + new class() + { + public function validate($store1, $store2) + { + return ['output1' => $store1, 'output2' => $store2]; + } + } + ); + } + + /** @test */ + function it_registers_both_types() + { + $types = $this->driver->getMetadata()->getTypes(); + $this->assertCount(2, $types); + + $store1 = $types->getIterator()[0]; + $store2 = $types->getIterator()[1]; + + $this->assertEquals($store1->getName(), 'Store'); + $this->assertEquals($store1->getProperties()[0]->getName(), 'Attribute1'); + $this->assertEquals($store2->getName(), 'Store'); + $this->assertEquals($store2->getProperties()[0]->getName(), 'Attribute2'); + } + + /** + * @test + * @runInSeparateProcess + */ + function it_knows_how_to_encode_both_types() + { + $engine = new Engine($this->driver, $this->handler); + $store1 = (object) ['Attribute1' => 'ok']; + $store2 = (object) ['Attribute2' => 'ok']; + + $response = $engine->request('validate', [$store1, $store2]); + + $this->assertEquals($store1, $response['output1']); + $this->assertEquals($store2, $response['output2']); + + $lastRequestInfo = $this->handler->collectLastRequestInfo(); + $this->assertContains('ok', $lastRequestInfo->getLastRequest()); + $this->assertContains('ok', $lastRequestInfo->getLastRequest()); + $this->assertContains('ok', $lastRequestInfo->getLastResponse()); + $this->assertContains('ok', $lastRequestInfo->getLastResponse()); + } + + /** + * @test + * @runInSeparateProcess + */ + function it_uses_same_model_for_both_objects() + { + $this->driver = $this->configureSoapDriver($this->wsdl, [ + 'classmap' => new ClassMapCollection([ + new ClassMap('Store', DuplicateTypeStore::class) + ]) + ]); + $this->handler = $this->configureServer( + $this->wsdl, + [], + new class() + { + public function validate($store1, $store2) + { + return [ + 'output1' => new DuplicateTypeStore('attr1', null), + 'output2' => new DuplicateTypeStore(null, 'attr2') + ]; + } + } + ); + + $engine = new Engine($this->driver, $this->handler); + $store1 = new DuplicateTypeStore('attr1', 'attr2'); + $store2 = new DuplicateTypeStore('attr1', 'attr2'); + $response = $engine->request('validate', [$store1, $store2]); + $lastRequestInfo = $this->handler->collectLastRequestInfo(); + + $this->assertEquals(new DuplicateTypeStore('attr1', null), $response['output1']); + $this->assertEquals(new DuplicateTypeStore(null, 'attr2'), $response['output2']); + $this->assertContains('attr1', $lastRequestInfo->getLastRequest()); + $this->assertContains('attr1', $lastRequestInfo->getLastRequest()); + $this->assertContains('attr1', $lastRequestInfo->getLastResponse()); + $this->assertContains('attr2', $lastRequestInfo->getLastResponse()); + } + + /** + * @test + * @runInSeparateProcess + */ + function it_is_possible_to_override_a_single_instance_with_typemap() + { + $this->driver = $this->configureSoapDriver($this->wsdl, [ + 'classmap' => new ClassMapCollection([ + new ClassMap('Store', DuplicateTypeStore::class) + ]), + 'typemap' => [ + [ + 'type_name' => 'Store', + 'type_ns' => 'http://soapinterop.org/xsd1', + 'from_xml' => function($xml) { + $doc = new \DOMDocument(); + $doc->loadXML($xml); + $attr1 = $doc->childNodes->item(0)->textContent; + + return $this->createStore1Class($attr1); + }, + ], + ] + ]); + $this->handler = $this->configureServer( + $this->wsdl, + [], + new class() + { + public function validate($store1, $store2) + { + return [ + 'output1' => new DuplicateTypeStore('attr1', null), + 'output2' => new DuplicateTypeStore(null, 'attr2') + ]; + } + } + ); + + $engine = new Engine($this->driver, $this->handler); + $store1 = new DuplicateTypeStore('attr1', 'attr2'); + $store2 = new DuplicateTypeStore('attr1', 'attr2'); + $response = $engine->request('validate', [$store1, $store2]); + $lastRequestInfo = $this->handler->collectLastRequestInfo(); + + $this->assertEquals($this->createStore1Class('attr1'), $response['output1']); + $this->assertEquals(new DuplicateTypeStore(null, 'attr2'), $response['output2']); + $this->assertContains('attr1', $lastRequestInfo->getLastRequest()); + $this->assertContains('attr1', $lastRequestInfo->getLastRequest()); + $this->assertContains('attr1', $lastRequestInfo->getLastResponse()); + $this->assertContains('attr2', $lastRequestInfo->getLastResponse()); + } + + private function createStore1Class($attr1) { + return new class($attr1) { + private $Attribute1; + public function __construct($Attribute1) + { + $this->Attribute1 = $Attribute1; + } + }; + } +} + + +class DuplicateTypeStore { + public $Attribute1; + public $Attribute2; + + public function __construct($Attribute1, $Attribute2) + { + $this->Attribute1 = $Attribute1; + $this->Attribute2 = $Attribute2; + } +} diff --git a/test/PhproTest/SoapClient/Functional/Encoding/EnumTest.php b/test/PhproTest/SoapClient/Functional/ExtSoap/Encoding/EnumTest.php similarity index 53% rename from test/PhproTest/SoapClient/Functional/Encoding/EnumTest.php rename to test/PhproTest/SoapClient/Functional/ExtSoap/Encoding/EnumTest.php index 62873462..262d9914 100644 --- a/test/PhproTest/SoapClient/Functional/Encoding/EnumTest.php +++ b/test/PhproTest/SoapClient/Functional/ExtSoap/Encoding/EnumTest.php @@ -2,36 +2,51 @@ declare( strict_types=1 ); -namespace PhproTest\SoapClient\Functional\Encoding; +namespace PhproTest\SoapClient\Functional\ExtSoap\Encoding; -use PhproTest\SoapClient\Functional\AbstractSoapTestCase; -use SoapServer; +use Phpro\SoapClient\Soap\Driver\ExtSoap\ExtSoapDriver; +use Phpro\SoapClient\Soap\Driver\ExtSoap\Handler\ExtSoapServerHandle; +use Phpro\SoapClient\Soap\Engine\Engine; +use PhproTest\SoapClient\Functional\ExtSoap\AbstractSoapTestCase; class EnumTest extends AbstractSoapTestCase { - protected function configureServer(SoapServer $server) + /** + * @var string + */ + private $wsdl; + + /** + * @var ExtSoapDriver + */ + private $driver; + + /** + * @var ExtSoapServerHandle + */ + private $handler; + + protected function setUp() { - $server->setObject(new class() { - public function validate($input) + $this->wsdl = FIXTURE_DIR . '/wsdl/functional/enum.wsdl'; + $this->driver = $this->configureSoapDriver($this->wsdl, []); + $this->handler = $this->configureServer( + $this->wsdl, + [], + new class() { - return $input; + public function validate($input) + { + return $input; + } } - }); - } - - protected function getWsdl(): string - { - return FIXTURE_DIR . '/wsdl/functional/enum.wsdl'; - } - - protected function getSoapOptions(): array { - return $this->provideBasicWsdlOptions(); + ); } /** @test */ function it_does_not_register_a_type() { - $types = $this->client->getSoapTypes(); + $types = $this->driver->getMetadata()->getTypes(); $this->assertCount(0, $types); } @@ -42,11 +57,13 @@ function it_does_not_register_a_type() function it_knows_how_to_add_enums() { $input = 'Home'; - $response = (string) $this->client->validate($input); - $this->assertEquals($input, $response); + $engine = new Engine($this->driver, $this->handler); + $response = (string) $engine->request('validate', [$input]); + $lastRequestInfo = $this->handler->collectLastRequestInfo(); - $this->assertContains('Home', $this->client->__getLastRequest()); - $this->assertContains('Home', $this->client->__getLastResponse()); + $this->assertEquals($input, $response); + $this->assertContains('Home', $lastRequestInfo->getLastRequest()); + $this->assertContains('Home', $lastRequestInfo->getLastResponse()); } /** @@ -56,10 +73,12 @@ function it_knows_how_to_add_enums() function it_does_not_validate_enums() { $input = 'INVALID'; - $this->client->validate($input); + $engine = new Engine($this->driver, $this->handler); + $engine->request('validate', [$input]); + $lastRequestInfo = $this->handler->collectLastRequestInfo(); - $this->assertContains('INVALID', $this->client->__getLastRequest()); - $this->assertContains('INVALID', $this->client->__getLastResponse()); + $this->assertContains('INVALID', $lastRequestInfo->getLastRequest()); + $this->assertContains('INVALID', $lastRequestInfo->getLastResponse()); } /** @@ -69,10 +88,12 @@ function it_does_not_validate_enums() function it_does_not_validate_enum_types() { $input = 123; - $this->client->validate($input); + $engine = new Engine($this->driver, $this->handler); + $engine->request('validate', [$input]); + $lastRequestInfo = $this->handler->collectLastRequestInfo(); - $this->assertContains('123', $this->client->__getLastRequest()); - $this->assertContains('123', $this->client->__getLastResponse()); + $this->assertContains('123', $lastRequestInfo->getLastRequest()); + $this->assertContains('123', $lastRequestInfo->getLastResponse()); } /** @@ -81,7 +102,7 @@ function it_does_not_validate_enum_types() */ function it_can_be_transformed_with_type_map() { - $this->configureSoapClient($this->getWsdl(), $this->provideBasicWsdlOptions([ + $this->driver = $this->configureSoapDriver($this->wsdl, [ 'typemap' => [ [ 'type_name' => 'PhoneTypeEnum', @@ -97,18 +118,20 @@ function it_can_be_transformed_with_type_map() return $this->createEnum($doc->textContent); }, 'to_xml' => function($enum) { - return sprintf('%s', $enum->__toString()); + return sprintf('%s', $enum); }, - ], - ], - ])); + ] + ] + ]); + $engine = new Engine($this->driver, $this->handler); $input = $this->createEnum('Home'); - $response = $this->client->validate($input); + $response = $engine->request('validate', [$input]); + $lastRequestInfo = $this->handler->collectLastRequestInfo(); $this->assertEquals($input, $response); - $this->assertContains('Home', $this->client->__getLastRequest()); - $this->assertContains('Home', $this->client->__getLastResponse()); + $this->assertContains('Home', $lastRequestInfo->getLastRequest()); + $this->assertContains('Home', $lastRequestInfo->getLastResponse()); } private function createEnum(string $value) { diff --git a/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/AbusedClientTest.php b/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/AbusedClientTest.php new file mode 100644 index 00000000..94c38d40 --- /dev/null +++ b/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/AbusedClientTest.php @@ -0,0 +1,119 @@ +client = new AbusedClient($wsdl, $options); + } + + /** @test */ + function it_can_encode_with_typemap() + { + $this->configureForWsdl(FIXTURE_DIR.'/wsdl/functional/string.wsdl', [ + 'typemap' => $this->generateHelloTypeMap('string'), + ]); + + $this->client->__soapCall('validate', ['goodbye']); + $encoded = $this->client->collectRequest(); + + $this->assertContains('hello', $encoded->getRequest()); + $this->assertNotContains('goodbye', $encoded->getRequest()); + } + + /** @test */ + function it_can_decode_with_typemap() + { + $this->configureForWsdl(FIXTURE_DIR.'/wsdl/functional/string.wsdl', [ + 'typemap' => $this->generateHelloTypeMap('string'), + ]); + + $this->client->registerResponse($this->generateSoapResponse(<< + goodbye + +EOB + )); + + $metadata = new ExtSoapMetadata($this->client); + $payload = (new DummyMethodArgumentsGenerator($metadata))->generateForSoapCall('validate'); + $decoded = $this->client->__soapCall('validate', $payload); + + $this->assertSame('hello', $decoded); + } + + /** @test */ + function it_can_decode_with_more_complex_types() + { + $this->configureForWsdl(FIXTURE_DIR.'/wsdl/functional/string.wsdl', [ + 'typemap' => $this->generateHelloTypeMap('string'), + ]); + + $this->client->registerResponse($this->generateSoapResponse(<< + + goodbye + + +EOB + )); + + $metadata = new ExtSoapMetadata($this->client); + $payload = (new DummyMethodArgumentsGenerator($metadata))->generateForSoapCall('validate'); + $decoded = $this->client->__soapCall('validate', $payload); + + $this->assertSame('hello', $decoded); + } + + private function generateSoapResponse(string $body): SoapResponse + { + $response = << + + $body + + +EORESPONSE; + + return new SoapResponse($response); + } + + private function generateHelloTypeMap(string $xsdType): array + { + return [ + [ + 'type_name' => $xsdType, + 'type_ns' => 'http://www.w3.org/2001/XMLSchema', + 'from_xml' => function () { + return 'hello'; + }, + 'to_xml' => function () { + return 'hello'; + }, + ], + ]; + } +} diff --git a/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/Engine/ExtSoapClientEngineTest.php b/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/Engine/ExtSoapClientEngineTest.php new file mode 100644 index 00000000..b2472b47 --- /dev/null +++ b/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/Engine/ExtSoapClientEngineTest.php @@ -0,0 +1,67 @@ +engine; + } + + protected function getHandler(): HandlerInterface + { + return $this->handler; + } + + protected function getVcrPrefix(): string + { + return 'ext-soap-with-client-handle-'; + } + + protected function skipVcr(): bool + { + return false; + } + + protected function skipLastHeadersCheck(): bool + { + return true; + } + + protected function configureForWsdl(string $wsdl) + { + $this->engine = new Engine( + ExtSoapDriver::createFromClient( + $client = AbusedClient::createFromOptions( + ExtSoapOptions::defaults($wsdl, [ + 'cache_wsdl' => WSDL_CACHE_NONE, + 'soap_version' => SOAP_1_2, + ]) + ) + ), + $this->handler = new ExtSoapClientHandle($client) + ); + } +} diff --git a/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/Engine/ExtSoapHttPlugEngineTest.php b/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/Engine/ExtSoapHttPlugEngineTest.php new file mode 100644 index 00000000..8dd4b12e --- /dev/null +++ b/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/Engine/ExtSoapHttPlugEngineTest.php @@ -0,0 +1,70 @@ +engine; + } + + protected function getHandler(): HandlerInterface + { + return $this->handler; + } + + protected function getVcrPrefix(): string + { + return 'ext-soap-with-httplug-handle-'; + } + + protected function skipVcr(): bool + { + return false; + } + + protected function skipLastHeadersCheck(): bool + { + return false; + } + + protected function configureForWsdl(string $wsdl) + { + $this->engine = new Engine( + ExtSoapDriver::createFromClient( + $client = AbusedClient::createFromOptions( + ExtSoapOptions::defaults($wsdl, [ + 'cache_wsdl' => WSDL_CACHE_NONE, + 'soap_version' => SOAP_1_2, + ]) + ) + ), + $this->handler = HttPlugHandle::createForClient( + Client::createWithConfig(['headers' => ['User-Agent' => 'testing/1.0']]) + ) + ); + } +} diff --git a/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/Engine/ExtSoapServerEngineTest.php b/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/Engine/ExtSoapServerEngineTest.php new file mode 100644 index 00000000..7e2f514f --- /dev/null +++ b/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/Engine/ExtSoapServerEngineTest.php @@ -0,0 +1,84 @@ +engine; + } + + protected function getHandler(): HandlerInterface + { + return $this->handler; + } + + protected function getVcrPrefix(): string + { + return 'ext-soap-with-server-handle-'; + } + + protected function skipVcr(): bool + { + return true; + } + + protected function skipLastHeadersCheck(): bool + { + return true; + } + + protected function configureForWsdl(string $wsdl) + { + $this->engine = new Engine( + ExtSoapDriver::createFromClient( + $client = AbusedClient::createFromOptions( + ExtSoapOptions::defaults($wsdl, [ + 'cache_wsdl' => WSDL_CACHE_NONE, + 'soap_version' => SOAP_1_2, + ]) + ) + ), + $this->handler = new ExtSoapServerHandle($this->mockServerForWsdl($wsdl)) + ); + } + + private function mockServerForWsdl(string $wsdl): \SoapServer + { + $server = new \SoapServer($wsdl, ['soap_version' => SOAP_1_2]); + $server->setObject(new class() { + public function GetCityWeatherByZIP($zip) { + return [ + 'GetCityWeatherByZIPResult' => [ + 'WeatherID' => 1, + 'Success' => true, + ] + ]; + } + }); + + return $server; + } +} diff --git a/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/ExtSoapDecoderTest.php b/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/ExtSoapDecoderTest.php new file mode 100644 index 00000000..7afd21a7 --- /dev/null +++ b/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/ExtSoapDecoderTest.php @@ -0,0 +1,43 @@ +decoder; + } + + protected function configureForWsdl(string $wsdl) + { + $this->decoder = new ExtSoapDecoder( + $client = AbusedClient::createFromOptions( + ExtSoapOptions::defaults($wsdl, []) + ->disableWsdlCache() + ->withClassMap(new ClassMapCollection([ + new ClassMap('MappedValidateResponse', ValidateResponse::class), + ])) + ), + new DummyMethodArgumentsGenerator(new ExtSoapMetadata($client)) + ); + } +} diff --git a/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/ExtSoapEncoderTest.php b/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/ExtSoapEncoderTest.php new file mode 100644 index 00000000..3c7e0737 --- /dev/null +++ b/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/ExtSoapEncoderTest.php @@ -0,0 +1,40 @@ +encoder; + } + + protected function configureForWsdl(string $wsdl) + { + $this->encoder = new ExtSoapEncoder( + $client = AbusedClient::createFromOptions( + ExtSoapOptions::defaults($wsdl) + ->disableWsdlCache() + ->withClassMap(new ClassMapCollection([ + new ClassMap('MappedValidateRequest', ValidateRequest::class), + ])) + ) + ); + } +} diff --git a/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/ExtSoapMetadataProviderTest.php b/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/ExtSoapMetadataProviderTest.php new file mode 100644 index 00000000..20b10e1a --- /dev/null +++ b/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/ExtSoapMetadataProviderTest.php @@ -0,0 +1,39 @@ +metadataProvider; + } + + protected function configureForWsdl(string $wsdl) + { + $this->metadataProvider = ExtSoapDriver::createFromClient( + $this->client = AbusedClient::createFromOptions( + ExtSoapOptions::defaults($wsdl) + ->disableWsdlCache() + ) + ); + } +} diff --git a/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/ExtSoapOptionsTest.php b/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/ExtSoapOptionsTest.php new file mode 100644 index 00000000..f5acd667 --- /dev/null +++ b/test/PhproTest/SoapClient/Integration/Soap/Driver/ExtSoap/ExtSoapOptionsTest.php @@ -0,0 +1,248 @@ +wsdl = FIXTURE_DIR.'/wsdl/functional/string.wsdl'; + $this->resolver = ExtSoapOptionsResolverFactory::createForWsdl($this->wsdl); + } + + /** @test */ + function it_is_possible_to_construct_from_empty_state() + { + $options = new ExtSoapOptions($this->wsdl, $expectedOptions = ['trace' => true]); + $this->assertSame($this->wsdl, $options->getWsdl()); + $this->assertSame($expectedOptions, $options->getOptions()); + } + + /** @test */ + function it_contains_a_wsdl() + { + $wsdl = ExtSoapOptions::defaults($this->wsdl)->getWsdl(); + $this->assertSame($wsdl, $this->wsdl); + } + + /** @test */ + function it_can_resolve_defaults() + { + $options = $this->resolver->resolve( + ExtSoapOptions::defaults($this->wsdl, [])->getOptions() + ); + + $this->assertTrue($options['trace']); + $this->assertTrue($options['exceptions']); + $this->assertSame(WSDL_CACHE_DISK, $options['cache_wsdl']); + $this->assertSame(SOAP_SINGLE_ELEMENT_ARRAYS, $options['features']); + $this->assertInternalType('array', $options['typemap']); + } + + /** @test */ + function it_is_possible_to_overwrite_defaults() + { + $options = $this->resolver->resolve( + ExtSoapOptions::defaults($this->wsdl, [ + 'trace' => false, + 'proxy_host' => $proxyHost = 'http://localhost', + ])->getOptions() + ); + + $this->assertFalse($options['trace']); + $this->assertTrue($options['exceptions']); + $this->assertSame($proxyHost, $options['proxy_host']); + } + + /** @test */ + function it_is_possible_to_attach_a_wsdl_provider() + { + $wsdlProvider = $this->prophesize(WsdlProviderInterface::class); + $wsdlProvider->provide($this->wsdl)->willReturn($newWsdl = 'new.wsdl'); + $options = ExtSoapOptions::defaults($this->wsdl, []) + ->withWsdlProvider($wsdlProvider->reveal()); + + $this->assertSame($newWsdl, $options->getWsdl()); + } + + /** @test */ + function it_is_possible_to_disable_wsdl_cache() + { + $options = $this->resolver->resolve( + ExtSoapOptions::defaults($this->wsdl)->disableWsdlCache()->getOptions() + ); + + $this->assertSame(WSDL_CACHE_NONE, $options['cache_wsdl']); + } + + /** @test */ + function it_contains_a_default_type_map() + { + $options = ExtSoapOptions::defaults($this->wsdl); + + $typeMap = $options->getTypeMap(); + $this->assertInstanceOf(TypeConverter\TypeConverterCollection::class, $typeMap); + $this->assertCount(4, $typeMap->getIterator()); + + $resolved = $this->resolver->resolve($options->getOptions()); + $this->assertInternalType('array', $resolved['typemap']); + $this->assertCount(4, $resolved['typemap']); + $this->assertSame('dateTime', $resolved['typemap'][0]['type_name']); + $this->assertSame('date', $resolved['typemap'][1]['type_name']); + $this->assertSame('decimal', $resolved['typemap'][2]['type_name']); + $this->assertSame('double', $resolved['typemap'][3]['type_name']); + } + + /** @test */ + function it_is_possible_to_replace_the_type_map() + { + $options = ExtSoapOptions::defaults($this->wsdl) + ->withTypeMap($typeMap = new TypeConverter\TypeConverterCollection()); + + $this->assertSame($typeMap, $options->getTypeMap()); + + $resolved = $this->resolver->resolve($options->getOptions()); + $this->assertInternalType('array', $resolved['typemap']); + $this->assertCount(0, $resolved['typemap']); + } + + /** @test */ + function it_is_possible_to_use_regular_type_map() + { + $options = ExtSoapOptions::defaults($this->wsdl, [ + 'typemap' => [ + [ + 'type_name' => $typeName = 'hello', + 'type_ns' => $typeNs = 'http://my-ns/xsd', + 'from_xml' => function ($input) { + return $input; + }, + 'to_xml' => function ($input) { + return ''.$input.''; + }, + ] + ] + ]); + + $resolved = $this->resolver->resolve($options->getOptions()); + $this->assertInternalType('array', $resolved['typemap']); + $this->assertCount(1, $resolved['typemap']); + $this->assertSame($typeName, $resolved['typemap'][0]['type_name']); + $this->assertSame($typeNs, $resolved['typemap'][0]['type_ns']); + + $this->expectException(UnexpectedConfigurationException::class); + $options->getTypeMap(); + } + + /** @test */ + function it_can_dynamically_add_a_default_clasmap() + { + $options = ExtSoapOptions::defaults($this->wsdl); + + $classMap = $options->getClassMap(); + $this->assertInstanceOf(ClassMapCollection::class, $classMap); + $this->assertCount(0, $classMap->getIterator()); + + $resolved = $this->resolver->resolve($options->getOptions()); + $this->assertInternalType('array', $resolved['classmap']); + $this->assertCount(0, $resolved['classmap']); + } + + /** @test */ + function it_is_possible_to_replace_the_class_map() + { + $options = ExtSoapOptions::defaults($this->wsdl) + ->withClassMap($classMap = new ClassMapCollection([ + new ClassMap('wsdlType', 'PhpClass'), + ])); + + $this->assertSame($classMap, $options->getClassMap()); + + $resolved = $this->resolver->resolve($options->getOptions()); + $this->assertInternalType('array', $resolved['classmap']); + $this->assertCount(1, $resolved['classmap']); + $this->assertSame('PhpClass', $resolved['classmap']['wsdlType']); + } + + /** @test */ + function it_is_possible_to_use_regular_class_map() + { + $options = ExtSoapOptions::defaults($this->wsdl, [ + 'classmap' => [ + 'wsdlType' => 'PhpClass', + ] + ]); + + $resolved = $this->resolver->resolve($options->getOptions()); + $this->assertInternalType('array', $resolved['classmap']); + $this->assertCount(1, $resolved['classmap']); + $this->assertSame('PhpClass', $resolved['classmap']['wsdlType']); + + $this->expectException(UnexpectedConfigurationException::class); + $options->getClassMap(); + } + + /** @test */ + function it_can_accept_all_knwon_options() + { + $options = $this->resolver->resolve( + (new ExtSoapOptions( + $this->wsdl, + $expectedOptions = [ + 'uri' => 'http://localhost', + 'location' => 'http://localhost', + 'soap_version' => SOAP_1_1, + 'login' => 'user', + 'password' => 'password', + 'authentication' => SOAP_AUTHENTICATION_BASIC, + 'proxy_host' => 'http://proxy', + 'proxy_port' => '8888', + 'proxy_login' => 'proxyuser', + 'proxy_password' => 'proxypass', + 'local_cert' => 'somecert.key', + 'passphrase' => 'sslpass', + 'compression' => SOAP_COMPRESSION_GZIP, + 'encoding' => 'utf-8', + 'trace' => true, + 'classmap' => [], + 'exceptions' => true, + 'connection_timeout' => 900, + 'default_socket_timeout' => 900, + 'typemap' => [], + 'cache_wsdl' => WSDL_CACHE_NONE, + 'user_agent' => 'My Super SoapClient', + 'stream_context' => stream_context_create(), + 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, + 'keep_alive' => false, + 'ssl_method' => SOAP_SSL_METHOD_SSLv23, + ] + ))->getOptions() + ); + + foreach ($options as $key => $option) { + $this->assertSame($expectedOptions[$key], $option); + } + } +} diff --git a/test/PhproTest/SoapClient/Integration/Soap/Engine/AbstractDecoderTest.php b/test/PhproTest/SoapClient/Integration/Soap/Engine/AbstractDecoderTest.php new file mode 100644 index 00000000..700887df --- /dev/null +++ b/test/PhproTest/SoapClient/Integration/Soap/Engine/AbstractDecoderTest.php @@ -0,0 +1,1218 @@ +configureForWsdl(FIXTURE_DIR . '/wsdl/functional/simpleContent.wsdl'); + $response = $this->createResponse(<< + 132 + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertEquals( + (object)([ + '_' => 132, + 'country' => 'BE', + ]), + $decoded + ); + } + + /** @test */ + public function it_handles_complex_types() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/complex-type-request-response.wsdl'); + $output = 'hello'; + $response = $this->createResponse(<< + + $output + + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertInstanceOf(\stdClass::class, $decoded); + $this->assertSame($output, $decoded->output); + } + + /** @test */ + public function it_handles_complex_types_with_classmap() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/complex-type-mapped-request-response.wsdl'); + $output = 'hello'; + $response = $this->createResponse(<< + + $output + + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertInstanceOf(ValidateResponse::class, $decoded); + $this->assertSame($output, $decoded->output); + } + + /** @test */ + public function it_handles_enum_types() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/enum.wsdl'); + $output = 'Home'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + public function it_handles_xml_entities() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/string.wsdl'); + $output = htmlspecialchars($expectedOutput = '<\'"ïnpüt"\'>', ENT_NOQUOTES); + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($expectedOutput, $decoded); + } + + /** @test */ + function it_decodes_null() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/guess.wsdl'); + $response = $this->createResponse(<< + + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame(null, $decoded); + } + + /** @test */ + function it_decodes_string() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/guess.wsdl'); + $output = 'string'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_long() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/guess.wsdl'); + $output = 132; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_double() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/guess.wsdl'); + $output = 132.12; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_false() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/guess.wsdl'); + $response = $this->createResponse(<< + false + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame(false, $decoded); + } + + /** @test */ + function it_decodes_true() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/guess.wsdl'); + $response = $this->createResponse(<< + true + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame(true, $decoded); + } + + /** @test */ + function it_decodes_xsd_string() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/string.wsdl'); + $output = 'output'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_boolean() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/boolean.wsdl'); + $response = $this->createResponse(<< + true + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame(true, $decoded); + } + + /** @test */ + function it_decodes_xsd_decimal() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/decimal.wsdl'); + $output = 12345.67890; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_float() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/float.wsdl'); + $output = 123.45; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_double() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/double.wsdl'); + $output = 123.45; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_long() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/long.wsdl'); + $output = 123; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_int() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/int.wsdl'); + $output = 123; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_short() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/short.wsdl'); + $output = 123; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_byte() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/byte.wsdl'); + $output = 123; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_nonpositive_integer() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/nonPositiveInteger.wsdl'); + $output = -123; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_positive_integer() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/positiveInteger.wsdl'); + $output = 123; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_nonnegative_integer() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/nonNegativeInteger.wsdl'); + $output = 123; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_negative_integer() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/negativeInteger.wsdl'); + $output = -123; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_unsigned_byte() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/unsignedByte.wsdl'); + $output = 123; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_unsigned_short() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/unsignedShort.wsdl'); + $output = 123; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_unsigned_int() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/unsignedInt.wsdl'); + $output = 123; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_unsigned_long() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/unsignedLong.wsdl'); + $output = 123; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_integer() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/integer.wsdl'); + $output = 123; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_datetime() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/datetime.wsdl'); + $output = '2018-01-25T21:32:52'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertInstanceOf(\DateTimeInterface::class, $decoded); + $this->assertSame($output, $decoded->format('Y-m-d\TH:i:s')); + } + + /** @test */ + function it_decodes_xsd_time() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/time.wsdl'); + $output = '21:32:52'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_date() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/date.wsdl'); + $output = '2019-01-25'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertInstanceOf(\DateTimeInterface::class, $decoded); + $this->assertSame($output, $decoded->format('Y-m-d')); + } + + /** @test */ + function it_decodes_xsd_gyearmonth() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/gYearMonth.wsdl'); + $output = '2019-01'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_gyear() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/gYear.wsdl'); + $output = '2019'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_gmonthday() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/gMonthDay.wsdl'); + $output = '--01-25'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_gday() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/gDay.wsdl'); + $output = '---25'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_gmonth() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/gMonth.wsdl'); + $output = '--01'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_duration() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/duration.wsdl'); + $output = 'PT2M10S'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_hexbinary() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/hexBinary.wsdl'); + $output = bin2hex($expectedOutput = 'decodedoutput'); + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + + $this->assertSame($expectedOutput, $decoded); + } + + /** @test */ + function it_decodes_base64binary() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/base64Binary.wsdl'); + $output = base64_encode($expectedOutput = 'decodedoutput'); + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + + $this->assertSame($expectedOutput, $decoded); + } + + /** @test */ + function it_decodes_xsd_any_type() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/any.wsdl'); + $output = '12243.223'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_any_uri() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/anyURI.wsdl'); + $output = 'http://www.w3.org/TR/xmlschema-0/'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_qname() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/qname.wsdl'); + $output = 'xsd:someElement'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_notation() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/notation.wsdl'); + $output = 'xsd:NOTATION'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_normalized_string() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/normalizedString.wsdl'); + $output = ' Being a Dog Is + a Full-Time Job'; + $expected = ' Being a Dog Is a Full-Time Job'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($expected, $decoded); + } + + /** @test */ + function it_decodes_xsd_token() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/token.wsdl'); + $output = ' Being a Dog Is + a Full-Time Job'; + $expected = 'Being a Dog Is a Full-Time Job'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($expected, $decoded); + } + + /** @test */ + function it_decodes_xsd_language() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/token.wsdl'); + $output = 'nl-BE'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_nmtoken() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/nmtoken.wsdl'); + $output = 'noSpaces-Or-SpecialChars-allowed-1234'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_nmtokens() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/nmtokens.wsdl'); + $output = 'token-1 token-2 token-3'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_name() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/name.wsdl'); + $output = 'Cannot-start-with-number-134'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_ncname() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/ncname.wsdl'); + $output = 'Cannot-contain-colon-134'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_ncnames() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/ncnames.wsdl'); + $output = 'Cannot-contain-colon-134 ncname2'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_id() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/id.wsdl'); + $output = 'IDField'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_idref() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/idref.wsdl'); + $output = 'IDField'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_idrefs() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/idrefs.wsdl'); + $output = 'IDField1 IDField2'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_entity() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/entity.wsdl'); + $output = 'Entity'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_entities() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/entities.wsdl'); + $output = 'Entity1 Entity2'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_soap_11_enc_object() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/soap11-enc-object.wsdl'); + $response = $this->createResponse(<< + + 50 + Description + + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertInstanceOf(\stdClass::class, $decoded); + $this->assertSame($decoded->Sku, 50); + $this->assertSame($decoded->Description, 'Description'); + } + + /** @test */ + function it_decodes_soap_11_enc_array() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/soap11-enc-array.wsdl'); + $response = $this->createResponse(<< + + string1 + string2 + + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertEquals(['string1', 'string2'], $decoded); + } + + /** @test */ + function it_decodes_soap_12_enc_object() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/soap12-enc-object.wsdl'); + $response = $this->createResponse(<< + + 50 + Description + + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertInstanceOf(\stdClass::class, $decoded); + $this->assertSame($decoded->Sku, 50); + $this->assertSame($decoded->Description, 'Description'); + } + + /** @test */ + function it_decodes_soap_12_enc_array() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/soap12-enc-array.wsdl'); + $response = $this->createResponse(<< + + string1 + string2 + + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertEquals(['string1', 'string2'], $decoded); + } + + /** @test */ + function it_decodes_apache_map_array() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/apache-map.wsdl'); + $response = $this->createResponse(<< + + + Key1 + Value1 + + + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertEquals(['Key1' => 'Value1'], $decoded); + } + + /** @test */ + function it_decodes_xsd_1999_string() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/1999string.wsdl'); + $output = 'output'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_1999_boolean() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/1999boolean.wsdl'); + $response = $this->createResponse(<< + true + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame(true, $decoded); + } + + /** @test */ + function it_decodes_xsd_1999_decimal() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/1999decimal.wsdl'); + $output = 20.2; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame((string) $output, $decoded); + } + + /** @test */ + function it_decodes_xsd_1999_float() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/1999float.wsdl'); + $output = 20.2; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_1999_double() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/1999double.wsdl'); + $output = 20.2; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_1999_long() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/1999long.wsdl'); + $output = 20; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_1999_int() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/1999int.wsdl'); + $output = 20; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_1999_short() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/1999short.wsdl'); + $output = 2; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_1999_byte() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/1999byte.wsdl'); + $output = 1; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + /** @test */ + function it_decodes_xsd_1999_timeinstant() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/1999timeinstant.wsdl'); + $output = '20190125T083100.001'; + $response = $this->createResponse(<< + $output + +EOB + ); + + $decoded = $this->getDecoder()->decode('validate', $response); + $this->assertSame($output, $decoded); + } + + protected function createResponse(string $applicationBodyXml): SoapResponse + { + return new SoapResponse(<< + + $applicationBodyXml + + +EOXML + ); + } +} diff --git a/test/PhproTest/SoapClient/Integration/Soap/Engine/AbstractEncoderTest.php b/test/PhproTest/SoapClient/Integration/Soap/Engine/AbstractEncoderTest.php new file mode 100644 index 00000000..2e7b3315 --- /dev/null +++ b/test/PhproTest/SoapClient/Integration/Soap/Engine/AbstractEncoderTest.php @@ -0,0 +1,1026 @@ +configureForWsdl(FIXTURE_DIR.'/wsdl/functional/simpleContent.wsdl'); + $input = ['_' => 132, 'country' => 'BE']; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals(132, $result->nodeValue); + $this->assertEquals('BE', $result->getAttribute('country')); + } + + /** @test */ + public function it_handles_complex_types() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/complex-type-request-response.wsdl'); + $input = (object)['input' => 'inputContent']; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/request/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input->input, $result->nodeValue); + } + + /** @test */ + public function it_handles_complex_types_with_classmap() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/complex-type-mapped-request-response.wsdl'); + $input = new ValidateRequest(); + $input->input = 'inputContent'; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/request/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input->input, $result->nodeValue); + } + + /** @test */ + public function it_handles_enum_types() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/enum.wsdl'); + $input = 'Home'; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + public function it_handles_xml_entities() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/string.wsdl'); + $input = '<\'"ïnpüt"\'>'; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertContains(htmlspecialchars($input, ENT_NOQUOTES), $encoded->getRequest()); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_null() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/guess.wsdl'); + $input = null; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_string() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/guess.wsdl'); + $input = 'hello'; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_long() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/guess.wsdl'); + $input = 132323; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_double() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/guess.wsdl'); + $input = 23.22; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_false() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/guess.wsdl'); + $input = false; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals('false', $result->nodeValue); + } + + /** @test */ + function it_encodes_true() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/guess.wsdl'); + $input = true; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals('true', $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_string() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/string.wsdl'); + + $encoded = $this->getEncoder()->encode($method = 'validate', ['input']); + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals('input', $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_boolean() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/boolean.wsdl'); + $input = true; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals('true', $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_decimal() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/decimal.wsdl'); + $input = 10.4; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/*[1]'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_float() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/float.wsdl'); + $input = 10.4; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_double() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/double.wsdl'); + $input = 10.4; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/*[1]'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_long() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/long.wsdl'); + $input = 2323232323; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_int() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/string.wsdl'); + + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 123]); + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_short() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/short.wsdl'); + + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 123]); + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_byte() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/byte.wsdl'); + + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 1]); + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_nonpositive_integer() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/nonPositiveInteger.wsdl'); + + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = -123]); + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_positive_integer() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/positiveInteger.wsdl'); + + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 123]); + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_nonnegative_integer() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/nonNegativeInteger.wsdl'); + + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 123]); + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_negative_integer() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/negativeInteger.wsdl'); + + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 123]); + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_unsigned_byte() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/unsignedByte.wsdl'); + + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 123]); + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_unsigned_short() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/unsignedShort.wsdl'); + + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 123]); + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_unsigned_int() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/unsignedInt.wsdl'); + + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 123]); + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_unsigned_long() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/unsignedLong.wsdl'); + + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 123]); + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_integer() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/integer.wsdl'); + + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 123]); + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_datetime() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/datetime.wsdl'); + $input = new \DateTimeImmutable('2019-01-25 11:30:00'); + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/*[1]'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input->format('Y-m-d\TH:i:sP'), $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_time() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/time.wsdl'); + + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = '11:30']); + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_date() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/date.wsdl'); + $input = new \DateTimeImmutable('2019-01-25'); + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/*[1]'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input->format('Y-m-d'), $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_gyearmonth() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/gYearMonth.wsdl'); + + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = '2019-01']); + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_gyear() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/gYear.wsdl'); + + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = '2019']); + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_gmonthday() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/gYearMonth.wsdl'); + + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = '--01-25']); + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_gday() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/gDay.wsdl'); + + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = '---25']); + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_gmonth() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/gMonth.wsdl'); + + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = '--01']); + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_duration() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/duration.wsdl'); + + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 'PT2M10S']); + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_hexbinary() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/hexBinary.wsdl'); + $input = 'myinput'; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals(strtoupper(bin2hex($input)), $result->nodeValue); + } + + /** @test */ + function it_encodes_base64binary() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/base64Binary.wsdl'); + $input = 'myinput'; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals(base64_encode($input), $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_any_type_by_guessing() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/any.wsdl'); + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 12243.223]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_any_uri() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/anyURI.wsdl'); + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 'http://www.w3.org/TR/xmlschema-0/']); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_qname() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/qname.wsdl'); + $input = 'xsd:someElement'; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_notation() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/notation.wsdl'); + $input = 'xsd:NOTATION'; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_normalized_string() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/normalizedString.wsdl'); + $input = ' Being a Dog Is + a Full-Time Job'; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_token() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/token.wsdl'); + $input = ' Being a Dog Is + a Full-Time Job'; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_language() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/language.wsdl'); + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 'nl-BE']); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_nmtoken() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/nmtoken.wsdl'); + $input = 'noSpaces-Or-SpecialChars-allowed-1234'; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_nmtokens() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/nmtokens.wsdl'); + $input = 'token-1 token-2 token-3'; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_name() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/name.wsdl'); + $input = 'Cannot-start-with-number-134'; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_ncname() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/ncname.wsdl'); + $input = 'Cannot-contain-colon-134'; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_id() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/id.wsdl'); + $input = 'IDField'; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_idref() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/idref.wsdl'); + $input = 'IDField'; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_idrefs() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/idrefs.wsdl'); + $input = 'IDField1 IDField2'; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_entity() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/entity.wsdl'); + $input = 'Entity'; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_entities() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/entities.wsdl'); + $input = 'Entity'; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_soap_11_enc_object() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/soap11-enc-object.wsdl'); + $input = (object) ['Sku' => 50, 'Description' => 'Description']; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $this->assertSoapRequest($encoded, $xml, $method); + + $sku = $this->runSingleElementXpathOnBody($xml, './application:validate/request/Sku'); + $this->assertEquals($input->Sku, $sku->nodeValue); + $this->assertEquals('xsd:int', $sku->getAttributeNS(self::XML_XSI_NS, 'type')); + + $description = $this->runSingleElementXpathOnBody($xml, './application:validate/request/Description'); + $this->assertEquals($input->Description, $description->nodeValue); + $this->assertEquals('xsd:string', $description->getAttributeNS(self::XML_XSI_NS, 'type')); + } + + /** @test */ + function it_encodes_soap_11_enc_array() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/soap11-enc-array.wsdl'); + $input = ['item1', 'item2']; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $this->assertSoapRequest($encoded, $xml, $method); + + $item1 = $this->runSingleElementXpathOnBody($xml, './application:validate/request/item[1]'); + $this->assertEquals($input[0], $item1->nodeValue); + $this->assertEquals('xsd:string', $item1->getAttributeNS(self::XML_XSI_NS, 'type')); + + $item2 = $this->runSingleElementXpathOnBody($xml, './application:validate/request/item[2]'); + $this->assertEquals($input[1], $item2->nodeValue); + $this->assertEquals('xsd:string', $item2->getAttributeNS(self::XML_XSI_NS, 'type')); + } + + /** @test */ + function it_encodes_soap_12_enc_object() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/soap12-enc-object.wsdl'); + $input = (object) ['Sku' => 50, 'Description' => 'Description']; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $this->assertSoapRequest($encoded, $xml, $method); + + $sku = $this->runSingleElementXpathOnBody($xml, './application:validate/request/Sku'); + $this->assertEquals($input->Sku, $sku->nodeValue); + $this->assertEquals('xsd:int', $sku->getAttributeNS(self::XML_XSI_NS, 'type')); + + $description = $this->runSingleElementXpathOnBody($xml, './application:validate/request/Description'); + $this->assertEquals($input->Description, $description->nodeValue); + $this->assertEquals('xsd:string', $description->getAttributeNS(self::XML_XSI_NS, 'type')); + } + + /** @test */ + function it_encodes_soap_12_enc_array() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/soap12-enc-array.wsdl'); + $input = ['item1', 'item2']; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $this->assertSoapRequest($encoded, $xml, $method); + + $item1 = $this->runSingleElementXpathOnBody($xml, './application:validate/request/item[1]'); + $this->assertEquals($input[0], $item1->nodeValue); + $this->assertEquals('xsd:string', $item1->getAttributeNS(self::XML_XSI_NS, 'type')); + + $item2 = $this->runSingleElementXpathOnBody($xml, './application:validate/request/item[2]'); + $this->assertEquals($input[1], $item2->nodeValue); + $this->assertEquals('xsd:string', $item2->getAttributeNS(self::XML_XSI_NS, 'type')); + } + + /** @test */ + function it_encodes_apache_map_array() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/apache-map.wsdl'); + $input = ['key1' => 'item1']; + $encoded = $this->getEncoder()->encode($method = 'validate', [$input]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $this->assertSoapRequest($encoded, $xml, $method); + + $requestItem = $this->runSingleElementXpathOnBody($xml, './application:validate/request'); + $this->assertContains(':Map', $requestItem->getAttributeNS(self::XML_XSI_NS, 'type')); + + $item1Key = $this->runSingleElementXpathOnBody($xml, './application:validate/request/item[1]/key'); + $this->assertEquals('key1', $item1Key->nodeValue); + $this->assertEquals('xsd:string', $item1Key->getAttributeNS(self::XML_XSI_NS, 'type')); + + $item1Value = $this->runSingleElementXpathOnBody($xml, './application:validate/request/item[1]/value'); + $this->assertEquals($input['key1'], $item1Value->nodeValue); + $this->assertEquals('xsd:string', $item1Value->getAttributeNS(self::XML_XSI_NS, 'type')); + } + + /** @test */ + function it_encodes_xsd_1999_string() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/1999string.wsdl'); + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 'string']); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_1999_boolean() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/1999boolean.wsdl'); + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = true]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals('true', $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_1999_decimal() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/1999decimal.wsdl'); + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 10.23]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_1999_float() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/1999float.wsdl'); + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 10.23]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_1999_double() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/1999double.wsdl'); + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 10.23]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_1999_long() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/1999long.wsdl'); + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 1023]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_1999_int() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/1999int.wsdl'); + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 1023]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_1999_short() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/1999short.wsdl'); + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 1023]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_1999_byte() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/1999byte.wsdl'); + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = 1]); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** @test */ + function it_encodes_xsd_1999_timeinstant() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/1999timeinstant.wsdl'); + $encoded = $this->getEncoder()->encode($method = 'validate', [$input = '20190125T083100.001']); + + $xml = SoapXml::fromString($encoded->getRequest()); + $result = $this->runSingleElementXpathOnBody($xml, './application:validate/input'); + + $this->assertSoapRequest($encoded, $xml, $method); + $this->assertEquals($input, $result->nodeValue); + } + + /** + * we make some assumptions in this method: + * - Location = body namespace + * - action = body namespace/Method + * - No one way configured + */ + protected function assertSoapRequest(SoapRequest $request, SoapXml $xml, string $method) + { + $bodyNamespace = $xml->detectBodyContentsNamespace(); + $this->assertEquals($bodyNamespace, $request->getLocation()); + $this->assertEquals(rtrim($bodyNamespace, '/').'/'.$method, $request->getAction()); + $this->assertTrue($request->isSOAP11() || $request->isSOAP12()); + $this->assertEquals(0, $request->getOneWay()); + } +} diff --git a/test/PhproTest/SoapClient/Integration/Soap/Engine/AbstractEngineTest.php b/test/PhproTest/SoapClient/Integration/Soap/Engine/AbstractEngineTest.php new file mode 100644 index 00000000..c08da1fc --- /dev/null +++ b/test/PhproTest/SoapClient/Integration/Soap/Engine/AbstractEngineTest.php @@ -0,0 +1,93 @@ +configureForWsdl(FIXTURE_DIR . '/wsdl/weather-ws.wsdl'); + $this->runWithCasette('get-city-weather-by-zip-10013.yml', function() { + $result = $this->getEngine()->request('GetCityWeatherByZIP', [['ZIP' => '10013']]); + $this->assertTrue($result->GetCityWeatherByZIPResult->Success); + }); + } + + /** + * @test + * @runInSeparateProcess + */ + function it_should_know_the_last_request_and_response() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/weather-ws.wsdl'); + $this->runWithCasette('get-city-weather-by-zip-10013.yml', function() { + $handler = $this->getHandler(); + $lastInfo = $handler->collectLastRequestInfo(); + $this->assertEquals(0, strlen($lastInfo->getLastRequest())); + $this->assertEquals(0, strlen($lastInfo->getLastResponse())); + if (!$this->skipLastHeadersCheck()) { + $this->assertEquals(0, strlen($lastInfo->getLastRequestHeaders())); + $this->assertEquals(0, strlen($lastInfo->getLastResponseHeaders())); + } + + $result = $this->getEngine()->request('GetCityWeatherByZIP', [['ZIP' => '10013']]); + + $lastInfo = $handler->collectLastRequestInfo(); + $this->assertGreaterThan(0, strlen($lastInfo->getLastRequest())); + $this->assertGreaterThan(0, strlen($lastInfo->getLastResponse())); + + + if (!$this->skipLastHeadersCheck()) { + $this->assertGreaterThan(0, strlen($lastInfo->getLastRequestHeaders())); + $this->assertGreaterThan(0, strlen($lastInfo->getLastResponseHeaders())); + } + + // Try parsing xml + $request = SoapXml::fromString($lastInfo->getLastRequest()); + $this->assertEquals($request->getEnvelope(), $request->getRootElement()); + $response = SoapXml::fromString($lastInfo->getLastRequest()); + $this->assertEquals($request->getEnvelope(), $response->getRootElement()); + }); + } + + private function runWithCasette(string $cassete, callable $test) + { + if ($this->skipVcr()) { + $test(); + return; + } + + try { + VCR::insertCassette($this->getVcrPrefix().$cassete); + $test(); + } finally { + Vcr::eject(); + } + } +} diff --git a/test/PhproTest/SoapClient/Integration/Soap/Engine/AbstractIntegrationTest.php b/test/PhproTest/SoapClient/Integration/Soap/Engine/AbstractIntegrationTest.php new file mode 100644 index 00000000..97b0fdbb --- /dev/null +++ b/test/PhproTest/SoapClient/Integration/Soap/Engine/AbstractIntegrationTest.php @@ -0,0 +1,31 @@ +xpath($xpath, $xml->getBody()); + $this->assertGreaterThan(0, $results->length); + + return $results; + } + + protected function runSingleElementXpathOnBody(SoapXml $xml, string $xpath): DOMElement + { + $results = $xml->xpath($xpath, $xml->getBody()); + $this->assertEquals(1, $results->length); + + return $results->item(0); + } +} diff --git a/test/PhproTest/SoapClient/Integration/Soap/Engine/AbstractMetadataProviderTest.php b/test/PhproTest/SoapClient/Integration/Soap/Engine/AbstractMetadataProviderTest.php new file mode 100644 index 00000000..c91a11b5 --- /dev/null +++ b/test/PhproTest/SoapClient/Integration/Soap/Engine/AbstractMetadataProviderTest.php @@ -0,0 +1,226 @@ +configureForWsdl(FIXTURE_DIR . '/wsdl/functional/string.wsdl'); + + $metadata = $this->getMetadataProvider()->getMetadata(); + $methods = $metadata->getMethods(); + + $this->assertCount(1, $methods); + $this->assertMethodExists( + $methods, + 'validate', + [ + new Parameter('input', XsdType::create('string')) + ], + XsdType::create('string') + ); + } + + /** @test */ + function it_can_load_wsdl_method_with_multiple_response_arguments() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/multiArgumentResponse.wsdl'); + + $metadata = $this->getMetadataProvider()->getMetadata(); + $methods = $metadata->getMethods(); + + $this->assertCount(1, $methods); + $this->assertMethodExists( + $methods, + 'validate', + [ + new Parameter('input', XsdType::create('string')) + ], + XsdType::create('array') + ); + } + + /** @test */ + function it_can_load_union_types_in_methods() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/union.wsdl'); + + $metadata = $this->getMetadataProvider()->getMetadata(); + $methods = $metadata->getMethods(); + + $jeansType = XsdType::create('jeansSize') + ->withBaseType('anyType') + ->withMemberTypes(['sizebyno', 'sizebystring']); + + $this->assertCount(1, $methods); + $this->assertMethodExists( + $methods, + 'validate', + [ + new Parameter('input', $jeansType) + ], + $jeansType + ); + } + + /** @test */ + function it_can_load_list_types_in_methods() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/list.wsdl'); + + $metadata = $this->getMetadataProvider()->getMetadata(); + $methods = $metadata->getMethods(); + + $listType = XsdType::create('valuelist') + ->withBaseType('array') + ->withMemberTypes(['integer']); + + $this->assertCount(1, $methods); + $this->assertMethodExists( + $methods, + 'validate', + [ + new Parameter('input', $listType) + ], + $listType + ); + } + + /** @test */ + function it_can_load_simple_content_types() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/simpleContent.wsdl'); + + $metadata = $this->getMetadataProvider()->getMetadata(); + $types = $metadata->getTypes(); + + $this->assertCount(1, $types); + $this->assertTypeExists( + $types, + XsdType::create('SimpleContent'), + [ + new Property('_', XsdType::create('integer')), + new Property('country', XsdType::create('string')), + ] + ); + } + + /** @test */ + function it_can_load_complex_types() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/complex-type-request-response.wsdl'); + + $metadata = $this->getMetadataProvider()->getMetadata(); + $types = $metadata->getTypes(); + + $this->assertCount(2, $types); + $this->assertTypeExists( + $types, + XsdType::create('ValidateRequest'), + [ + new Property('input', XsdType::create('string')) + ] + ); + $this->assertTypeExists( + $types, + XsdType::create('ValidateResponse'), + [ + new Property('output', XsdType::create('string')) + ] + ); + } + + /** @test */ + function it_can_load_union_types() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/union.wsdl'); + + $metadata = $this->getMetadataProvider()->getMetadata(); + $types = $metadata->getTypes(); + + $jeansType = XsdType::create('jeansSize') + ->withBaseType('anyType') + ->withMemberTypes(['sizebyno', 'sizebystring']); + + $this->assertCount(1, $types); + $this->assertTypeExists( + $types, + XsdType::create('jeansSizeContainer'), + [ + new Property('jeansSize', $jeansType) + ] + ); + } + + /** @test */ + function it_can_load_list_types() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/list.wsdl'); + + $metadata = $this->getMetadataProvider()->getMetadata(); + $types = $metadata->getTypes(); + + $listType = XsdType::create('valuelist') + ->withBaseType('array') + ->withMemberTypes(['integer']); + + $this->assertCount(1, $types); + $this->assertTypeExists( + $types, + XsdType::create('valuelistContainer'), + [ + new Property('valuelist', $listType) + ] + ); + } + + /** @test */ + function it_can_handle_duplicate_type_declarations() + { + $this->configureForWsdl(FIXTURE_DIR . '/wsdl/functional/duplicate-typenames.wsdl'); + + $metadata = $this->getMetadataProvider()->getMetadata(); + $types = $metadata->getTypes(); + + $this->assertCount(2, $types); + + $type1 = $types->getIterator()[1]; + $this->assertSame('Store', $type1->getName()); + $this->assertEquals(XsdType::create('Store'), $type1->getXsdType()); + $this->assertEquals([new Property('Attribute2', XsdType::create('string'))], $type1->getProperties()); + + $type2 = $types->getIterator()[1]; + $this->assertSame('Store', $type2->getName()); + $this->assertEquals(XsdType::create('Store'), $type2->getXsdType()); + $this->assertEquals([new Property('Attribute2', XsdType::create('string'))], $type2->getProperties()); + } + + private function assertMethodExists(MethodCollection $methods, string $name, array $parameters, XsdType $returnType) + { + $method = $methods->fetchOneByName($name); + $this->assertSame($name, $method->getName()); + $this->assertEquals($parameters, $method->getParameters()); + $this->assertEquals($returnType, $method->getReturnType()); + } + + private function assertTypeExists(TypeCollection $types, XsdType $xsdType, array $properties) + { + $type = $types->fetchOneByName($xsdType->getName()); + $this->assertSame($xsdType->getName(), $type->getName()); + $this->assertEquals($xsdType->getName(), $type->getXsdType()); + $this->assertEquals($properties, $type->getProperties()); + } +} diff --git a/test/PhproTest/SoapClient/Integration/Soap/HttPlugSoapClientTest.php b/test/PhproTest/SoapClient/Integration/Soap/HttPlugSoapClientTest.php deleted file mode 100644 index f405e924..00000000 --- a/test/PhproTest/SoapClient/Integration/Soap/HttPlugSoapClientTest.php +++ /dev/null @@ -1,65 +0,0 @@ - ['User-Agent' => 'testing/1.0']]); - $this->client = new PhproSoapClient(self::CDYNE_WSDL, ['soap_version' => SOAP_1_2]); - $this->client->setHandler(HttPlugHandle::createForClient($httpClient)); - } - - /** - * @test - * @vcr guzzle-get-city-weather-by-zip-10013.yml - * - * Note: this method will throw Exceptions if VCR can't take over the configured SoapClient. - */ - function it_should_be_possible_to_hook_php_vcr_for_testing() - { - $result = $this->client->GetCityWeatherByZIP(['ZIP' => '10013']); - $this->assertTrue($result->GetCityWeatherByZIPResult->Success); - } - - /** - * @test - * @vcr guzzle-get-city-weather-by-zip-10013.yml - */ - function it_should_know_the_last_request_and_response() - { - $this->assertEquals(0, strlen($this->client->__getLastRequest())); - $this->assertEquals(0, strlen($this->client->__getLastResponse())); - $this->assertEquals(0, strlen($this->client->__getLastRequestHeaders())); - $this->assertEquals(0, strlen($this->client->__getLastResponseHeaders())); - $this->client->GetCityWeatherByZIP(['ZIP' => '10013']); - $this->assertGreaterThan(0, strlen($this->client->__getLastRequest())); - $this->assertGreaterThan(0, strlen($this->client->__getLastResponse())); - $this->assertGreaterThan(0, strlen($this->client->__getLastRequestHeaders())); - $this->assertGreaterThan(0, strlen($this->client->__getLastResponseHeaders())); - } -} diff --git a/test/PhproTest/SoapClient/Integration/Soap/LocalSoapServerClientTest.php b/test/PhproTest/SoapClient/Integration/Soap/LocalSoapServerClientTest.php deleted file mode 100644 index 92821064..00000000 --- a/test/PhproTest/SoapClient/Integration/Soap/LocalSoapServerClientTest.php +++ /dev/null @@ -1,75 +0,0 @@ -server = new \SoapServer(self::CDYNE_WSDL, ['soap_version' => SOAP_1_2]); - $this->client = new PhproSoapClient(self::CDYNE_WSDL, ['soap_version' => SOAP_1_2]); - $this->client->setHandler(new LocalSoapServerHandle($this->server)); - - $this->server->setObject(new class() { - public function GetCityWeatherByZIP($zip) { - return [ - 'GetCityWeatherByZIPResult' => [ - 'WeatherID' => 1, - 'Success' => true, - ] - ]; - } - }); - } - - /** - * @test - * @@runInSeparateProcess - */ - function it_should_run_through_soap_server() - { - $result = $this->client->GetCityWeatherByZIP(['ZIP' => '10013']); - $this->assertTrue($result->GetCityWeatherByZIPResult->Success); - } - - /** - * @test - * @@runInSeparateProcess - */ - function it_should_know_the_last_request_and_response() - { - $this->assertEquals(0, strlen($this->client->__getLastRequest())); - $this->assertEquals(0, strlen($this->client->__getLastResponse())); - $this->client->GetCityWeatherByZIP(['ZIP' => '10013']); - $this->assertGreaterThan(0, strlen($this->client->__getLastRequest())); - $this->assertGreaterThan(0, strlen($this->client->__getLastRequest())); - } -} diff --git a/test/PhproTest/SoapClient/Integration/Soap/SoapClientTest.php b/test/PhproTest/SoapClient/Integration/Soap/SoapClientTest.php deleted file mode 100644 index 718f713f..00000000 --- a/test/PhproTest/SoapClient/Integration/Soap/SoapClientTest.php +++ /dev/null @@ -1,72 +0,0 @@ -client = new PhproSoapClient(self::CDYNE_WSDL, ['soap_version' => SOAP_1_2]); - } - - /** - * @test - */ - function it_should_know_all_WSDL_types() - { - $types = $this->client->getSoapTypes(); - - $this->assertTrue(array_key_exists('GetCityForecastByZIP', $types)); - $this->assertEquals('string', $types['GetCityForecastByZIP']['ZIP']); - } - - /** - * @test - * @vcr soap-get-city-weather-by-zip-10013.yml - * - * Note: this method will throw Exceptions if VCR can't take over the configured SoapClient. - */ - function it_should_be_possible_to_hook_php_vcr_for_testing() - { - $result = $this->client->GetCityWeatherByZIP(['ZIP' => '10013']); - $this->assertTrue($result->GetCityWeatherByZIPResult->Success); - } - - /** - * @test - * @vcr soap-get-city-weather-by-zip-10013.yml - * - * Note: The headers are not remembered by the internally used php-vcr soapclient. - */ - function it_should_know_the_last_request_and_response() - { - $this->assertEquals(0, strlen($this->client->__getLastRequest())); - $this->assertEquals(0, strlen($this->client->__getLastResponse())); - $this->client->GetCityWeatherByZIP(['ZIP' => '10013']); - $this->assertGreaterThan(0, strlen($this->client->__getLastRequest())); - $this->assertGreaterThan(0, strlen($this->client->__getLastResponse())); - } -} diff --git a/test/PhproTest/SoapClient/Integration/Soap/Type/ValidateRequest.php b/test/PhproTest/SoapClient/Integration/Soap/Type/ValidateRequest.php new file mode 100644 index 00000000..4dfb00db --- /dev/null +++ b/test/PhproTest/SoapClient/Integration/Soap/Type/ValidateRequest.php @@ -0,0 +1,10 @@ + [ - 'myProperty' => 'string', - ] + $typeMap = new TypeMap($namespace = 'MyNamespace', [ + new Type( + $namespace, + 'MyType', + [ + new Property('myProperty', 'string', $namespace) + ] + ), ]); return new ClassMapContext($file, $typeMap, 'ClassMap', 'ClassMapNamespace'); diff --git a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ClientMethodAssemblerTest.php b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ClientMethodAssemblerTest.php index 13ade654..2d1d9c9a 100644 --- a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ClientMethodAssemblerTest.php +++ b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ClientMethodAssemblerTest.php @@ -5,6 +5,7 @@ use Phpro\SoapClient\CodeGenerator\Assembler\ClientMethodAssembler; use Phpro\SoapClient\CodeGenerator\Context\ClientMethodContext; use Phpro\SoapClient\CodeGenerator\Model\ClientMethod; +use Phpro\SoapClient\CodeGenerator\Model\Parameter; use PHPUnit\Framework\TestCase; use Zend\Code\Generator\ClassGenerator; @@ -41,10 +42,15 @@ private function createContext() { // ClassGenerator $class, ClientMethod $method $class = new ClassGenerator(); - $class->setNamespaceName('Vendor\\MyNamespace'); - $method = ClientMethod::createFromExtSoapFunctionString( - 'ReturnType functionName(ParamType $param)', - 'Vendor\\MyTypeNamespace' + $class->setNamespaceName($namespace = 'Vendor\\MyNamespace'); + $typeNamespace = 'Vendor\\MyTypeNamespace'; + $method = new ClientMethod( + 'functionName', + [ + new Parameter('param', $typeNamespace.'\\ParamType'), + ], + 'ReturnType', + $typeNamespace ); return new ClientMethodContext($class, $method); @@ -57,10 +63,16 @@ private function createMultiArgumentContext() { // ClassGenerator $class, ClientMethod $method $class = new ClassGenerator(); - $class->setNamespaceName('Vendor\\MyNamespace'); - $method = ClientMethod::createFromExtSoapFunctionString( - 'ReturnType functionName(ParamType $param, OtherParamType $param2)', - 'Vendor\\MyTypeNamespace' + $class->setNamespaceName($namespace = 'Vendor\\MyNamespace'); + $typeNamespace = 'Vendor\\MyTypeNamespace'; + $method = new ClientMethod( + 'functionName', + [ + new Parameter('param', $typeNamespace.'\\ParamType'), + new Parameter('param2', $typeNamespace.'\\OtherParamType'), + ], + 'ReturnType', + $typeNamespace ); return new ClientMethodContext($class, $method); @@ -153,9 +165,14 @@ function it_assembles_a_method_with_underscore_param_type() $assembler = new ClientMethodAssembler(); $class = new ClassGenerator(); $class->setNamespaceName('Vendor\\MyNamespace'); - $method = ClientMethod::createFromExtSoapFunctionString( - 'return_type Function_name(param_type $param)', - 'Vendor\\MyTypeNamespace' + $typeNamespace = 'Vendor\\MyTypeNamespace'; + $method = new ClientMethod( + 'Function_name', + [ + new Parameter('param', $typeNamespace.'\\param_type'), + ], + 'return_type', + $typeNamespace ); $context = new ClientMethodContext($class, $method); diff --git a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ConstructorAssemblerTest.php b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ConstructorAssemblerTest.php index 7b33535c..6d44c6ec 100644 --- a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ConstructorAssemblerTest.php +++ b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ConstructorAssemblerTest.php @@ -6,6 +6,7 @@ use Phpro\SoapClient\CodeGenerator\Assembler\ConstructorAssembler; use Phpro\SoapClient\CodeGenerator\Assembler\ConstructorAssemblerOptions; use Phpro\SoapClient\CodeGenerator\Context\TypeContext; +use Phpro\SoapClient\CodeGenerator\Model\Property; use Phpro\SoapClient\CodeGenerator\Model\Type; use PHPUnit\Framework\TestCase; use Zend\Code\Generator\ClassGenerator; @@ -79,10 +80,10 @@ function it_assembles_a_type_with_type_hints() { $assembler = new ConstructorAssembler((new ConstructorAssemblerOptions())->withTypeHints()); $class = new ClassGenerator('MyType', 'MyNamespace'); - $type = new Type('MyNamespace', 'MyType', [ - 'prop1' => 'string', - 'prop2' => 'int', - 'prop3' => 'SomeClass', + $type = new Type($namespace = 'MyNamespace', 'MyType', [ + new Property('prop1', 'string', $namespace), + new Property('prop2', 'int', $namespace), + new Property('prop3', 'SomeClass', $namespace), ]); $context = new TypeContext($class, $type); @@ -157,9 +158,9 @@ public function __construct(string \$prop1, int \$prop2) private function createContext() { $class = new ClassGenerator('MyType', 'MyNamespace'); - $type = new Type('MyNamespace', 'MyType', [ - 'prop1' => 'string', - 'prop2' => 'int' + $type = new Type($namespace = 'MyNamespace', 'MyType', [ + new Property('prop1', 'string', $namespace), + new Property('prop2', 'int', $namespace), ]); return new TypeContext($class, $type); diff --git a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ExtendAssemblerTest.php b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ExtendAssemblerTest.php index 3b817439..415cd391 100644 --- a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ExtendAssemblerTest.php +++ b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ExtendAssemblerTest.php @@ -5,6 +5,7 @@ use Phpro\SoapClient\CodeGenerator\Assembler\AssemblerInterface; use Phpro\SoapClient\CodeGenerator\Assembler\ExtendAssembler; use Phpro\SoapClient\CodeGenerator\Context\TypeContext; +use Phpro\SoapClient\CodeGenerator\Model\Property; use Phpro\SoapClient\CodeGenerator\Model\Type; use PHPUnit\Framework\TestCase; use Zend\Code\Generator\ClassGenerator; @@ -92,9 +93,9 @@ class MyType private function createContext() { $class = new ClassGenerator('MyType', 'MyNamespace'); - $type = new Type('MyNamespace', 'MyType', [ - 'prop1' => 'string', - 'prop2' => 'int' + $type = new Type($namespace = 'MyNamespace', 'MyType', [ + new Property('prop1', 'string', $namespace), + new Property('prop2', 'int', $namespace), ]); return new TypeContext($class, $type); diff --git a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/FinalClassAssemblerTest.php b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/FinalClassAssemblerTest.php index f512496c..31f56ef8 100644 --- a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/FinalClassAssemblerTest.php +++ b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/FinalClassAssemblerTest.php @@ -5,6 +5,7 @@ use Phpro\SoapClient\CodeGenerator\Assembler\AssemblerInterface; use Phpro\SoapClient\CodeGenerator\Assembler\FinalClassAssembler; use Phpro\SoapClient\CodeGenerator\Context\TypeContext; +use Phpro\SoapClient\CodeGenerator\Model\Property; use Phpro\SoapClient\CodeGenerator\Model\Type; use PHPUnit\Framework\TestCase; use Zend\Code\Generator\ClassGenerator; @@ -65,9 +66,9 @@ final class MyType private function createContext() { $class = new ClassGenerator('MyType', 'MyNamespace'); - $type = new Type('MyNamespace', 'MyType', [ - 'prop1' => 'string', - 'prop2' => 'int' + $type = new Type($namespace ='MyNamespace', 'MyType', [ + new Property('prop1', 'string', $namespace), + new Property('prop2', 'int', $namespace), ]); return new TypeContext($class, $type); diff --git a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/FluentSetterAssemblerTest.php b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/FluentSetterAssemblerTest.php index efae6d08..8857dd45 100644 --- a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/FluentSetterAssemblerTest.php +++ b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/FluentSetterAssemblerTest.php @@ -194,10 +194,9 @@ public function setProp1(\$prop1) : \MyNamespace\MyType private function createContext() { $class = new ClassGenerator('MyType', 'MyNamespace'); - $type = new Type('MyNamespace', 'MyType', [ - 'prop1' => 'string', + $type = new Type($namespace = 'MyNamespace', 'MyType', [ + $property = new Property('prop1', 'string', 'ns1'), ]); - $property = new Property('prop1', 'string', 'ns1'); return new PropertyContext($class, $type, $property); } @@ -208,10 +207,9 @@ private function createContext() private function createContextWithAnUnknownType() { $class = new ClassGenerator('MyType', 'MyNamespace'); - $type = new Type('MyNamespace', 'MyType', [ - 'prop1' => 'foobar', + $type = new Type($namespace = 'MyNamespace', 'MyType', [ + $property = new Property('prop1', 'foobar', $namespace), ]); - $property = new Property('prop1', 'foobar', 'MyNamespace'); return new PropertyContext($class, $type, $property); } diff --git a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/GetterAssemblerTest.php b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/GetterAssemblerTest.php index e55ab111..74b0ad52 100644 --- a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/GetterAssemblerTest.php +++ b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/GetterAssemblerTest.php @@ -194,15 +194,15 @@ public function getProp4() : \\ns1\\MyResponse private function createContext($propertyName = 'prop1') { $properties = [ - 'prop1' => 'string', - 'prop2' => 'int', - 'prop3' => 'boolean', - 'prop4' => 'My_Response', + 'prop1' => new Property('prop1', 'string', 'ns1'), + 'prop2' => new Property('prop2', 'int', 'ns1'), + 'prop3' => new Property('prop3', 'boolean', 'ns1'), + 'prop4' => new Property('prop4', 'My_Response', 'ns1'), ]; $class = new ClassGenerator('MyType', 'MyNamespace'); - $type = new Type('MyNamespace', 'MyType', $properties); - $property = new Property($propertyName, $properties[$propertyName], 'ns1'); + $type = new Type('MyNamespace', 'MyType', array_values($properties)); + $property = $properties[$propertyName]; return new PropertyContext($class, $type, $property); } diff --git a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ImmutableSetterAssemblerTest.php b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ImmutableSetterAssemblerTest.php index 5d1b35b9..040d2567 100644 --- a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ImmutableSetterAssemblerTest.php +++ b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ImmutableSetterAssemblerTest.php @@ -81,9 +81,8 @@ private function createContext() { $class = new ClassGenerator('MyType', 'MyNamespace'); $type = new Type('MyNamespace', 'MyType', [ - 'prop1' => 'string' + $property = new Property('prop1', 'string', 'ns1'), ]); - $property = new Property('prop1', 'string', 'ns1'); return new PropertyContext($class, $type, $property); } diff --git a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/InterfaceAssemblerTest.php b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/InterfaceAssemblerTest.php index 6ef7740d..25780243 100644 --- a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/InterfaceAssemblerTest.php +++ b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/InterfaceAssemblerTest.php @@ -83,9 +83,9 @@ class MyType implements Iterator private function createContext() { $class = new ClassGenerator('MyType', 'MyNamespace'); - $type = new Type('MyNamespace', 'MyType', [ - 'prop1' => 'string', - 'prop2' => 'int' + $type = new Type($namespace = 'MyNamespace', 'MyType', [ + new Property('prop1', 'string', $namespace), + new Property('prop2', 'int', $namespace), ]); return new TypeContext($class, $type); diff --git a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/IteratorAssemblerTest.php b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/IteratorAssemblerTest.php index 4bf4a489..e0db668a 100644 --- a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/IteratorAssemblerTest.php +++ b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/IteratorAssemblerTest.php @@ -5,6 +5,7 @@ use Phpro\SoapClient\CodeGenerator\Assembler\AssemblerInterface; use Phpro\SoapClient\CodeGenerator\Assembler\IteratorAssembler; use Phpro\SoapClient\CodeGenerator\Context\TypeContext; +use Phpro\SoapClient\CodeGenerator\Model\Property; use Phpro\SoapClient\CodeGenerator\Model\Type; use PHPUnit\Framework\TestCase; use Zend\Code\Generator\ClassGenerator; @@ -76,8 +77,8 @@ public function getIterator() private function createContext() { $class = new ClassGenerator('MyType', 'MyNamespace'); - $type = new Type('MyNamespace', 'MyType', [ - 'prop1' => 'array', + $type = new Type($namespace = 'MyNamespace', 'MyType', [ + new Property('prop1', 'array', $namespace), ]); return new TypeContext($class, $type); diff --git a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/JsonSerializableAssemblerTest.php b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/JsonSerializableAssemblerTest.php index fee52bac..9380fc48 100644 --- a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/JsonSerializableAssemblerTest.php +++ b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/JsonSerializableAssemblerTest.php @@ -5,6 +5,7 @@ use Phpro\SoapClient\CodeGenerator\Assembler\AssemblerInterface; use Phpro\SoapClient\CodeGenerator\Assembler\JsonSerializableAssembler; use Phpro\SoapClient\CodeGenerator\Context\TypeContext; +use Phpro\SoapClient\CodeGenerator\Model\Property; use Phpro\SoapClient\CodeGenerator\Model\Type; use PHPUnit\Framework\TestCase; use Zend\Code\Generator\ClassGenerator; @@ -79,9 +80,9 @@ public function jsonSerialize() private function createContext() { $class = new ClassGenerator('MyType', 'MyNamespace'); - $type = new Type('MyNamespace', 'MyType', [ - 'prop1' => 'array', - 'prop2' => 'array', + $type = new Type($namespace = 'MyNamespace', 'MyType', [ + new Property('prop1', 'array', $namespace), + new Property('prop2', 'array', $namespace), ]); return new TypeContext($class, $type); diff --git a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/PropertyAssemblerTest.php b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/PropertyAssemblerTest.php index 24380200..de6e8775 100644 --- a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/PropertyAssemblerTest.php +++ b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/PropertyAssemblerTest.php @@ -172,10 +172,8 @@ private function createContext() { $class = new ClassGenerator('MyType', 'MyNamespace'); $type = new Type('MyNamespace', 'MyType', [ - 'prop1' => 'string', - 'prop2' => 'int', + $property = new Property('prop1', 'string', 'ns1'), ]); - $property = new Property('prop1', 'string', 'ns1'); return new PropertyContext($class, $type, $property); } diff --git a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/RequestAssemblerTest.php b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/RequestAssemblerTest.php index f241768c..0c728ef7 100644 --- a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/RequestAssemblerTest.php +++ b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/RequestAssemblerTest.php @@ -5,6 +5,7 @@ use Phpro\SoapClient\CodeGenerator\Assembler\AssemblerInterface; use Phpro\SoapClient\CodeGenerator\Assembler\RequestAssembler; use Phpro\SoapClient\CodeGenerator\Context\TypeContext; +use Phpro\SoapClient\CodeGenerator\Model\Property; use Phpro\SoapClient\CodeGenerator\Model\Type; use PHPUnit\Framework\TestCase; use Zend\Code\Generator\ClassGenerator; @@ -68,9 +69,9 @@ class MyType implements RequestInterface private function createContext() { $class = new ClassGenerator('MyType', 'MyNamespace'); - $type = new Type('MyNamespace', 'MyType', [ - 'prop1' => 'string', - 'prop2' => 'int' + $type = new Type($namespace = 'MyNamespace', 'MyType', [ + new Property('prop1', 'string', $namespace), + new Property('prop2', 'int', $namespace), ]); return new TypeContext($class, $type); diff --git a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ResultAssemblerTest.php b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ResultAssemblerTest.php index c454f479..e8161b1b 100644 --- a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ResultAssemblerTest.php +++ b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ResultAssemblerTest.php @@ -5,6 +5,7 @@ use Phpro\SoapClient\CodeGenerator\Assembler\AssemblerInterface; use Phpro\SoapClient\CodeGenerator\Assembler\ResultAssembler; use Phpro\SoapClient\CodeGenerator\Context\TypeContext; +use Phpro\SoapClient\CodeGenerator\Model\Property; use Phpro\SoapClient\CodeGenerator\Model\Type; use PHPUnit\Framework\TestCase; use Zend\Code\Generator\ClassGenerator; @@ -68,9 +69,9 @@ class MyType implements ResultInterface private function createContext() { $class = new ClassGenerator('MyType', 'MyNamespace'); - $type = new Type('MyNamespace', 'MyType', [ - 'prop1' => 'string', - 'prop2' => 'int' + $type = new Type($namespace = 'MyNamespace', 'MyType', [ + new Property('prop1', 'string', $namespace), + new Property('prop2', 'int', $namespace), ]); return new TypeContext($class, $type); diff --git a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ResultProviderAssemblerTest.php b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ResultProviderAssemblerTest.php index 6e60ee3a..f283f0df 100644 --- a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ResultProviderAssemblerTest.php +++ b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/ResultProviderAssemblerTest.php @@ -5,6 +5,7 @@ use Phpro\SoapClient\CodeGenerator\Assembler\AssemblerInterface; use Phpro\SoapClient\CodeGenerator\Assembler\ResultProviderAssembler; use Phpro\SoapClient\CodeGenerator\Context\TypeContext; +use Phpro\SoapClient\CodeGenerator\Model\Property; use Phpro\SoapClient\CodeGenerator\Model\Type; use Phpro\SoapClient\Type\MixedResult; use PHPUnit\Framework\TestCase; @@ -147,8 +148,8 @@ public function getResult() : \Phpro\SoapClient\Type\ResultInterface private function createContext() { $class = new ClassGenerator('MyType', 'MyNamespace'); - $type = new Type('MyNamespace', 'MyType', [ - 'prop1' => 'SomeClass', + $type = new Type($namespace = 'MyNamespace', 'MyType', [ + new Property('prop1', 'SomeClass', $namespace) ]); return new TypeContext($class, $type); diff --git a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/SetterAssemblerTest.php b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/SetterAssemblerTest.php index b10f2435..d21105c1 100644 --- a/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/SetterAssemblerTest.php +++ b/test/PhproTest/SoapClient/Unit/CodeGenerator/Assembler/SetterAssemblerTest.php @@ -77,10 +77,9 @@ private function createContext() { $class = new ClassGenerator('MyType', 'MyNamespace'); $type = new Type('MyNamespace', 'MyType', [ - 'prop1' => 'string', - 'prop2' => 'int' + $property = new Property('prop1', 'string', 'ns1'), ]); - $property = new Property('prop1', 'string', 'ns1'); + return new PropertyContext($class, $type, $property); } diff --git a/test/PhproTest/SoapClient/Unit/CodeGenerator/ClientFactoryGeneratorTest.php b/test/PhproTest/SoapClient/Unit/CodeGenerator/ClientFactoryGeneratorTest.php index e0f99168..fe46f9ee 100644 --- a/test/PhproTest/SoapClient/Unit/CodeGenerator/ClientFactoryGeneratorTest.php +++ b/test/PhproTest/SoapClient/Unit/CodeGenerator/ClientFactoryGeneratorTest.php @@ -1,5 +1,6 @@ withClassMaps(Myclassmap::getCollection()); + \$engine = ExtSoapEngineFactory::fromOptions( + ExtSoapOptions::defaults(\$wsdl, []) + ->withClassMap(SomeClassmap::getCollection()) + ); + \$eventDispatcher = new EventDispatcher(); - return \$clientBuilder->build(); + return new Myclient(\$engine, \$eventDispatcher); } @@ -43,7 +47,7 @@ public static function factory(string \$wsdl) : \App\Client\Myclient $classMapContext = new ClassMapContext( new FileGenerator(), new \Phpro\SoapClient\CodeGenerator\Model\TypeMap('App\\Types', []), - 'Myclassmap', + 'SomeClassmap', 'App\\Classmap' ); $context = new ClientFactoryContext($clientContext, $classMapContext); diff --git a/test/PhproTest/SoapClient/Unit/CodeGenerator/ConfigGeneratorTest.php b/test/PhproTest/SoapClient/Unit/CodeGenerator/ConfigGeneratorTest.php index 762178d1..52708cc6 100644 --- a/test/PhproTest/SoapClient/Unit/CodeGenerator/ConfigGeneratorTest.php +++ b/test/PhproTest/SoapClient/Unit/CodeGenerator/ConfigGeneratorTest.php @@ -1,5 +1,7 @@ setWsdl('wsdl.xml') + ->setEngine(ExtSoapEngineFactory::fromOptions( + ExtSoapOptions::defaults('wsdl.xml', []) + ->disableWsdlCache() + )) ->setTypeDestination('src/type') ->setTypeNamespace('App\\\\Type') ->setClientDestination('src/client') @@ -50,7 +57,7 @@ public function testGenerate() CONTENT; $context = new ConfigContext(); $context - ->addSetter('setWsdl', 'wsdl.xml') + ->setWsdl('wsdl.xml') ->addSetter('setTypeDestination', 'src/type') ->addSetter('setTypeNamespace', 'App\\\\Type') ->addSetter('setClientDestination', 'src/client') @@ -75,9 +82,14 @@ public function testGenerateWithoutRegex() use Phpro\SoapClient\CodeGenerator\Assembler; use Phpro\SoapClient\CodeGenerator\Rules; use Phpro\SoapClient\CodeGenerator\Config\Config; +use Phpro\SoapClient\Soap\Driver\ExtSoap\ExtSoapOptions; +use Phpro\SoapClient\Soap\Driver\ExtSoap\ExtSoapEngineFactory; return Config::create() - ->setWsdl('wsdl.xml') + ->setEngine(ExtSoapEngineFactory::fromOptions( + ExtSoapOptions::defaults('wsdl.xml', []) + ->disableWsdlCache() + )) ->setTypeDestination('src/type') ->setTypeNamespace('App\\\\Type') ->setClientDestination('src/client') @@ -93,7 +105,7 @@ public function testGenerateWithoutRegex() CONTENT; $context = new ConfigContext(); $context - ->addSetter('setWsdl', 'wsdl.xml') + ->setWsdl('wsdl.xml') ->addSetter('setTypeDestination', 'src/type') ->addSetter('setTypeNamespace', 'App\\\\Type') ->addSetter('setClientDestination', 'src/client') @@ -107,4 +119,5 @@ public function testGenerateWithoutRegex() $generated = $generator->generate(new FileGenerator(), $context); self::assertEquals($expected, $generated); } + } diff --git a/test/PhproTest/SoapClient/Unit/Xml/XmlTest.php b/test/PhproTest/SoapClient/Unit/Xml/XmlTest.php index 24ab6fc6..afcc6e28 100644 --- a/test/PhproTest/SoapClient/Unit/Xml/XmlTest.php +++ b/test/PhproTest/SoapClient/Unit/Xml/XmlTest.php @@ -65,6 +65,18 @@ function it_is_possible_to_run_xpath_queries() ); } + /** + * @test + */ + function it_is_possible_to_run_xpath_queries_with_node_context() + { + $xml = new Xml($this->xml); + $documentElement = $xml->xpath('/soap:Envelope')->item(0); + $header = $xml->xpath('./soap:Header', $documentElement)->item(0); + + $this->assertEquals('soap:Header', $header->nodeName); + } + /** * @test */ diff --git a/test/fixtures/vcr/soap-get-city-weather-by-zip-10013.yml b/test/fixtures/vcr/ext-soap-with-client-handle-get-city-weather-by-zip-10013.yml similarity index 100% rename from test/fixtures/vcr/soap-get-city-weather-by-zip-10013.yml rename to test/fixtures/vcr/ext-soap-with-client-handle-get-city-weather-by-zip-10013.yml diff --git a/test/fixtures/vcr/guzzle-get-city-weather-by-zip-10013.yml b/test/fixtures/vcr/ext-soap-with-httplug-handle-get-city-weather-by-zip-10013.yml similarity index 100% rename from test/fixtures/vcr/guzzle-get-city-weather-by-zip-10013.yml rename to test/fixtures/vcr/ext-soap-with-httplug-handle-get-city-weather-by-zip-10013.yml diff --git a/test/fixtures/wsdl/functional/1999boolean.wsdl b/test/fixtures/wsdl/functional/1999boolean.wsdl new file mode 100644 index 00000000..bf69cfd8 --- /dev/null +++ b/test/fixtures/wsdl/functional/1999boolean.wsdl @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/1999byte.wsdl b/test/fixtures/wsdl/functional/1999byte.wsdl new file mode 100644 index 00000000..447d4dad --- /dev/null +++ b/test/fixtures/wsdl/functional/1999byte.wsdl @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/1999decimal.wsdl b/test/fixtures/wsdl/functional/1999decimal.wsdl new file mode 100644 index 00000000..c91e5601 --- /dev/null +++ b/test/fixtures/wsdl/functional/1999decimal.wsdl @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/1999double.wsdl b/test/fixtures/wsdl/functional/1999double.wsdl new file mode 100644 index 00000000..70f5931a --- /dev/null +++ b/test/fixtures/wsdl/functional/1999double.wsdl @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/1999float.wsdl b/test/fixtures/wsdl/functional/1999float.wsdl new file mode 100644 index 00000000..48c6a4c8 --- /dev/null +++ b/test/fixtures/wsdl/functional/1999float.wsdl @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/1999int.wsdl b/test/fixtures/wsdl/functional/1999int.wsdl new file mode 100644 index 00000000..72a49fb5 --- /dev/null +++ b/test/fixtures/wsdl/functional/1999int.wsdl @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/1999long.wsdl b/test/fixtures/wsdl/functional/1999long.wsdl new file mode 100644 index 00000000..f4c7e7a4 --- /dev/null +++ b/test/fixtures/wsdl/functional/1999long.wsdl @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/1999short.wsdl b/test/fixtures/wsdl/functional/1999short.wsdl new file mode 100644 index 00000000..bac264ab --- /dev/null +++ b/test/fixtures/wsdl/functional/1999short.wsdl @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/1999string.wsdl b/test/fixtures/wsdl/functional/1999string.wsdl new file mode 100644 index 00000000..c494deb0 --- /dev/null +++ b/test/fixtures/wsdl/functional/1999string.wsdl @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/1999timeinstant.wsdl b/test/fixtures/wsdl/functional/1999timeinstant.wsdl new file mode 100644 index 00000000..16debd47 --- /dev/null +++ b/test/fixtures/wsdl/functional/1999timeinstant.wsdl @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/any.wsdl b/test/fixtures/wsdl/functional/any.wsdl new file mode 100644 index 00000000..49d76c25 --- /dev/null +++ b/test/fixtures/wsdl/functional/any.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/anyURI.wsdl b/test/fixtures/wsdl/functional/anyURI.wsdl new file mode 100644 index 00000000..d0d483c0 --- /dev/null +++ b/test/fixtures/wsdl/functional/anyURI.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/apache-map.wsdl b/test/fixtures/wsdl/functional/apache-map.wsdl new file mode 100644 index 00000000..18f682b8 --- /dev/null +++ b/test/fixtures/wsdl/functional/apache-map.wsdl @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/base64Binary.wsdl b/test/fixtures/wsdl/functional/base64Binary.wsdl index 0621ef17..e9ebbb3e 100644 --- a/test/fixtures/wsdl/functional/base64Binary.wsdl +++ b/test/fixtures/wsdl/functional/base64Binary.wsdl @@ -9,7 +9,6 @@ - @@ -23,7 +22,7 @@ - + diff --git a/test/fixtures/wsdl/functional/boolean.wsdl b/test/fixtures/wsdl/functional/boolean.wsdl new file mode 100644 index 00000000..ee800c20 --- /dev/null +++ b/test/fixtures/wsdl/functional/boolean.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/byte.wsdl b/test/fixtures/wsdl/functional/byte.wsdl new file mode 100644 index 00000000..a57dabc5 --- /dev/null +++ b/test/fixtures/wsdl/functional/byte.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/complex-type-mapped-request-response.wsdl b/test/fixtures/wsdl/functional/complex-type-mapped-request-response.wsdl new file mode 100644 index 00000000..6ccd4237 --- /dev/null +++ b/test/fixtures/wsdl/functional/complex-type-mapped-request-response.wsdl @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/complex-type-request-response.wsdl b/test/fixtures/wsdl/functional/complex-type-request-response.wsdl new file mode 100644 index 00000000..b651ab7d --- /dev/null +++ b/test/fixtures/wsdl/functional/complex-type-request-response.wsdl @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/date.wsdl b/test/fixtures/wsdl/functional/date.wsdl new file mode 100644 index 00000000..b6591c62 --- /dev/null +++ b/test/fixtures/wsdl/functional/date.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/datetime.wsdl b/test/fixtures/wsdl/functional/datetime.wsdl new file mode 100644 index 00000000..77600429 --- /dev/null +++ b/test/fixtures/wsdl/functional/datetime.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/decimal.wsdl b/test/fixtures/wsdl/functional/decimal.wsdl new file mode 100644 index 00000000..47d89ee0 --- /dev/null +++ b/test/fixtures/wsdl/functional/decimal.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/double.wsdl b/test/fixtures/wsdl/functional/double.wsdl new file mode 100644 index 00000000..d0eb6b35 --- /dev/null +++ b/test/fixtures/wsdl/functional/double.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/duration.wsdl b/test/fixtures/wsdl/functional/duration.wsdl new file mode 100644 index 00000000..2ced45c6 --- /dev/null +++ b/test/fixtures/wsdl/functional/duration.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/entities.wsdl b/test/fixtures/wsdl/functional/entities.wsdl new file mode 100644 index 00000000..0b67e2a7 --- /dev/null +++ b/test/fixtures/wsdl/functional/entities.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/entity.wsdl b/test/fixtures/wsdl/functional/entity.wsdl new file mode 100644 index 00000000..89708018 --- /dev/null +++ b/test/fixtures/wsdl/functional/entity.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/enum.wsdl b/test/fixtures/wsdl/functional/enum.wsdl index deb78ddc..f8584052 100644 --- a/test/fixtures/wsdl/functional/enum.wsdl +++ b/test/fixtures/wsdl/functional/enum.wsdl @@ -35,7 +35,7 @@ - + @@ -51,3 +51,5 @@ + + diff --git a/test/fixtures/wsdl/functional/float.wsdl b/test/fixtures/wsdl/functional/float.wsdl new file mode 100644 index 00000000..2fffb3cd --- /dev/null +++ b/test/fixtures/wsdl/functional/float.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/gDay.wsdl b/test/fixtures/wsdl/functional/gDay.wsdl new file mode 100644 index 00000000..c117e77b --- /dev/null +++ b/test/fixtures/wsdl/functional/gDay.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/gMonth.wsdl b/test/fixtures/wsdl/functional/gMonth.wsdl new file mode 100644 index 00000000..cda40cbf --- /dev/null +++ b/test/fixtures/wsdl/functional/gMonth.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/gMonthDay.wsdl b/test/fixtures/wsdl/functional/gMonthDay.wsdl new file mode 100644 index 00000000..1c2e1798 --- /dev/null +++ b/test/fixtures/wsdl/functional/gMonthDay.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/gYear.wsdl b/test/fixtures/wsdl/functional/gYear.wsdl new file mode 100644 index 00000000..c8dfc01c --- /dev/null +++ b/test/fixtures/wsdl/functional/gYear.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/gYearMonth.wsdl b/test/fixtures/wsdl/functional/gYearMonth.wsdl new file mode 100644 index 00000000..5cce6f37 --- /dev/null +++ b/test/fixtures/wsdl/functional/gYearMonth.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/guess.wsdl b/test/fixtures/wsdl/functional/guess.wsdl new file mode 100644 index 00000000..66c9e5cd --- /dev/null +++ b/test/fixtures/wsdl/functional/guess.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/hexBinary.wsdl b/test/fixtures/wsdl/functional/hexBinary.wsdl new file mode 100644 index 00000000..f1daec97 --- /dev/null +++ b/test/fixtures/wsdl/functional/hexBinary.wsdl @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/id.wsdl b/test/fixtures/wsdl/functional/id.wsdl new file mode 100644 index 00000000..7c0fb7b7 --- /dev/null +++ b/test/fixtures/wsdl/functional/id.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/idref.wsdl b/test/fixtures/wsdl/functional/idref.wsdl new file mode 100644 index 00000000..7b372dbd --- /dev/null +++ b/test/fixtures/wsdl/functional/idref.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/idrefs.wsdl b/test/fixtures/wsdl/functional/idrefs.wsdl new file mode 100644 index 00000000..c69865e1 --- /dev/null +++ b/test/fixtures/wsdl/functional/idrefs.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/int.wsdl b/test/fixtures/wsdl/functional/int.wsdl new file mode 100644 index 00000000..d560ba86 --- /dev/null +++ b/test/fixtures/wsdl/functional/int.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/integer.wsdl b/test/fixtures/wsdl/functional/integer.wsdl new file mode 100644 index 00000000..f06d7428 --- /dev/null +++ b/test/fixtures/wsdl/functional/integer.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/language.wsdl b/test/fixtures/wsdl/functional/language.wsdl new file mode 100644 index 00000000..2bb48943 --- /dev/null +++ b/test/fixtures/wsdl/functional/language.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/list.wsdl b/test/fixtures/wsdl/functional/list.wsdl new file mode 100644 index 00000000..61d02ae4 --- /dev/null +++ b/test/fixtures/wsdl/functional/list.wsdl @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/long.wsdl b/test/fixtures/wsdl/functional/long.wsdl new file mode 100644 index 00000000..2a11c036 --- /dev/null +++ b/test/fixtures/wsdl/functional/long.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/multiArgumentResponse.wsdl b/test/fixtures/wsdl/functional/multiArgumentResponse.wsdl new file mode 100644 index 00000000..93a9401f --- /dev/null +++ b/test/fixtures/wsdl/functional/multiArgumentResponse.wsdl @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/name.wsdl b/test/fixtures/wsdl/functional/name.wsdl new file mode 100644 index 00000000..8d772789 --- /dev/null +++ b/test/fixtures/wsdl/functional/name.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/ncname.wsdl b/test/fixtures/wsdl/functional/ncname.wsdl new file mode 100644 index 00000000..1acf5857 --- /dev/null +++ b/test/fixtures/wsdl/functional/ncname.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/ncnames.wsdl b/test/fixtures/wsdl/functional/ncnames.wsdl new file mode 100644 index 00000000..eef4fe3d --- /dev/null +++ b/test/fixtures/wsdl/functional/ncnames.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/negativeInteger.wsdl b/test/fixtures/wsdl/functional/negativeInteger.wsdl new file mode 100644 index 00000000..1f555046 --- /dev/null +++ b/test/fixtures/wsdl/functional/negativeInteger.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/nmtoken.wsdl b/test/fixtures/wsdl/functional/nmtoken.wsdl new file mode 100644 index 00000000..f3d8bd82 --- /dev/null +++ b/test/fixtures/wsdl/functional/nmtoken.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/nmtokens.wsdl b/test/fixtures/wsdl/functional/nmtokens.wsdl new file mode 100644 index 00000000..67a52f40 --- /dev/null +++ b/test/fixtures/wsdl/functional/nmtokens.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/nonNegativeInteger.wsdl b/test/fixtures/wsdl/functional/nonNegativeInteger.wsdl new file mode 100644 index 00000000..c56f5ac9 --- /dev/null +++ b/test/fixtures/wsdl/functional/nonNegativeInteger.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/nonPositiveInteger.wsdl b/test/fixtures/wsdl/functional/nonPositiveInteger.wsdl new file mode 100644 index 00000000..71eb5d95 --- /dev/null +++ b/test/fixtures/wsdl/functional/nonPositiveInteger.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/normalizedString.wsdl b/test/fixtures/wsdl/functional/normalizedString.wsdl new file mode 100644 index 00000000..ceda2fbc --- /dev/null +++ b/test/fixtures/wsdl/functional/normalizedString.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/notation.wsdl b/test/fixtures/wsdl/functional/notation.wsdl new file mode 100644 index 00000000..84dd82a4 --- /dev/null +++ b/test/fixtures/wsdl/functional/notation.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/positiveInteger.wsdl b/test/fixtures/wsdl/functional/positiveInteger.wsdl new file mode 100644 index 00000000..32587823 --- /dev/null +++ b/test/fixtures/wsdl/functional/positiveInteger.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/qname.wsdl b/test/fixtures/wsdl/functional/qname.wsdl new file mode 100644 index 00000000..76c2c3c9 --- /dev/null +++ b/test/fixtures/wsdl/functional/qname.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/short.wsdl b/test/fixtures/wsdl/functional/short.wsdl new file mode 100644 index 00000000..5aa2f0b9 --- /dev/null +++ b/test/fixtures/wsdl/functional/short.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/simpleContent.wsdl b/test/fixtures/wsdl/functional/simpleContent.wsdl index f42c4284..c3c367e3 100644 --- a/test/fixtures/wsdl/functional/simpleContent.wsdl +++ b/test/fixtures/wsdl/functional/simpleContent.wsdl @@ -35,7 +35,7 @@ - + diff --git a/test/fixtures/wsdl/functional/soap11-enc-array.wsdl b/test/fixtures/wsdl/functional/soap11-enc-array.wsdl new file mode 100644 index 00000000..a5139961 --- /dev/null +++ b/test/fixtures/wsdl/functional/soap11-enc-array.wsdl @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/soap11-enc-object.wsdl b/test/fixtures/wsdl/functional/soap11-enc-object.wsdl new file mode 100644 index 00000000..ba8f81ee --- /dev/null +++ b/test/fixtures/wsdl/functional/soap11-enc-object.wsdl @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/soap12-enc-array.wsdl b/test/fixtures/wsdl/functional/soap12-enc-array.wsdl new file mode 100644 index 00000000..f9a09a68 --- /dev/null +++ b/test/fixtures/wsdl/functional/soap12-enc-array.wsdl @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/soap12-enc-object.wsdl b/test/fixtures/wsdl/functional/soap12-enc-object.wsdl new file mode 100644 index 00000000..80bd5ed4 --- /dev/null +++ b/test/fixtures/wsdl/functional/soap12-enc-object.wsdl @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/string.wsdl b/test/fixtures/wsdl/functional/string.wsdl new file mode 100644 index 00000000..8c8c747a --- /dev/null +++ b/test/fixtures/wsdl/functional/string.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/time.wsdl b/test/fixtures/wsdl/functional/time.wsdl new file mode 100644 index 00000000..11135e26 --- /dev/null +++ b/test/fixtures/wsdl/functional/time.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/token.wsdl b/test/fixtures/wsdl/functional/token.wsdl new file mode 100644 index 00000000..b4b75b71 --- /dev/null +++ b/test/fixtures/wsdl/functional/token.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/union.wsdl b/test/fixtures/wsdl/functional/union.wsdl new file mode 100644 index 00000000..51b8b066 --- /dev/null +++ b/test/fixtures/wsdl/functional/union.wsdl @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/unsignedByte.wsdl b/test/fixtures/wsdl/functional/unsignedByte.wsdl new file mode 100644 index 00000000..ac8e10d1 --- /dev/null +++ b/test/fixtures/wsdl/functional/unsignedByte.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/unsignedInt.wsdl b/test/fixtures/wsdl/functional/unsignedInt.wsdl new file mode 100644 index 00000000..fc8f483a --- /dev/null +++ b/test/fixtures/wsdl/functional/unsignedInt.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/unsignedLong.wsdl b/test/fixtures/wsdl/functional/unsignedLong.wsdl new file mode 100644 index 00000000..90019206 --- /dev/null +++ b/test/fixtures/wsdl/functional/unsignedLong.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/fixtures/wsdl/functional/unsignedShort.wsdl b/test/fixtures/wsdl/functional/unsignedShort.wsdl new file mode 100644 index 00000000..35bf2856 --- /dev/null +++ b/test/fixtures/wsdl/functional/unsignedShort.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +