Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepare soap-client for new php-soap/encoding package #524

Merged
merged 1 commit into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Want more information about the future of this project? Check out this list of t
You can choose what HTTP client you want to use.
This package expects some PSR implementations to be present in order to be installed:

* PSR-6: `psr/cache-implementation` like `symfony/cache` or `cache/*-adapter`
* PSR-7: `psr/http-message-implementation` like `nyholm/psr7` or `guzzlehttp/psr7`
* PSR-17: `psr/http-factory-implementation` like `nyholm/psr7` or `guzzlehttp/psr7`
* PSR-18: `psr/http-client-implementation` like `symfony/http-client` or `guzzlehttp/guzzle`
Expand Down Expand Up @@ -73,8 +74,8 @@ You can customize the generated code based on the manual installation pages in t
- [Get in control of the soap-client](https://github.com/php-soap/engine)
- [Psr-18 HTTP Transport](https://github.com/php-soap/psr18-transport/)
- [Configure one or multiple HTTP middlewares.](https://github.com/php-soap/psr18-transport/#middleware)
- [Customize how ext-soap behaves](https://github.com/php-soap/ext-soap-engine/)
- [Select a WSDL Provider](https://github.com/php-soap/ext-soap-engine/#wsdlprovider)
- [Customize how the encoding behaves](https://github.com/php-soap/encoding)
- [Select a WSDL loader](https://github.com/php-soap/wsdl#wsdl-loader)
- [Manipulate the metadata](docs/drivers/metadata.md)


Expand All @@ -88,10 +89,6 @@ For more advanced configuration, you can check the documentation inside the php-
- [Specify generation `Rules`](docs/code-generation/rules.md)
- [Generate code through `Assemblers`](docs/code-generation/assemblers.md)

## Known issues

- [ext-soap](docs/known-issues/ext-soap.md)

# Why this soap client was made

By default, the SoapClient works with a mix of arrays, stdClasses and other scalar types.
Expand Down
88 changes: 87 additions & 1 deletion UPGRADING.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,88 @@
# V3 to V4

**NOTE:** We now require a `psr/cache-implementation` so that the engine (and WSDL parsing) can be cached. Some examples are: `symfony/cache` or `cache/*-adapter`.
If you don't have a cache implementation installed, you can for example run:

```bash
composer require symfony/cache
```

Next, you can upgrade the soap-client:

```bash
composer require 'phpro/soap-client:^4.0.0' --update-with-dependencies
```

In V4, the engine factory changed again.
This will be the final breaking change for the engine factory since we now have a generic way to create it for both runtime and code generation:

Change the engine inside your code generation configuration:

```php
use Phpro\SoapClient\CodeGenerator\Config\Config;
use Phpro\SoapClient\Soap\CodeGeneratorEngineFactory;
use Phpro\SoapClient\Soap\DefaultEngineFactory;
use Phpro\SoapClient\Soap\EngineOptions;
use Soap\Wsdl\Loader\FlatteningLoader;
use Soap\Wsdl\Loader\StreamWrapperLoader;

return Config::create()
->setEngine($engine = DefaultEngineFactory::create(
EngineOptions::defaults('your.wsdl')
->withWsdlLoader(new FlatteningLoader(new StreamWrapperLoader())) // Or a PSR18-based loader ... :))
))
```

Regenerate classes:

```
./vendor/bin/soap-client generate:client --config=config/soap-client.php
./vendor/bin/soap-client generate:classmap --config=config/soap-client.php
./vendor/bin/soap-client generate:types --config=config/soap-client.php
./vendor/bin/soap-client generate:clientfactory --config=config/soap-client.php
```

Change the engine inside your (generated) ClientFactory:

```php
$engine = DefaultEngineFactory::create(
EngineOptions::defaults($wsdl)
->withEncoderRegistry(
EncoderRegistry::default()->addClassMapCollection(
CalcClassmap::getCollection()
)
)
// If you want to enable WSDL caching:
// ->withCache($yourPsr6CachePool)
// If you want to use Alternate HTTP settings:
// ->withWsdlLoader()
// ->withTransport()
// If you want specific SOAP setting:
// ->withWsdlParserContext()
// ->withPreferredSoapVersion()
);
```

[More information about the engine options can be found here.](/docs/cli/generate-clientfactory.md)


In case you are using a non-default metadata strategy, you can now configure it in the code generation configuration:

```php
use Phpro\SoapClient\CodeGenerator\Config\Config;
use Phpro\SoapClient\Soap\Metadata\Manipulators\DuplicateTypes\RemoveDuplicateTypesStrategy;
use Phpro\SoapClient\Soap\Metadata\MetadataOptions;

return Config::create()
->setTypeMetadataOptions(
MetadataOptions::empty()->withTypesManipulator(new RemoveDuplicateTypesStrategy())
)
```

[More information about the metadata options can be found here.](/docs/drivers/metadata.md)



# V2 to V3

```bash
Expand Down Expand Up @@ -254,7 +339,8 @@ Full example on how you can personalize your factory class:
use Http\Client\Common\PluginClient;
use Http\Discovery\Psr18ClientDiscovery;
use Phpro\SoapClient\Soap\DefaultEngineFactory;
use Phpro\SoapClient\Soap\ExtSoap\Metadata\Manipulators\DuplicateTypes\RemoveDuplicateTypesStrategy;use Phpro\SoapClient\Soap\Metadata\Manipulators\TypesManipulatorChain;
use Phpro\SoapClient\Soap\Metadata\Manipulators\DuplicateTypes\RemoveDuplicateTypesStrategy;
use Phpro\SoapClient\Soap\Metadata\Manipulators\TypesManipulatorChain;
use Phpro\SoapClient\Soap\Metadata\MetadataOptions;
use Soap\ExtSoapEngine\ExtSoapOptions;
use Soap\ExtSoapEngine\Wsdl\Naming\Md5Strategy;
Expand Down
12 changes: 7 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
"php": "~8.1.0 || ~8.2.0 || ~8.3.0",
"azjezz/psl": "^2.1",
"laminas/laminas-code": "^4.8.0",
"php-soap/engine": "^2.7",
"php-soap/ext-soap-engine": "^1.4",
"php-soap/psr18-transport": "^1.3",
"php-soap/wsdl-reader": "~0.6",
"php-soap/cached-engine": "~0.1",
"php-soap/engine": "^2.9",
"php-soap/encoding": "~0.2",
"php-soap/psr18-transport": "^1.6",
"php-soap/wsdl-reader": "~0.15",
"psr/event-dispatcher": "^1.0",
"psr/log": "^1.0 || ^2.0 || ^3.0",
"symfony/console": "~5.4 || ~6.0 || ~7.0",
Expand All @@ -36,7 +37,8 @@
"phpspec/prophecy-phpunit": "^2.0.1",
"phpstan/phpstan": "^1.10.15",
"phpunit/phpunit": "~9.5",
"squizlabs/php_codesniffer": "^3.7.1"
"squizlabs/php_codesniffer": "^3.7.1",
"symfony/cache": "^6.4 || ^7.0"
},
"config": {
"sort-packages": true,
Expand Down
10 changes: 5 additions & 5 deletions docs/cli/generate-classmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,18 @@ Example output:

namespace Myapp\Example\Classmap;

use Soap\ExtSoapEngine\Configuration\ClassMap\ClassMapCollection;
use Soap\ExtSoapEngine\Configuration\ClassMap\ClassMap;
use Soap\Encoding\ClassMap\ClassMapCollection;
use Soap\Encoding\ClassMap\ClassMap;

class OrderClassMap
{

public static function getCollection() : ClassMapCollection
{
return new ClassMapCollection(
new ClassMap('CreateOrder', Type\Example1::class),
new ClassMap('CardOrder', Type\Example2::class),
new ClassMap('OrderDetails', Type\Example3::class)
new ClassMap('http://namespace', 'CreateOrder', Type\Example1::class),
new ClassMap('http://namespace', 'CardOrder', Type\Example2::class),
new ClassMap('http://namespace', 'OrderDetails', Type\Example3::class)
);
}
}
Expand Down
51 changes: 35 additions & 16 deletions docs/cli/generate-clientfactory.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Generate a base client factory

To make things a little easier to get started a client factory generator method is available.
The generated factory can be seen as a good starting point to initialize the client.
It can be customized to your needs.

```bash
vendor/bin/soap-client generate:clientfactory
Expand Down Expand Up @@ -33,31 +35,49 @@ More advanced client factory:

use Http\Client\Common\PluginClient;
use Http\Discovery\Psr18ClientDiscovery;
use Phpro\SoapClient\Soap\ExtSoap\Metadata\Manipulators\DuplicateTypes\IntersectDuplicateTypesStrategy;
use Phpro\SoapClient\Caller\EngineCaller;
use Phpro\SoapClient\Caller\EventDispatchingCaller;
use Phpro\SoapClient\Soap\EngineOptions;
use Phpro\SoapClient\Soap\DefaultEngineFactory;
use Phpro\SoapClient\Soap\Metadata\Manipulators\DuplicateTypes\IntersectDuplicateTypesStrategy;
use Phpro\SoapClient\Soap\Metadata\MetadataOptions;
use Soap\CachedEngine\CacheConfig;
use Soap\Encoding\EncoderRegistry;
use Soap\Psr18Transport\Psr18Transport;
use Soap\Psr18Transport\Wsdl\Psr18Loader;
use Soap\Wsdl\Loader\FlatteningLoader;
use Soap\WsdlReader\Model\Definitions\SoapVersion;
use Symfony\Component\Cache\Adapter\RedisAdapter;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Phpro\SoapClient\Soap\ExtSoap\DefaultEngineFactory;
use Soap\ExtSoapEngine\ExtSoapOptions;
use Phpro\SoapClient\Caller\EventDispatchingCaller;
use Phpro\SoapClient\Caller\EngineCaller;

class CalculatorClientFactory
{
public static function factory(string $wsdl) : CalculatorClient
{
$engine = DefaultEngineFactory::create(
ExtSoapOptions::defaults($wsdl, [])
->withClassMap(CalculatorClassmap::getCollection()),
Psr18Transport::createForClient(
new PluginClient(
Psr18ClientDiscovery::find(),
[$plugin1, $plugin2]
EngineOptions::defaults($wsdl)
->withEncoderRegistry(
EncoderRegistry::default()
->addClassMapCollection(CalculatorClassmap::getCollection())
)
->withTransport(
Psr18Transport::createForClient(
new PluginClient(
Psr18ClientDiscovery::find(),
[$plugin1, $plugin2]
)
)
)
->withWsdlLoader(
new FlatteningLoader(
new Psr18Loader(Psr18ClientDiscovery::find())
)
)
->withCache(
new RedisAdapter(RedisAdapter::createConnection('redis://localhost')),
new CacheConfig('my-wsdl-cache-key', ttlInSeconds: 3600)
)
),
MetadataOptions::empty()->withTypesManipulator(
new IntersectDuplicateTypesStrategy()
)
->withPreferredSoapVersion(SoapVersion::SOAP_12)
);

$eventDispatcher = new EventDispatcher();
Expand All @@ -74,7 +94,6 @@ You can then tweak this class to fit your needs.

Here you can find some bookmarks for changing the factory:

- [Configuring ExtSoapOptions](https://github.com/php-soap/ext-soap-engine/#configuration-options)
- [Listening to events](../events.md)
- [Configuring the engine](https://github.com/php-soap/engine)
- [Using HTTP middleware](https://github.com/php-soap/psr18-transport/#middleware)
Expand Down
2 changes: 0 additions & 2 deletions docs/cli/generate-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ Usage:

Options:
--config=CONFIG The location of the soap code-generator config file

```

This generator will read all XSD types from the provided WSDL and convert it to PHP classes.
Expand All @@ -27,7 +26,6 @@ Keep in mind that the WSDL must provide all XSD types for the generation of valu
Options:

- **config**: A [configuration file](../code-generation/configuration.md) is required to build the types.
- **overwrite**: The soap-client overrides a file that cannot be patched without asking for confirmation.


When the value objects are generated, you will still need to customize them.
Expand Down
18 changes: 12 additions & 6 deletions docs/code-generation/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@ 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\CodeGeneratorEngineFactory;
use Soap\ExtSoapEngine\ExtSoapOptions;
use Phpro\SoapClient\Soap\DefaultEngineFactory;
use Phpro\SoapClient\Soap\EngineOptions;
use Phpro\SoapClient\Soap\Metadata\Manipulators\DuplicateTypes\IntersectDuplicateTypesStrategy;
use Phpro\SoapClient\Soap\Metadata\MetadataOptions;
use Soap\Wsdl\Loader\FlatteningLoader;
use Soap\Wsdl\Loader\StreamWrapperLoader;

return Config::create()
->setEngine(CodeGeneratorEngineFactory::create(
'wsdl.xml',
new FlatteningLoader(new StreamWrapperLoader())
->setEngine(DefaultEngineFactory::create(
EngineOptions::defaults('wsdl.xml')
->withWsdlLoader(new FlatteningLoader(new StreamWrapperLoader()))
))
->setTypeDestination('src/SoapTypes')
->setTypeNamespace('SoapTypes')
Expand All @@ -27,6 +29,10 @@ return Config::create()
->setClassMapNamespace('Acme\\Classmap')
->setClassMapDestination('src/acme/classmap')
->setClassMapName('AcmeClassmap')
->setTypeMetadataOptions(
MetadataOptions::empty()
->withTypesManipulator(new IntersectDuplicateTypesStrategy())
)
->addRule(new Rules\AssembleRule(new Assembler\GetterAssembler(
(new Assembler\GetterAssemblerOptions())
->withReturnType()
Expand All @@ -52,7 +58,7 @@ Execute `vendor/bin/soap-client generate:config` to start the interactive config

Specify how the code generation tool can talk to SOAP.
By default, we push a custom engine that deeply parses the WSDL for code generation purpose.
For loading the WSDL, a PSR-18 based WSDL loader is being used in 'flattening' mode.
For loading the WSDL, a stream based WSDL loader is being used in 'flattening' mode.
It is possible to change this to any other configuration you want to use
and provide additional options like the preferred SOAP version.

Expand Down
42 changes: 27 additions & 15 deletions docs/drivers/metadata.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,48 @@
# Driver metadata

## Dealing with ext-soap issues

### Duplicate types

Ext-soap does not add any namespace or unique identifier to the types it knows.
You can read more about this in the [known ext-soap issues](../known-issues/ext-soap.md#duplicate-typenames) section.
Therefore, we added some strategies to deal with duplicate types:
XSDs can have both internal and external types making that the names of the type can be non-unique in a given XML namespace.
It might not be possible to generate unique types for all types in the WSDL.
Therefore, we added some strategies to deal with duplicate types by default.

This can be configured in the [client configuration](/docs/code-generation/configuration.md):

**IntersectDuplicateTypesStrategy**

Enabled by default when using `DefaultEngineFactory::create()`.
Enabled by default when using `Config::create()`.

This duplicate types strategy will merge all duplicate types into one big type which contains all properties.


```php
use Phpro\SoapClient\CodeGenerator\Config\Config;
use Phpro\SoapClient\Soap\Metadata\Manipulators\DuplicateTypes\IntersectDuplicateTypesStrategy;
use Phpro\SoapClient\Soap\Metadata\MetadataOptions;

return Config::create()
//...
->setTypeMetadataOptions(
MetadataOptions::empty()->withTypesManipulator(new IntersectDuplicateTypesStrategy())
)
// ...
```

**RemoveDuplicateTypesStrategy**

This duplicate types strategy will remove all duplicate types it finds.

You can overwrite the strategy on the `DefaultEngineFactory` object inside the client factory:

```php
<?php

use Phpro\SoapClient\Soap\DefaultEngineFactory;
use Phpro\SoapClient\Soap\ExtSoap\Metadata\Manipulators\DuplicateTypes\RemoveDuplicateTypesStrategy;
use Phpro\SoapClient\CodeGenerator\Config\Config;
use Phpro\SoapClient\Soap\Metadata\Manipulators\DuplicateTypes\RemoveDuplicateTypesStrategy;
use Phpro\SoapClient\Soap\Metadata\MetadataOptions;

$engine = DefaultEngineFactory::create(
$options, $transport,
MetadataOptions::empty()->withTypesManipulator(
new RemoveDuplicateTypesStrategy()
return Config::create()
//...
->setTypeMetadataOptions(
MetadataOptions::empty()->withTypesManipulator(new RemoveDuplicateTypesStrategy())
)
);
// ...
```
Loading
Loading