Compare commits

..

135 Commits
v4.1 ... master

Author SHA1 Message Date
1fa5c8a15e Mark client generated services as public 2022-02-23 15:13:04 +01:00
813dd52d70 Update dependency injection for Symfony 4.* 2022-02-09 09:47:50 +01:00
8a40d23a94 Use laminas/laminas-mime instead of zendframework/zend-mime 2022-02-08 16:03:13 +01:00
5d335f2ca9 Correction de l'écriture du xml 2020-07-15 12:35:40 -04:00
9d6468d0a6
Update composer.json 2020-07-15 11:25:49 -04:00
9786f291b0
Update composer.json 2020-07-15 11:25:04 -04:00
750db6692b
Update composer.json 2020-07-15 11:24:05 -04:00
Mimir
9f7b7f40b8
Merge pull request #4 from Cadoles/develop
Add minOccurs annotation support on complexType
2020-07-15 16:29:05 +02:00
Mimir
87947a1e7b
Merge branch 'mse' into develop 2020-07-15 16:26:24 +02:00
e024833d48 Add minOccurs annotation support on complexType 2020-07-15 16:16:25 +02:00
fc44014790 Définition timeout curl a 10 secondes 2019-10-24 16:34:14 -04:00
7ba9c4048c Nouvelle méthode de validation des WSDL 2019-10-10 15:20:59 -04:00
f0733bd671 Nouvelle méthode de validation des WSDL 2019-10-10 15:17:16 -04:00
f5e1be09de Merge branch 'mse' of github.com:Cadoles/BeSimpleSoap into mse 2019-10-10 15:16:24 -04:00
df3d75047f Nouvelle méthode de validation des WSDL 2019-10-10 15:16:10 -04:00
87350704d3
Merge pull request #2 from Cadoles/issue#1
vérification fichier de cache vide ou xml erronné
2019-09-24 09:19:38 -04:00
85f86469ab Merge OK 2019-09-24 09:17:28 -04:00
e1a35d1e1e Vérification fichier de cache vide ou xml erronné 2019-09-24 08:54:47 -04:00
30850d7a01
Merge pull request #3 from Cadoles/php-cs-fixer
Passe générale php-cs-fixer
2019-09-24 08:50:42 -04:00
77403fcfbb Suppression fichier de cache cs-fixer 2019-09-24 08:45:47 -04:00
dc63ba20e4 ajouter fichier de cache cs-fixer au gitignore 2019-09-24 08:43:49 -04:00
dad2b76165 Passe générale php-cs-fixer 2019-09-24 08:23:19 -04:00
a1695680ae Signature de Response iso PROD 2019-09-20 12:10:09 -04:00
95706abbd7 Retour à une signature iso PROD 2019-09-19 15:29:04 -04:00
6d5f9ff9e5 Show null attributes in response
Partially revert changes from d1f5c1f6740121751754644c1123d97717fe5035 and fea1093bed108392caf4388b191d7c902a43838a
2019-09-16 16:41:21 +02:00
914acccf1d Ignore .php_cs.cache files 2019-09-12 11:45:48 +02:00
0c94185907 Revert "Fix Dumper. Each complext type is now wrapped inside container element tag"
This reverts commit 7802a0d19fb4fe1c5ad2f8b180f19649c52854cd.
2019-09-12 11:44:47 +02:00
aa0b750f47 Revert "Array support change"
This reverts commit 3f2a99adf6133910f36bf00f19a57accb59e1e40.
2019-09-12 11:43:53 +02:00
Tim Timmermans
cc83e1e6db Add support for "overriden" routes 2019-08-06 11:59:02 +02:00
Tim Timmermans
412e7f16c9 Reverted default definition style to RPC. 2019-08-06 11:58:51 +02:00
Tim Timmermans
729a2bc8df Fix dumper in order to generate a valid WSDL 2019-08-06 11:58:35 +02:00
BohwaZ
b8bf76aeb9 fixup! Update README, add back some instructions on how to use 2019-08-06 11:07:42 +02:00
BohwaZ
a3d691261c Update README, add back some instructions on how to use 2019-08-06 11:04:18 +02:00
BohwaZ
6cf62100a4 ext-mcrypt is not necessary and is not included in PHP anymore 2019-08-06 11:03:54 +02:00
Tim Timmermans
2e9dc9a34d Fix issue that each method param overrides the initial input message. 2019-08-06 10:57:16 +02:00
BohwaZ
95a91bb8bb Those tests don't have any value as depending on different PHP versions, the headers can slightly change 2019-08-06 10:48:46 +02:00
BohwaZ
ec0004ea36 Revert "Fix error handling"
This reverts commit ef81da77ea25d78cf55408fde3e7919f60faff3e.
2019-08-06 10:28:55 +02:00
BohwaZ
00101ff7fb Restore package name after merging back changes of cocciagialla fork 2019-08-06 10:26:19 +02:00
Gianluigi 'cocciagialla' Mammarella
ef81da77ea Fix error handling 2019-07-03 01:08:36 +02:00
Gianluigi 'cocciagialla' Mammarella
54e9e0ed05 Remove SOAP-ENC 2019-06-27 13:40:00 +02:00
Gianluigi 'cocciagialla' Mammarella
679b44ba13 Use encoded instead of literal 2019-06-27 13:08:26 +02:00
Gianluigi 'cocciagialla' Mammarella
a7a49b793a Add minOccurs and maxOccurs into wsdl dumper 2019-06-26 19:22:09 +02:00
Gianluigi 'cocciagialla' Mammarella
d1f5c1f674 Remove from response the nillable elements. Fix namespace declaration in the xml response 2019-06-26 19:03:56 +02:00
Gianluigi 'cocciagialla' Mammarella
fea1093bed Remove from response the nillable elements. Fix namespace declaration in the xml response 2019-06-26 18:53:59 +02:00
Gianluigi 'cocciagialla' Mammarella
9fc58e4388 Replace SOAP-ENV with soap as soap-envelope ns prefix 2019-06-24 19:05:43 +02:00
Gianluigi 'cocciagialla' Mammarella
a7c610b767 Add hexBinary type 2019-04-15 18:20:57 +02:00
Gianluigi 'cocciagialla' Mammarella
2b8f75b4ae Fix wsdl for array complex type 2019-04-11 10:33:17 +02:00
Gianluigi 'cocciagialla' Mammarella
6718703ba5 Add headers binder for document 2019-04-10 07:31:37 +02:00
Gianluigi 'cocciagialla' Mammarella
f9f47b913d Add base64Binary type 2019-04-10 07:30:54 +02:00
Gianluigi 'cocciagialla' Mammarella
ca4991a9f6 Fix location url from relative to absolute 2019-04-10 07:30:25 +02:00
Gianluigi 'cocciagialla' Mammarella
cdf77dacd8 Fix input naming 2019-04-10 07:29:27 +02:00
Gianluigi 'cocciagialla' Mammarella
7802a0d19f Fix Dumper. Each complext type is now wrapped inside container element tag 2019-04-10 07:28:07 +02:00
Gianluigi 'cocciagialla' Mammarella
c4118855de Fix document literal binder for request and response 2019-04-10 07:22:34 +02:00
Gianluigi 'cocciagialla' Mammarella
2771991fc0 Set document instead of rpc as default binding style 2019-04-10 07:21:51 +02:00
Gianluigi 'cocciagialla' Mammarella
ceb69d97c3 Fix binding name and soapAction attribute on wsdl 2019-04-10 07:20:49 +02:00
Gianluigi 'cocciagialla' Mammarella
19326bccdd Add .idea to ignore 2019-04-10 07:20:07 +02:00
Gianluigi 'cocciagialla' Mammarella
22bde386ab Fix composer json 2019-04-02 15:15:56 +02:00
Gianluigi 'cocciagialla' Mammarella
2d36e5f060 Fix compatibility with SF4 + Other fixes 2019-04-02 14:58:41 +02:00
Gianluigi 'cocciagialla' Mammarella
873dc0ae08 Replace DefinitionDecorator with ChildDefinition 2019-03-14 04:53:26 +01:00
Gianluigi 'cocciagialla' Mammarella
0e24ffe23d Alias dev-master 2019-03-14 04:31:19 +01:00
Gianluigi Mammarella
d0f53bc806
pdate to SF4 2019-03-14 03:24:20 +01:00
Gianluigi Mammarella
0cb00e71b5
Change package name 2019-03-14 03:05:52 +01:00
Michael Veroux
cc888bf168 Deprecated method change 2019-02-13 10:02:20 +01:00
Michael Veroux
bb95a6cb45 Response xml format change support with backward compatibility 2019-02-11 12:28:54 +01:00
Michael Veroux
3f2a99adf6 Array support change
Support of mapping xml attributes
2019-02-11 12:28:54 +01:00
Michael Veroux
ad93b5ca49 PHP 7 compatibility 2019-02-11 11:55:54 +01:00
Michael Veroux
cdeab44c2c Like this, DATETIME_FORMAT could be overriden
Partial Fix BeSimple#68
2019-02-11 11:45:50 +01:00
Michael Veroux
e046be22eb Date semantics must support milliseconds for better interoperability
Fix BeSimple#68
2019-02-11 11:39:35 +01:00
Michael Veroux
b10b5431e5 Back to original name 2019-02-11 11:33:27 +01:00
Ghislain Loaec
408d88f164 Readme typo 2018-04-06 12:07:55 +02:00
Ghislain Loaec
0e4034a093 Merge tag '0.3.0' into develop
Compatibility Symfony 3
2018-04-06 12:02:37 +02:00
Ghislain Loaec
fd64676312 Merge branch 'release/0.3.0' 2018-04-06 12:02:15 +02:00
Ghislain Loaec
4d66d072ec Bump version 0.3.0 2018-04-06 12:01:48 +02:00
Ghislain Loaec
735f6a5826 README update 2018-04-06 11:58:10 +02:00
Ghislain Loaec
498012697d get path 2018-04-06 11:32:08 +02:00
Ghislain Loaec
b96b65cc49 ComtainerAware -> Interface 2018-04-06 11:29:08 +02:00
Ghislain Loaec
0748b23630 Symfony 2 fixes 2018-04-06 11:21:50 +02:00
Ghislain Loaec
63111261e7 Restart fomr 0.2 2018-04-06 11:18:36 +02:00
Ghislain Loaec
2b91f94b8d Ignore composer.phar 2018-04-06 11:06:18 +02:00
Ghislain Loaec
1af0828b15 Revert whole code to legacy 2018-04-06 10:58:45 +02:00
Ghislain Loaec
0ca2fe1fd5 getCurrentRequest 2018-04-06 10:53:16 +02:00
Ghislain Loaec
fd923e032e cache->getPath 2018-04-06 10:50:13 +02:00
Ghislain Loaec
e32514abe4 Add Classmap (common) 2018-04-06 10:43:58 +02:00
Ghislain Loaec
7322bfefd0 Add Classmap 2018-04-06 10:40:03 +02:00
Ghislain Loaec
e232b1d8b9 ContainerAware -> ContainerAwareInterface 2018-04-06 10:20:53 +02:00
Ghislain Loaec
1b87b4d212 Fix pattern->path 2018-04-06 10:16:21 +02:00
Ghislain Loaec
ae746087e6 Test With Legacy bundle 2018-04-06 10:12:08 +02:00
Ghislain Loaec
9312e4af6a Revert "Test"
This reverts commit c3da1d545aa930393216e4fc8fff9ca3ff1ead62.
2018-04-06 10:09:28 +02:00
Ghislain Loaec
c3da1d545a Test 2018-04-06 09:58:43 +02:00
Ghislain Loaec
ad2bd7bc7a Rename fork 2018-04-04 11:52:49 +02:00
Petr Bechyně
e58927469c Run mock server in each SoapClient test case & unit test fixed 2018-02-06 00:38:35 +01:00
Petr Bechyně
45cce3a41c Integration test fixed 2018-02-06 00:31:06 +01:00
Petr Bechyně
e6beef5a80
Merge pull request #14 from tmirks/enable-symfony-bundle
Get basic bundle configuration working for SoapClient with Symfony 3.x.
2018-02-05 23:53:11 +01:00
Tim Mirecki
69a7005c35 Get basic bundle configuration working for SoapClient with Symfony 3.x. 2018-01-18 11:40:02 -05:00
milanmimra
073028f160 Merge pull request #10 from vhorky/feature/curl-ssl-version
Soap client option allows setting CURLOPT_SSLVERSION
2017-09-21 10:54:15 +02:00
VH
a9f11beb83 Soap client option allows setting CURLOPT_SSLVERSION 2017-09-21 10:45:27 +02:00
Petr Bechyně
7ab8771989 Merge pull request #7 from tuscanicz/develop
Recognizing mime boundary according to RFC
2017-08-23 16:11:19 +02:00
milamimr
d68c25daad Recognizing mime boundary according to RFC 2017-08-23 15:30:36 +02:00
Petr Bechyně
6e117940a3 ResolveRemoteIncludes fix: RelativePathResolver was not used in XmlDomDocumentImportReplacer 2017-07-24 10:11:13 +02:00
Petr Bechyně
0c47f5a8d4 RelativePathResolver did not work correctly for ../directories 2017-07-21 14:49:42 +02:00
Petr Bechyně
75a0489cce Merge remote-tracking branch 'remotes/origin/develop' 2017-07-21 10:31:28 +02:00
Petr Bechyně
de5d6a2647 SoapClientOptions now contains resolve remove includes option for WSDL downloader 2017-07-21 10:21:50 +02:00
Petr Bechyně
6970b7bbef WsdlDownloader fix: remote includes now work correctly with relative URLs & tests added 2017-07-18 18:52:52 +02:00
Petr Bechyně
b650254d54 SoapClient::trace = SoapClientOptions::SOAP_CLIENT_TRACE_OFF fixed when SoapFault is thrown
Incompatible changes: 1) Default SoapClientOptionsBuilder method now sets tracing to ON and 2) SoapResponse now contains request in all calls so that SoapRequestFactory interface had to be changed.
2017-06-16 13:42:08 +02:00
Petr Bechyně
668f2dd258 PhpUnit - code coverage whitelisted 2017-06-13 13:06:58 +02:00
Petr Bechyně
a8bc834077 Mime/PartHeaders now handle both Content-ID and Content-id according to W3 specs 2017-06-12 15:14:28 +02:00
Petr Bechyně
f74e4b08ce Mime Parser: throws Exception with MimePartMessage contents 2017-06-12 00:28:27 +02:00
Petr Bechyně
dcd5ff5234 Travis now run only PHP 7.x builds, phpstan requirements will fail on 5.6.x or previous 2017-06-07 17:10:10 +02:00
Petr Bechyně
7bd8481a4e Travis CI - test fixes
1. Travis has to run PHP build-in server separately, 2. SoapFault message expectations are now Couldn't/Could not
2017-06-07 17:05:03 +02:00
Petr Bechyně
c82288d641 Travis deployment fixed 2017-06-07 16:23:47 +02:00
Petr Bechyně
bb20882ade Readme updated 2017-06-07 16:18:46 +02:00
Petr Bechyně
2264e329a1 Added phing for running tests & fixed issues in order to pass the tests 2017-06-07 15:50:04 +02:00
Petr Bechyně
b9e36b4900 Fix notice: attribute soapClientOptions defined in Trait and Client class 2017-06-05 10:50:53 +02:00
Petr Bechyně
d495f22413 SoapFaultWithTracingData now provides request / response information from Server SoapFaults 2017-05-30 18:29:51 +02:00
Petr Bechyně
8db9b374e4 SoapFault handling refactored: client now returns server fault codes + more details in message 2017-05-26 10:53:41 +02:00
Petr Bechyně
f669c18c7f Merge pull request #3 from ceesco53/patch-1
composer.json refers to upstream not this fork (README.md fix)
2017-05-25 19:07:26 +02:00
John
524d1f3fd7 composer.json refers to upstream not this fork
Using the composer.json instructions as is will cause the rest of your instructions to fail.  It points to upstream package.  I've got some other changes coming soon.  Happy to help.
2017-05-25 12:13:58 -04:00
Petr Bechyně
ecffdc18fd Minor bugfixes of SoapFault handling
SoapFault is now properly prefixed so that SoapFaultSourceGetter identifies them correctly, missing exceptions option is now processed in SoapServer
2017-05-10 09:15:27 +02:00
Petr Bechyně
b45202f40a Project composer description update 2017-04-26 13:00:40 +02:00
Petr Bechyně
ab83642f06 Parser fix: single line MimeMessages are now parsed correctly 2017-04-06 15:51:29 +02:00
Petr Bechyně
564005da93 SoapServer/Client now handle binary files correctly & large tests/fixtures update
Soap Server and Client were breaking binary files during transfer due to invalid Mime Message Parser. Now is it working fine with no errors, but the message parser is about to be rewritten into a better form.
2017-04-04 18:36:18 +02:00
Petr Bechyně
311f9e6d08 Readme update: better examples added 2017-03-15 11:23:21 +01:00
Petr Bechyně
e67d5aa84b Readme updated 2017-03-15 10:48:23 +01:00
Petr Bechyně
d3023b1a5a UnitTests are now located in tests directory & tiny improvements 2017-03-15 10:25:48 +01:00
Petr Bechyně
21d705bbfa SoapClient custom endpoint location & connection keep alive configuration added & tests updated 2017-03-03 11:11:44 +01:00
Petr Bechyně
0e2c33faf8 Support of older PHP versions removed: MimeFilter does not sanitize PHP 5.4.x error 2017-02-22 12:23:24 +01:00
Petr Bechyně
cf6e147c26 Merge remote-tracking branch 'remotes/origin/develop' 2017-02-18 00:14:21 +01:00
Petr Bechyně
f276a30a47 Curl/WsdlGenerator - better error handling 2017-02-18 00:13:02 +01:00
Petr Bechyně
4edc46e67f Parser fix - MimeMessages with CRLF caused iconv_mime_decode throwing Exceptions 2017-02-17 15:06:06 +01:00
Petr Bechyně
a76526a5b6 DEFAULT_CONNECTION_TIMEOUT default value increased to 120 2017-02-17 11:20:09 +01:00
Petr Bechyně
baf32c1350 Curl is now returning response body even on error
It is better to switch off CURLOPT_FAILONERROR and check response status manually by HTTP response code
2017-02-17 11:07:26 +01:00
Petr Bechyně
5c0bf914e3 Unused SoapClientNativeDataTransferObject removed 2017-02-17 03:36:16 +01:00
Petr Bechyně
01d10b89fd SoapClient now handles Attachments better
The inner storage is now the only possible way to handle attachments and hydrate responses by using ClassMap at the same time. To get the response objects from ClassMap, use SoapResponse->getResponseObject() method
2017-02-17 03:19:22 +01:00
Petr Bechyně
e1b50ce914 SoapClient::__soapCall() must be compatible with \SoapClient::__soapCall() fix 2017-02-17 00:26:01 +01:00
Petr Bechyně
68b41acc46 SoapClient - WSDL download fixes 2017-02-17 00:14:05 +01:00
180 changed files with 3277 additions and 6573 deletions

5
.gitignore vendored
View File

@ -1,3 +1,6 @@
/vendor/ /vendor/
composer.lock
composer.phar
phpunit.xml phpunit.xml
.idea/ .idea
.php_cs.cache

View File

@ -1,16 +1,16 @@
language: php language: php
php: php:
- 5.3
- 5.4
- 5.5
- 5.6 - 5.6
- 7.0
- 7.1
env: env:
- SYMFONY_VERSION=2.6.* - SYMFONY_VERSION=2.8.*
- SYMFONY_VERSION="dev-master symfony/debug:~2.7@dev symfony/http-kernel:~2.7@dev" - SYMFONY_VERSION="dev-master symfony/debug:~2.8@dev symfony/http-kernel:~2.8@dev"
before_script: before_script:
- phpenv config-add myphp.ini
- composer self-update - composer self-update
- composer require symfony/framework-bundle:${SYMFONY_VERSION} --no-update - composer require symfony/framework-bundle:${SYMFONY_VERSION} --no-update
- composer update --no-interaction --prefer-source - composer update --no-interaction --prefer-source
@ -22,4 +22,4 @@ script:
matrix: matrix:
allow_failures: allow_failures:
- env: SYMFONY_VERSION="dev-master symfony/debug:~2.7@dev symfony/http-kernel:~2.7@dev" - env: SYMFONY_VERSION="dev-master symfony/debug:~2.8@dev symfony/http-kernel:~2.8@dev"

118
README.md
View File

@ -1,9 +1,30 @@
# BeSimpleSoap # BeSimpleSoap (Symfony 3.4 / 4.x)
Build SOAP and WSDL based web services. This fork provides the BeSimpleSoap bundle, updated to be compatible with Symfony 3.4 and 4.x (as well as with PHP 7.0-7.4).
This fork from 2017 is a refactored version that fixes a lot of errors and provides
better APi, more robust, stable and modern codebase. We forked the official [BeSimpleSoap](https://github.com/BeSimple/BeSimpleSoap) repository in order to sucessfully maintain some of our projects.
See [How to use](#how-to-use) that will help you to understand the magic.
We now have integrated changes and fixes from sub-forks (thank you guys!), and we should be up to date now :)
This fork is maintained by people from [Cadoles](https://www.cadoles.com/).
# Contributing
We do welcome pull requests :) please include tests if you can.
Running tests can be done by running `php vendor/bin/phpunit`.
# Installation
If you do not yet have composer, follow instructions on the [Composer website](https://getcomposer.org/download/) to install it.
Then just running:
```
$ composer require cadoles/soap
```
should be enough to get you up and running.
# Components # Components
@ -23,52 +44,25 @@ BeSimpleSoap consists of five components ...
## BeSimpleSoapWsdl ## BeSimpleSoapWsdl
Currently **unsupported!** For further information see the [README](https://github.com/BeSimple/BeSimpleSoap/blob/master/src/BeSimple/SoapWsdl/README.md). **Untouched!**
The component is not affected by refactoring so it should work properly.
For further information see the original [README](https://github.com/BeSimple/BeSimpleSoap/blob/master/src/BeSimple/SoapWsdl/README.md).
## BeSimpleSoapBundle ## BeSimpleSoapBundle
Currently **unsupported!** **Unsupported!**
The BeSimpleSoapBundle is a Symfony2 bundle to build WSDL and SOAP based web services. The BeSimpleSoapBundle is a Symfony2 bundle to build WSDL and SOAP based web services.
For further information see the the original [README](https://github.com/BeSimple/BeSimpleSoap/blob/master/src/BeSimple/SoapBundle/README.md). For further information see the the original [README](https://github.com/BeSimple/BeSimpleSoap/blob/master/src/BeSimple/SoapBundle/README.md).
*May not work properly since the Symfony libraries were removed.* *Will not work since the Symfony libraries were removed and usages of other components were not refactored. Feel free to fork this repository and fix it!*
# Installation
If you do not yet have composer, install it like this:
```sh
curl -s http://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin
```
Create a `composer.json` file:
```json
{
"require": {
"besimple/soap": "0.2.*@dev"
}
}
```
Now you are ready to install the library:
```sh
php /usr/local/bin/composer.phar install
```
# How to use # How to use
You can investigate the unit tests in order to get a clue. You can investigate the unit tests dir ``tests`` in order to get a clue.
Forget about associative arrays, multiple extension and silent errors! Forget about associative arrays, vague configurations, multiple extension and silent errors!
This may look a bit more complex at the first sight,
but it will guide you to configure and set up your client or server properly.
``` ## Example of soap client call
// unit tests for soap client
BeSimple\SoapClient\Tests\SoapClientBuilderTest
// unit tests for soap server
BeSimple\SoapServer\Tests\SoapServerBuilderTest
```
## Small example of soap client call
```php ```php
$soapClientBuilder = new SoapClientBuilder(); $soapClientBuilder = new SoapClientBuilder();
@ -84,22 +78,23 @@ var_dump($soapResponse); // Contains Response, Attachments
``` ```
### Something wrong?! ### Something wrong?!
Turn on the tracking and catch `SoapFaultWithTracingData` exception to get some sweets :) Turn on the tracking and catch `SoapFaultWithTracingData` exception to get some sweets :)
```php ```php
try { try {
$soapResponse = $soapClient->soapCall('GetUKLocationByCounty', [$getUKLocationByCountyRequest]); $soapResponse = $soapClient->soapCall('myMethod', [$myRequest]);
} catch (SoapFaultWithTracingData $fault) { } catch (SoapFaultWithTracingData $fault) {
var_dump($fault->getSoapResponseTracingData()->getLastRequest()); var_dump($fault->getSoapResponseTracingData()->getLastRequest());
} }
``` ```
In this example, a ``MyRequest`` object has been used to describe request.
Using a ClassMap, you help SoapClient to turn it into XML request.
## Small example of soap server handling ## Example of soap server handling
Starting a SOAP server is a bit more complex. Starting a SOAP server is a bit more complex.
I would suggest you to inspect SoapServer unit tests to get complete image. I recommend you to inspect SoapServer unit tests for inspiration.
But don't be scared too much, you just need to create a DummyService that will
handle your client SOAP calls.
```php ```php
$dummyService = new DummyService(); $dummyService = new DummyService();
@ -116,9 +111,36 @@ $request = $soapServer->createRequest(
$dummyService->getEndpoint(), $dummyService->getEndpoint(),
'DummyService.dummyServiceMethod', 'DummyService.dummyServiceMethod',
'text/xml;charset=UTF-8', 'text/xml;charset=UTF-8',
'<your><soap><request><here /></request></soap></your>' '<received><soap><request><here /></request></soap></received>'
); );
$response = $soapServer->handleRequest($request); $response = $soapServer->handleRequest($request);
var_dump($response); // Contains Response, Attachments var_dump($response); // Contains Response, Attachments
``` ```
In this example, a ``DummyService`` service has been used to handle request.
Using a service can help you create coherent SoapServer endpoints.
Service can hold an endpoint URL, WSDL path and a class map as associative array.
You can hold a class map as ``ClassMap`` object directly in the ``DummyService`` instead of array.
In the service you should describe SOAP methods from given WSDL.
In the example, the dummyServiceMethod is called.
The method will receive request object and return response object that are matched according to the class map.
See a simplified implementation of ``dummyServiceMethod`` to get a clue:
```php
/**
* @param DummyServiceRequest $dummyServiceRequest
* @return DummyServiceResponse
*/
public function dummyServiceMethod(DummyServiceRequest $dummyServiceRequest)
{
$response = new DummyServiceResponse();
$response->status = true;
return $response;
}
```
For further information and getting inspiration for your implementation, see the unit tests in ``tests`` dir.

2
cache/.gitignore vendored
View File

@ -1,2 +0,0 @@
*
!.gitignore

View File

@ -1,8 +1,9 @@
{ {
"name": "tuscanicz/soap", "name": "cadoles/soap",
"type": "library", "type": "library",
"description": "A fork of the abandoned besimple/soap package with added support for Symfony 3.0", "description": "Build and consume SOAP and WSDL based web services",
"keywords": ["soap", "soap server", "soap client"], "keywords": ["soap"],
"homepage": "https://github.com/Cadoles/BeSimpleSoap",
"license": "MIT", "license": "MIT",
"authors": [ "authors": [
{ {
@ -16,37 +17,37 @@
{ {
"name": "Andreas Schamberger", "name": "Andreas Schamberger",
"email": "mail@andreass.net" "email": "mail@andreass.net"
},
{
"name": "Petr Bechyně",
"email": "mail@petrbechyne.com"
} }
], ],
"require": { "require": {
"php": ">=5.3.0|>=7.0", "php": ">=7.0",
"ext-soap": "*", "ext-soap": "*",
"ext-curl": "*", "ext-curl": "*",
"ass/xmlsecurity": "~1.0", "ass/xmlsecurity": "~1.0",
"zendframework/zend-mime": "2.1.*" "symfony/framework-bundle": "~3.4|~4.0",
"symfony/twig-bundle": "~3.4|~4.0",
"laminas/laminas-mime": "~2.1"
}, },
"replace": { "replace": {
"besimple/soap-bundle": "self.version", "besimple/soap-bundle": "self.version",
"besimple/soap-client": "self.version", "besimple/soap-client": "self.version",
"besimple/soap-common": "self.version", "besimple/soap-common": "self.version",
"besimple/soap-server": "self.version", "besimple/soap-server": "self.version",
"besimple/soap-wsdl": "self.version" "besimple/soap-wsdl": "self.version",
"cocciagialla/soap": "self.version"
}, },
"require-dev": { "require-dev": {
"ext-mcrypt": "*", "mikey179/vfsstream": "~1.6.5",
"mikey179/vfsStream": "~1.0", "symfony/filesystem": "~2.3",
"phpunit/phpunit": "~4.0" "symfony/process": "~2.3",
"phpunit/phpunit": "^5.7"
}, },
"autoload": { "autoload": {
"psr-0": { "BeSimple\\": "src/" } "psr-0": { "BeSimple\\": "src/" }
}, },
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "0.4-dev" "dev-master": "5.2.0-dev"
} }
} }
} }

1349
composer.lock generated
View File

@ -1,1349 +0,0 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "7601f1ec280c086361e1deaf021f8ca1",
"content-hash": "59372f34124af17d5c35938dfffc6075",
"packages": [
{
"name": "ass/xmlsecurity",
"version": "v1.1.1",
"source": {
"type": "git",
"url": "https://github.com/aschamberger/XmlSecurity.git",
"reference": "c8976519ebbf6e4d953cd781d09df44b7f65fbb8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/aschamberger/XmlSecurity/zipball/c8976519ebbf6e4d953cd781d09df44b7f65fbb8",
"reference": "c8976519ebbf6e4d953cd781d09df44b7f65fbb8",
"shasum": ""
},
"require": {
"ext-openssl": "*",
"lib-openssl": ">=0.9.0",
"php": ">=5.3.0"
},
"require-dev": {
"satooshi/php-coveralls": "dev-master"
},
"suggest": {
"ext-mcrypt": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-0": {
"ass\\XmlSecurity": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Robert Richards",
"email": "rrichards@cdatazone.org"
},
{
"name": "Andreas Schamberger",
"email": "mail@andreass.net"
}
],
"description": "The XmlSecurity library is written in PHP for working with XML Encryption and Signatures",
"homepage": "https://github.com/aschamberger/XmlSecurity",
"keywords": [
"encryption",
"security",
"signature",
"xml"
],
"time": "2015-05-31 10:10:35"
},
{
"name": "zendframework/zend-mime",
"version": "2.1.6",
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-mime.git",
"reference": "066d6eecff586a7fb10e8907c032beaf1a9d6104"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-mime/zipball/066d6eecff586a7fb10e8907c032beaf1a9d6104",
"reference": "066d6eecff586a7fb10e8907c032beaf1a9d6104",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"zendframework/zend-stdlib": "self.version"
},
"require-dev": {
"fabpot/php-cs-fixer": "1.7.*",
"phpunit/phpunit": "~4.0",
"satooshi/php-coveralls": "dev-master",
"zendframework/zend-mail": "self.version"
},
"suggest": {
"zendframework/zend-mail": "Zend\\Mail component"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.1-dev",
"dev-develop": "2.2-dev"
}
},
"autoload": {
"psr-4": {
"Zend\\Mime\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"homepage": "https://github.com/zendframework/zend-mime",
"keywords": [
"mime",
"zf2"
],
"time": "2013-04-17 13:32:54"
},
{
"name": "zendframework/zend-stdlib",
"version": "2.1.6",
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-stdlib.git",
"reference": "0027339961ad3d49f91ee092e23f7269c18cb470"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-stdlib/zipball/0027339961ad3d49f91ee092e23f7269c18cb470",
"reference": "0027339961ad3d49f91ee092e23f7269c18cb470",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"fabpot/php-cs-fixer": "1.7.*",
"phpunit/phpunit": "~4.0",
"satooshi/php-coveralls": "dev-master",
"zendframework/zend-eventmanager": "self.version",
"zendframework/zend-filter": "self.version",
"zendframework/zend-serializer": "self.version",
"zendframework/zend-servicemanager": "self.version"
},
"suggest": {
"pecl-weakref": "Implementation of weak references for Stdlib\\CallbackHandler",
"zendframework/zend-eventmanager": "To support aggregate hydrator usage",
"zendframework/zend-filter": "To support naming strategy hydrator usage",
"zendframework/zend-serializer": "Zend\\Serializer component",
"zendframework/zend-servicemanager": "To support hydrator plugin manager usage"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.1-dev",
"dev-develop": "2.2-dev"
}
},
"autoload": {
"psr-4": {
"Zend\\Stdlib\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"homepage": "https://github.com/zendframework/zend-stdlib",
"keywords": [
"stdlib",
"zf2"
],
"time": "2013-04-17 13:32:54"
}
],
"packages-dev": [
{
"name": "doctrine/instantiator",
"version": "1.0.5",
"source": {
"type": "git",
"url": "https://github.com/doctrine/instantiator.git",
"reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d",
"reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
"shasum": ""
},
"require": {
"php": ">=5.3,<8.0-DEV"
},
"require-dev": {
"athletic/athletic": "~0.1.8",
"ext-pdo": "*",
"ext-phar": "*",
"phpunit/phpunit": "~4.0",
"squizlabs/php_codesniffer": "~2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com",
"homepage": "http://ocramius.github.com/"
}
],
"description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
"homepage": "https://github.com/doctrine/instantiator",
"keywords": [
"constructor",
"instantiate"
],
"time": "2015-06-14 21:17:01"
},
{
"name": "mikey179/vfsStream",
"version": "v1.6.4",
"source": {
"type": "git",
"url": "https://github.com/mikey179/vfsStream.git",
"reference": "0247f57b2245e8ad2e689d7cee754b45fbabd592"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mikey179/vfsStream/zipball/0247f57b2245e8ad2e689d7cee754b45fbabd592",
"reference": "0247f57b2245e8ad2e689d7cee754b45fbabd592",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "~4.5"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.6.x-dev"
}
},
"autoload": {
"psr-0": {
"org\\bovigo\\vfs\\": "src/main/php"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Frank Kleine",
"homepage": "http://frankkleine.de/",
"role": "Developer"
}
],
"description": "Virtual file system to mock the real file system in unit tests.",
"homepage": "http://vfs.bovigo.org/",
"time": "2016-07-18 14:02:57"
},
{
"name": "phpdocumentor/reflection-common",
"version": "1.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionCommon.git",
"reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
"reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
"shasum": ""
},
"require": {
"php": ">=5.5"
},
"require-dev": {
"phpunit/phpunit": "^4.6"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"phpDocumentor\\Reflection\\": [
"src"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jaap van Otterdijk",
"email": "opensource@ijaap.nl"
}
],
"description": "Common reflection classes used by phpdocumentor to reflect the code structure",
"homepage": "http://www.phpdoc.org",
"keywords": [
"FQSEN",
"phpDocumentor",
"phpdoc",
"reflection",
"static analysis"
],
"time": "2015-12-27 11:43:31"
},
{
"name": "phpdocumentor/reflection-docblock",
"version": "3.1.1",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e",
"reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e",
"shasum": ""
},
"require": {
"php": ">=5.5",
"phpdocumentor/reflection-common": "^1.0@dev",
"phpdocumentor/type-resolver": "^0.2.0",
"webmozart/assert": "^1.0"
},
"require-dev": {
"mockery/mockery": "^0.9.4",
"phpunit/phpunit": "^4.4"
},
"type": "library",
"autoload": {
"psr-4": {
"phpDocumentor\\Reflection\\": [
"src/"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mike van Riel",
"email": "me@mikevanriel.com"
}
],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"time": "2016-09-30 07:12:33"
},
{
"name": "phpdocumentor/type-resolver",
"version": "0.2.1",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb",
"reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb",
"shasum": ""
},
"require": {
"php": ">=5.5",
"phpdocumentor/reflection-common": "^1.0"
},
"require-dev": {
"mockery/mockery": "^0.9.4",
"phpunit/phpunit": "^5.2||^4.8.24"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"phpDocumentor\\Reflection\\": [
"src/"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mike van Riel",
"email": "me@mikevanriel.com"
}
],
"time": "2016-11-25 06:54:22"
},
{
"name": "phpspec/prophecy",
"version": "v1.6.2",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
"reference": "6c52c2722f8460122f96f86346600e1077ce22cb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/6c52c2722f8460122f96f86346600e1077ce22cb",
"reference": "6c52c2722f8460122f96f86346600e1077ce22cb",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.2",
"php": "^5.3|^7.0",
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
"sebastian/comparator": "^1.1",
"sebastian/recursion-context": "^1.0|^2.0"
},
"require-dev": {
"phpspec/phpspec": "^2.0",
"phpunit/phpunit": "^4.8 || ^5.6.5"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.6.x-dev"
}
},
"autoload": {
"psr-0": {
"Prophecy\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Konstantin Kudryashov",
"email": "ever.zet@gmail.com",
"homepage": "http://everzet.com"
},
{
"name": "Marcello Duarte",
"email": "marcello.duarte@gmail.com"
}
],
"description": "Highly opinionated mocking framework for PHP 5.3+",
"homepage": "https://github.com/phpspec/prophecy",
"keywords": [
"Double",
"Dummy",
"fake",
"mock",
"spy",
"stub"
],
"time": "2016-11-21 14:58:47"
},
{
"name": "phpunit/php-code-coverage",
"version": "2.2.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979",
"reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"phpunit/php-file-iterator": "~1.3",
"phpunit/php-text-template": "~1.2",
"phpunit/php-token-stream": "~1.3",
"sebastian/environment": "^1.3.2",
"sebastian/version": "~1.0"
},
"require-dev": {
"ext-xdebug": ">=2.1.4",
"phpunit/phpunit": "~4"
},
"suggest": {
"ext-dom": "*",
"ext-xdebug": ">=2.2.1",
"ext-xmlwriter": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
"homepage": "https://github.com/sebastianbergmann/php-code-coverage",
"keywords": [
"coverage",
"testing",
"xunit"
],
"time": "2015-10-06 15:47:00"
},
{
"name": "phpunit/php-file-iterator",
"version": "1.4.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
"reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
"reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "FilterIterator implementation that filters files based on a list of suffixes.",
"homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
"keywords": [
"filesystem",
"iterator"
],
"time": "2016-10-03 07:40:28"
},
{
"name": "phpunit/php-text-template",
"version": "1.2.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-text-template.git",
"reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
"reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "Simple template engine.",
"homepage": "https://github.com/sebastianbergmann/php-text-template/",
"keywords": [
"template"
],
"time": "2015-06-21 13:50:34"
},
{
"name": "phpunit/php-timer",
"version": "1.0.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-timer.git",
"reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260",
"reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4|~5"
},
"type": "library",
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Utility class for timing",
"homepage": "https://github.com/sebastianbergmann/php-timer/",
"keywords": [
"timer"
],
"time": "2016-05-12 18:03:57"
},
{
"name": "phpunit/php-token-stream",
"version": "1.4.9",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
"reference": "3b402f65a4cc90abf6e1104e388b896ce209631b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3b402f65a4cc90abf6e1104e388b896ce209631b",
"reference": "3b402f65a4cc90abf6e1104e388b896ce209631b",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Wrapper around PHP's tokenizer extension.",
"homepage": "https://github.com/sebastianbergmann/php-token-stream/",
"keywords": [
"tokenizer"
],
"time": "2016-11-15 14:06:22"
},
{
"name": "phpunit/phpunit",
"version": "4.8.34",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "7eb45205d27edd94bd2b3614085ea158bd1e2bca"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7eb45205d27edd94bd2b3614085ea158bd1e2bca",
"reference": "7eb45205d27edd94bd2b3614085ea158bd1e2bca",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-json": "*",
"ext-pcre": "*",
"ext-reflection": "*",
"ext-spl": "*",
"php": ">=5.3.3",
"phpspec/prophecy": "^1.3.1",
"phpunit/php-code-coverage": "~2.1",
"phpunit/php-file-iterator": "~1.4",
"phpunit/php-text-template": "~1.2",
"phpunit/php-timer": "^1.0.6",
"phpunit/phpunit-mock-objects": "~2.3",
"sebastian/comparator": "~1.2.2",
"sebastian/diff": "~1.2",
"sebastian/environment": "~1.3",
"sebastian/exporter": "~1.2",
"sebastian/global-state": "~1.0",
"sebastian/version": "~1.0",
"symfony/yaml": "~2.1|~3.0"
},
"suggest": {
"phpunit/php-invoker": "~1.1"
},
"bin": [
"phpunit"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.8.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "The PHP Unit Testing framework.",
"homepage": "https://phpunit.de/",
"keywords": [
"phpunit",
"testing",
"xunit"
],
"time": "2017-01-26 16:15:36"
},
{
"name": "phpunit/phpunit-mock-objects",
"version": "2.3.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
"reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983",
"reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.2",
"php": ">=5.3.3",
"phpunit/php-text-template": "~1.2",
"sebastian/exporter": "~1.2"
},
"require-dev": {
"phpunit/phpunit": "~4.4"
},
"suggest": {
"ext-soap": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.3.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Mock Object library for PHPUnit",
"homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
"keywords": [
"mock",
"xunit"
],
"time": "2015-10-02 06:51:40"
},
{
"name": "sebastian/comparator",
"version": "1.2.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
"reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
"reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"sebastian/diff": "~1.2",
"sebastian/exporter": "~1.2 || ~2.0"
},
"require-dev": {
"phpunit/phpunit": "~4.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Jeff Welch",
"email": "whatthejeff@gmail.com"
},
{
"name": "Volker Dusch",
"email": "github@wallbash.com"
},
{
"name": "Bernhard Schussek",
"email": "bschussek@2bepublished.at"
},
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Provides the functionality to compare PHP values for equality",
"homepage": "http://www.github.com/sebastianbergmann/comparator",
"keywords": [
"comparator",
"compare",
"equality"
],
"time": "2017-01-29 09:50:25"
},
{
"name": "sebastian/diff",
"version": "1.4.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
"reference": "13edfd8706462032c2f52b4b862974dd46b71c9e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e",
"reference": "13edfd8706462032c2f52b4b862974dd46b71c9e",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.8"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Kore Nordmann",
"email": "mail@kore-nordmann.de"
},
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Diff implementation",
"homepage": "https://github.com/sebastianbergmann/diff",
"keywords": [
"diff"
],
"time": "2015-12-08 07:14:41"
},
{
"name": "sebastian/environment",
"version": "1.3.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
"reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea",
"reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea",
"shasum": ""
},
"require": {
"php": "^5.3.3 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8 || ^5.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Provides functionality to handle HHVM/PHP environments",
"homepage": "http://www.github.com/sebastianbergmann/environment",
"keywords": [
"Xdebug",
"environment",
"hhvm"
],
"time": "2016-08-18 05:49:44"
},
{
"name": "sebastian/exporter",
"version": "1.2.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "42c4c2eec485ee3e159ec9884f95b431287edde4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4",
"reference": "42c4c2eec485ee3e159ec9884f95b431287edde4",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"sebastian/recursion-context": "~1.0"
},
"require-dev": {
"ext-mbstring": "*",
"phpunit/phpunit": "~4.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Jeff Welch",
"email": "whatthejeff@gmail.com"
},
{
"name": "Volker Dusch",
"email": "github@wallbash.com"
},
{
"name": "Bernhard Schussek",
"email": "bschussek@2bepublished.at"
},
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
},
{
"name": "Adam Harvey",
"email": "aharvey@php.net"
}
],
"description": "Provides the functionality to export PHP variables for visualization",
"homepage": "http://www.github.com/sebastianbergmann/exporter",
"keywords": [
"export",
"exporter"
],
"time": "2016-06-17 09:04:28"
},
{
"name": "sebastian/global-state",
"version": "1.1.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
"reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4",
"reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.2"
},
"suggest": {
"ext-uopz": "*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
}
],
"description": "Snapshotting of global state",
"homepage": "http://www.github.com/sebastianbergmann/global-state",
"keywords": [
"global state"
],
"time": "2015-10-12 03:26:01"
},
{
"name": "sebastian/recursion-context",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/recursion-context.git",
"reference": "913401df809e99e4f47b27cdd781f4a258d58791"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791",
"reference": "913401df809e99e4f47b27cdd781f4a258d58791",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Jeff Welch",
"email": "whatthejeff@gmail.com"
},
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de"
},
{
"name": "Adam Harvey",
"email": "aharvey@php.net"
}
],
"description": "Provides functionality to recursively process PHP variables",
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
"time": "2015-11-11 19:50:13"
},
{
"name": "sebastian/version",
"version": "1.0.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/version.git",
"reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
"reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
"shasum": ""
},
"type": "library",
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
"homepage": "https://github.com/sebastianbergmann/version",
"time": "2015-06-21 13:59:46"
},
{
"name": "symfony/yaml",
"version": "v3.2.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "50eadbd7926e31842893c957eca362b21592a97d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/50eadbd7926e31842893c957eca362b21592a97d",
"reference": "50eadbd7926e31842893c957eca362b21592a97d",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"require-dev": {
"symfony/console": "~2.8|~3.0"
},
"suggest": {
"symfony/console": "For validating YAML files using the lint command"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.2-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Yaml\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
"time": "2017-01-03 13:51:32"
},
{
"name": "webmozart/assert",
"version": "1.2.0",
"source": {
"type": "git",
"url": "https://github.com/webmozart/assert.git",
"reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f",
"reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f",
"shasum": ""
},
"require": {
"php": "^5.3.3 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.6",
"sebastian/version": "^1.0.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3-dev"
}
},
"autoload": {
"psr-4": {
"Webmozart\\Assert\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Bernhard Schussek",
"email": "bschussek@gmail.com"
}
],
"description": "Assertions to validate method input/output with nice error messages.",
"keywords": [
"assert",
"check",
"validate"
],
"time": "2016-11-23 20:04:58"
}
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=5.3.0|>=7.0",
"ext-soap": "*",
"ext-curl": "*"
},
"platform-dev": {
"ext-mcrypt": "*"
}
}

View File

@ -9,7 +9,6 @@
processIsolation="false" processIsolation="false"
stopOnFailure="false" stopOnFailure="false"
syntaxCheck="false" syntaxCheck="false"
stderr="true"
bootstrap="vendor/autoload.php" bootstrap="vendor/autoload.php"
> >
@ -19,8 +18,17 @@
<testsuites> <testsuites>
<testsuite name="BeSimpleSoap Test Suite"> <testsuite name="BeSimpleSoap Test Suite">
<file>src/BeSimple/SoapClient/Tests/SoapClientBuilderTest.php</file> <directory>./src/BeSimple/*/Tests/</directory>
<file>src/BeSimple/SoapServer/Tests/SoapServerBuilderTest.php</file>
</testsuite> </testsuite>
</testsuites> </testsuites>
<filter>
<whitelist>
<directory>./src/BeSimple/</directory>
<exclude>
<directory>./src/BeSimple/*/Tests</directory>
<directory>./src/BeSimple/*/Resources</directory>
</exclude>
</whitelist>
</filter>
</phpunit> </phpunit>

View File

@ -1,3 +1,4 @@
vendor/ vendor/
composer.lock composer.lock
phpunit.xml phpunit.xml
.idea/

View File

@ -13,45 +13,27 @@
namespace BeSimple\SoapBundle; namespace BeSimple\SoapBundle;
use BeSimple\SoapCommon\Cache as BaseCache; use BeSimple\SoapCommon\Cache as BaseCache;
use BeSimple\SoapCommon\SoapOptions\SoapOptions;
use Exception;
/** /**
* @author Francis Besset <francis.besset@gmail.com> * @author Francis Besset <francis.besset@gmail.com>
*/ */
class Cache class Cache
{ {
public function __construct(SoapOptions $soapOptions) public function __construct($cacheDisabled, $type, $directory, $lifetime = null, $limit = null)
{ {
if ($soapOptions->isWsdlCached()) { $isEnabled = (Boolean) $cacheDisabled ? BaseCache::DISABLED : BaseCache::ENABLED;
$isEnabled = (bool)$soapOptions->isWsdlCached() ? BaseCache::ENABLED : BaseCache::DISABLED;
BaseCache::setEnabled($isEnabled); BaseCache::setEnabled($isEnabled);
BaseCache::setType($soapOptions->getWsdlCacheType());
BaseCache::setDirectory($soapOptions->getWsdlCacheDir()); BaseCache::setType($type);
} else { BaseCache::setDirectory($directory);
BaseCache::setEnabled(BaseCache::DISABLED);
BaseCache::setType(SoapOptions::SOAP_CACHE_TYPE_NONE); if (null !== $lifetime) {
BaseCache::setDirectory(null); BaseCache::setLifetime($lifetime);
}
} }
public function validateSettings(SoapOptions $soapOptions) if (null !== $limit) {
{ BaseCache::setLimit($limit);
if ($soapOptions->isWsdlCached()) {
if (BaseCache::isEnabled() !== true) {
throw new Exception('WSDL cache could not be set');
}
if ($soapOptions->getWsdlCacheType() !== (int)BaseCache::getType()) {
throw new Exception('WSDL cache type could not be set, ini settings is: '.BaseCache::getType());
}
if ($soapOptions->getWsdlCacheDir() !== BaseCache::getDirectory()) {
throw new Exception('WSDL cache dir could not be set, real dir is: '.BaseCache::getDirectory());
}
} else {
if (BaseCache::isEnabled() !== false) {
throw new Exception('WSDL cache could not be turned off');
}
} }
} }
} }

View File

@ -15,15 +15,17 @@ namespace BeSimple\SoapBundle\Controller;
use BeSimple\SoapBundle\Handler\ExceptionHandler; use BeSimple\SoapBundle\Handler\ExceptionHandler;
use BeSimple\SoapBundle\Soap\SoapRequest; use BeSimple\SoapBundle\Soap\SoapRequest;
use BeSimple\SoapBundle\Soap\SoapResponse; use BeSimple\SoapBundle\Soap\SoapResponse;
use BeSimple\SoapBundle\WebServiceContext;
use BeSimple\SoapServer\SoapServerBuilder; use BeSimple\SoapServer\SoapServerBuilder;
use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait; use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
/** /**
* @author Christian Kerl <christian-kerl@web.de> * @author Christian Kerl <christian-kerl@web.de>
@ -56,13 +58,14 @@ class SoapWebServiceController implements ContainerAwareInterface
/** /**
* @var array * @var array
*/ */
private $headers = array(); private $headers = [];
/** /**
* @return \BeSimple\SoapBundle\Soap\SoapResponse * @return \BeSimple\SoapBundle\Soap\SoapResponse
*/ */
public function callAction($webservice) public function callAction($webservice)
{ {
/** @var WebServiceContext $webServiceContext */
$webServiceContext = $this->getWebServiceContext($webservice); $webServiceContext = $this->getWebServiceContext($webservice);
$this->serviceBinder = $webServiceContext->getServiceBinder(); $this->serviceBinder = $webServiceContext->getServiceBinder();
@ -86,19 +89,26 @@ class SoapWebServiceController implements ContainerAwareInterface
} }
/** /**
* @return Symfony\Component\HttpFoundation\Response * @return Response
*/ */
public function definitionAction($webservice) public function definitionAction($webservice)
{ {
$routeName = $webservice.'_webservice_call';
$result = $this->container->get('router')->getRouteCollection()->get($routeName);
if (null === $result) {
$routeName = '_webservice_call';
}
$response = new Response($this->getWebServiceContext($webservice)->getWsdlFileContent( $response = new Response($this->getWebServiceContext($webservice)->getWsdlFileContent(
$this->container->get('router')->generate( $this->container->get('router')->generate(
'_webservice_call', $routeName,
array('webservice' => $webservice), ['webservice' => $webservice],
true UrlGeneratorInterface::ABSOLUTE_URL
) )
)); ));
$request = $this->container->get('request'); /** @var Request $request */
$request = $this->container->get('request_stack')->getCurrentRequest();
$query = $request->query; $query = $request->query;
if ($query->has('wsdl') || $query->has('WSDL')) { if ($query->has('wsdl') || $query->has('WSDL')) {
$request->setRequestFormat('wsdl'); $request->setRequestFormat('wsdl');
@ -124,14 +134,14 @@ class SoapWebServiceController implements ContainerAwareInterface
throw new \LogicException(sprintf('The parameter "%s" is required in Request::$query parameter bag to generate the SoapFault.', '_besimple_soap_webservice'), null, $e); throw new \LogicException(sprintf('The parameter "%s" is required in Request::$query parameter bag to generate the SoapFault.', '_besimple_soap_webservice'), null, $e);
} }
$view = 'TwigBundle:Exception:'.($this->container->get('kernel')->isDebug() ? 'exception' : 'error').'.txt.twig'; $view = '@Twig/Exception/'.($this->container->get('kernel')->isDebug() ? 'exception' : 'error').'.txt.twig';
$code = $exception->getStatusCode(); $code = $exception->getStatusCode();
$details = $this->container->get('templating')->render($view, array( $details = $this->container->get('twig')->render($view, [
'status_code' => $code, 'status_code' => $code,
'status_text' => isset(Response::$statusTexts[$code]) ? Response::$statusTexts[$code] : '', 'status_text' => isset(Response::$statusTexts[$code]) ? Response::$statusTexts[$code] : '',
'exception' => $exception, 'exception' => $exception,
'logger' => $logger, 'logger' => $logger,
)); ]);
$handler = new ExceptionHandler($exception, $details); $handler = new ExceptionHandler($exception, $details);
if ($soapFault = $request->query->get('_besimple_soap_fault')) { if ($soapFault = $request->query->get('_besimple_soap_fault')) {
@ -141,8 +151,8 @@ class SoapWebServiceController implements ContainerAwareInterface
$request->query->remove('_besimple_soap_fault'); $request->query->remove('_besimple_soap_fault');
} }
$server = SoapServerBuilder::createWithDefaults(__DIR__.'/../Handler/wsdl/exception.wsdl') $server = SoapServerBuilder::createWithDefaults()
->withWsdl() ->withWsdl(__DIR__.'/../Handler/wsdl/exception.wsdl')
->withWsdlCacheNone() ->withWsdlCacheNone()
->withHandler($handler) ->withHandler($handler)
->build() ->build()
@ -223,7 +233,7 @@ class SoapWebServiceController implements ContainerAwareInterface
} }
/** /**
* Set the SoapResponse * Set the SoapResponse.
* *
* @param Response $response A response to check and set * @param Response $response A response to check and set
* *
@ -240,7 +250,7 @@ class SoapWebServiceController implements ContainerAwareInterface
return $this->soapResponse = $response; return $this->soapResponse = $response;
} }
private function getWebServiceContext($webservice) protected function getWebServiceContext($webservice)
{ {
$context = sprintf('besimple.soap.context.%s', $webservice); $context = sprintf('besimple.soap.context.%s', $webservice);

View File

@ -48,7 +48,7 @@ class TypeRepository
public function fixTypeInformation(ServiceDefinition $definition) public function fixTypeInformation(ServiceDefinition $definition)
{ {
foreach($definition->getAllTypes() as $type) { foreach ($definition->getAllTypes() as $type) {
$phpType = $type->getPhpType(); $phpType = $type->getPhpType();
$xmlType = $type->getXmlType(); $xmlType = $type->getXmlType();

View File

@ -12,7 +12,7 @@ namespace BeSimple\SoapBundle\Converter;
use BeSimple\SoapBundle\Soap\SoapRequest; use BeSimple\SoapBundle\Soap\SoapRequest;
use BeSimple\SoapBundle\Soap\SoapResponse; use BeSimple\SoapBundle\Soap\SoapResponse;
use BeSimple\SoapBundle\Util\String; use BeSimple\SoapBundle\Util\BsString;
use BeSimple\SoapCommon\Converter\TypeConverterInterface; use BeSimple\SoapCommon\Converter\TypeConverterInterface;
/** /**
@ -40,7 +40,7 @@ class XopIncludeTypeConverter implements TypeConverterInterface
$ref = $include->getAttribute('href'); $ref = $include->getAttribute('href');
if (String::startsWith($ref, 'cid:')) { if (BsString::startsWith($ref, 'cid:')) {
$cid = urldecode(substr($ref, 4)); $cid = urldecode(substr($ref, 4));
return $request->getSoapAttachments()->get($cid)->getContent(); return $request->getSoapAttachments()->get($cid)->getContent();

View File

@ -17,10 +17,11 @@ use BeSimple\SoapCommon\Cache;
use Symfony\Component\Config\Definition\Processor; use Symfony\Component\Config\Definition\Processor;
use Symfony\Component\Config\FileLocator; use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\DefinitionDecorator; use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\HttpKernel\Kernel;
/** /**
* BeSimpleSoapExtension. * BeSimpleSoapExtension.
@ -59,7 +60,7 @@ class BeSimpleSoapExtension extends Extension
$container->setParameter('besimple.soap.definition.dumper.options.stylesheet', $config['wsdl_dumper']['stylesheet']); $container->setParameter('besimple.soap.definition.dumper.options.stylesheet', $config['wsdl_dumper']['stylesheet']);
foreach($config['services'] as $name => $serviceConfig) { foreach ($config['services'] as $name => $serviceConfig) {
$serviceConfig['name'] = $name; $serviceConfig['name'] = $name;
$this->createWebServiceContext($serviceConfig, $container); $this->createWebServiceContext($serviceConfig, $container);
} }
@ -80,10 +81,14 @@ class BeSimpleSoapExtension extends Extension
private function registerClientConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader) private function registerClientConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
{ {
if (3 === Kernel::MAJOR_VERSION) {
$loader->load('client3.xml');
} else {
$loader->load('client.xml'); $loader->load('client.xml');
}
foreach ($config as $client => $options) { foreach ($config as $client => $options) {
$definition = new DefinitionDecorator('besimple.soap.client.builder'); $definition = new ChildDefinition('besimple.soap.client.builder');
$container->setDefinition(sprintf('besimple.soap.client.builder.%s', $client), $definition); $container->setDefinition(sprintf('besimple.soap.client.builder.%s', $client), $definition);
$definition->replaceArgument(0, $options['wsdl']); $definition->replaceArgument(0, $options['wsdl']);
@ -130,7 +135,7 @@ class BeSimpleSoapExtension extends Extension
private function createClientClassmap($client, array $classmap, ContainerBuilder $container) private function createClientClassmap($client, array $classmap, ContainerBuilder $container)
{ {
$definition = new DefinitionDecorator('besimple.soap.classmap'); $definition = new ChildDefinition('besimple.soap.classmap');
$container->setDefinition(sprintf('besimple.soap.classmap.%s', $client), $definition); $container->setDefinition(sprintf('besimple.soap.classmap.%s', $client), $definition);
if (!empty($classmap)) { if (!empty($classmap)) {
@ -144,13 +149,18 @@ class BeSimpleSoapExtension extends Extension
private function createClient($client, ContainerBuilder $container) private function createClient($client, ContainerBuilder $container)
{ {
$definition = new DefinitionDecorator('besimple.soap.client'); $definition = new ChildDefinition('besimple.soap.client');
$container->setDefinition(sprintf('besimple.soap.client.%s', $client), $definition); $container->setDefinition(sprintf('besimple.soap.client.%s', $client), $definition);
if (Kernel::MAJOR_VERSION >= 3) {
$definition->setFactory(array( $definition->setFactory(array(
new Reference(sprintf('besimple.soap.client.builder.%s', $client)), new Reference(sprintf('besimple.soap.client.builder.%s', $client)),
'build' 'build'
)); ));
$definition->setPublic(true);
} else {
$definition->setFactoryService(sprintf('besimple.soap.client.builder.%s', $client));
}
} }
private function createWebServiceContext(array $config, ContainerBuilder $container) private function createWebServiceContext(array $config, ContainerBuilder $container)
@ -159,7 +169,7 @@ class BeSimpleSoapExtension extends Extension
unset($config['binding']); unset($config['binding']);
$contextId = 'besimple.soap.context.'.$config['name']; $contextId = 'besimple.soap.context.'.$config['name'];
$definition = new DefinitionDecorator('besimple.soap.context.'.$bindingSuffix); $definition = new ChildDefinition('besimple.soap.context.'.$bindingSuffix);
$container->setDefinition($contextId, $definition); $container->setDefinition($contextId, $definition);
if (isset($config['cache_type'])) { if (isset($config['cache_type'])) {
@ -168,6 +178,7 @@ class BeSimpleSoapExtension extends Extension
$options = $container $options = $container
->getDefinition('besimple.soap.context.'.$bindingSuffix) ->getDefinition('besimple.soap.context.'.$bindingSuffix)
->setPublic(true)
->getArgument(2); ->getArgument(2);
$definition->replaceArgument(2, array_merge($options, $config)); $definition->replaceArgument(2, array_merge($options, $config));

View File

@ -96,8 +96,12 @@ class Configuration
->info('proxy configuration') ->info('proxy configuration')
->addDefaultsIfNotSet() ->addDefaultsIfNotSet()
->beforeNormalization() ->beforeNormalization()
->ifTrue(function ($v) { return !is_array($v); }) ->ifTrue(function ($v) {
->then(function ($v) { return array('host' => null === $v ? false : $v); }) return !is_array($v);
})
->then(function ($v) {
return array('host' => null === $v ? false : $v);
})
->end() ->end()
->children() ->children()
->scalarNode('host')->defaultFalse()->end() ->scalarNode('host')->defaultFalse()->end()

View File

@ -20,7 +20,7 @@
</service> </service>
<service id="besimple.soap.client" class="%besimple.soap.client.builder.class%" abstract="true"> <service id="besimple.soap.client" class="%besimple.soap.client.builder.class%" abstract="true">
<factory class="besimple.soap.client.builder" method="build" /> <factory service="besimple.soap.client.builder" method="build" />
</service> </service>
<service id="besimple.soap.classmap" class="%besimple.soap.classmap.class%" abstract="true" /> <service id="besimple.soap.classmap" class="%besimple.soap.classmap.class%" abstract="true" />

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="besimple.soap.client.builder.class">BeSimple\SoapBundle\Soap\SoapClientBuilder</parameter>
<parameter key="besimple.soap.classmap.class">BeSimple\SoapCommon\Classmap</parameter>
</parameters>
<services>
<service id="besimple.soap.client.builder" class="%besimple.soap.client.builder.class%" abstract="true">
<argument /> <!-- wsdl URI -->
<argument type="collection">
<argument key="debug">%kernel.debug%</argument>
</argument>
<argument type="service" id="besimple.soap.classmap" />
<argument type="service" id="besimple.soap.converter.collection" />
<argument type="service" id="besimple.soap.cache" /> <!-- hack to load besimple cache configuration -->
</service>
<service id="besimple.soap.client" class="%besimple.soap.client.builder.class%" abstract="true">
<factory service="besimple.soap.client.builder" method="build" />
</service>
<service id="besimple.soap.classmap" class="%besimple.soap.classmap.class%" abstract="true" />
</services>
</container>

View File

@ -4,15 +4,13 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd"> xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
<route id="_webservice_call" path="/{webservice}"> <route id="_webservice_call" path="/{webservice}" methods="POST">
<default key="_controller">BeSimpleSoapBundle:SoapWebService:Call</default> <default key="_controller">BeSimpleSoapBundle:SoapWebService:Call</default>
<default key="_format">xml</default> <default key="_format">xml</default>
<requirement key="_method">POST</requirement>
</route> </route>
<route id="_webservice_definition" path="/{webservice}"> <route id="_webservice_definition" path="/{webservice}" methods="GET">
<default key="_controller">BeSimpleSoapBundle:SoapWebService:Definition</default> <default key="_controller">BeSimpleSoapBundle:SoapWebService:Definition</default>
<default key="_format">xml</default> <default key="_format">xml</default>
<requirement key="_method">GET</requirement>
</route> </route>
</routes> </routes>

View File

@ -19,7 +19,7 @@
</parameters> </parameters>
<services> <services>
<service id="besimple.soap.response" class="%besimple.soap.response.class%" /> <service id="besimple.soap.response" class="%besimple.soap.response.class%" public="true" />
<service id="besimple.soap.response.listener" class="%besimple.soap.response.listener.class%"> <service id="besimple.soap.response.listener" class="%besimple.soap.response.listener.class%">
<tag name="kernel.event_listener" event="kernel.view" method="onKernelView" /> <tag name="kernel.event_listener" event="kernel.view" method="onKernelView" />
@ -96,6 +96,14 @@
<argument>dateTime</argument> <argument>dateTime</argument>
<argument>xsd:dateTime</argument> <argument>xsd:dateTime</argument>
</call> </call>
<call method="addType">
<argument>base64Binary</argument>
<argument>xsd:base64Binary</argument>
</call>
<call method="addType">
<argument>hexBinary</argument>
<argument>xsd:hexBinary</argument>
</call>
</service> </service>
</services> </services>

View File

@ -0,0 +1,33 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (c) Christian Kerl <christian-kerl@web.de>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace BeSimple\SoapBundle\ServiceBinding;
use BeSimple\SoapBundle\ServiceDefinition\Method;
use BeSimple\SoapCommon\Definition\Type\TypeRepository;
/**
* @author Francis Besset <francis.besset@gmail.com>
*/
class DocumentLiteralWrappedRequestHeaderMessageBinder extends DocumentLiteralWrappedRequestMessageBinder
{
private $header;
public function setHeader($header)
{
$this->header = $header;
}
public function processMessage(Method $messageDefinition, $message, TypeRepository $typeRepository)
{
$headerDefinition = $messageDefinition->getHeaders()->get($this->header);
return [];
}
}

View File

@ -11,23 +11,24 @@
namespace BeSimple\SoapBundle\ServiceBinding; namespace BeSimple\SoapBundle\ServiceBinding;
use BeSimple\SoapBundle\ServiceDefinition\Method; use BeSimple\SoapBundle\ServiceDefinition\Method;
use BeSimple\SoapCommon\Definition\Type\TypeRepository;
/** /**
* @author Christian Kerl <christian-kerl@web.de> * @author Christian Kerl <christian-kerl@web.de>
*/ */
class DocumentLiteralWrappedRequestMessageBinder implements MessageBinderInterface class DocumentLiteralWrappedRequestMessageBinder implements MessageBinderInterface
{ {
public function processMessage(Method $messageDefinition, $message) public function processMessage(Method $messageDefinition, $message, TypeRepository $typeRepository)
{ {
if(count($message) > 1) { if (count($message) > 1) {
throw new \InvalidArgumentException(); throw new \InvalidArgumentException();
} }
$result = array(); $result = array();
$message = $message[0]; $message = $message[0];
foreach($messageDefinition->getArguments() as $argument) { foreach ($messageDefinition->getInput()->all() as $argument) {
$result[$argument->getName()] = $message->{$argument->getName()}; $result[$argument->getName()] = $message;
} }
return $result; return $result;

View File

@ -11,17 +11,15 @@
namespace BeSimple\SoapBundle\ServiceBinding; namespace BeSimple\SoapBundle\ServiceBinding;
use BeSimple\SoapBundle\ServiceDefinition\Method; use BeSimple\SoapBundle\ServiceDefinition\Method;
use BeSimple\SoapCommon\Definition\Type\TypeRepository;
/** /**
* @author Christian Kerl <christian-kerl@web.de> * @author Christian Kerl <christian-kerl@web.de>
*/ */
class DocumentLiteralWrappedResponseMessageBinder implements MessageBinderInterface class DocumentLiteralWrappedResponseMessageBinder implements MessageBinderInterface
{ {
public function processMessage(Method $messageDefinition, $message) public function processMessage(Method $messageDefinition, $message, TypeRepository $typeRepository)
{ {
$result = new \stdClass(); return $message;
$result->{$messageDefinition->getName().'Result'} = $message;
return $result;
} }
} }

View File

@ -24,5 +24,5 @@ interface MessageBinderInterface
* *
* @return mixed * @return mixed
*/ */
function processMessage(Method $messageDefinition, $message, TypeRepository $typeRepository); public function processMessage(Method $messageDefinition, $message, TypeRepository $typeRepository);
} }

View File

@ -32,7 +32,10 @@ class RpcLiteralResponseMessageBinder implements MessageBinderInterface
{ {
$this->typeRepository = $typeRepository; $this->typeRepository = $typeRepository;
return $this->processType($messageDefinition->getOutput()->get('return')->getType(), $message); $parts = $messageDefinition->getOutput()->all();
$part = array_shift($parts);
return $this->processType($part->getType(), $message);
} }
private function processType($phpType, $message) private function processType($phpType, $message)

View File

@ -44,7 +44,8 @@ class ServiceBinder
* @param MessageBinderInterface $requestMessageBinder * @param MessageBinderInterface $requestMessageBinder
* @param MessageBinderInterface $responseMessageBinder * @param MessageBinderInterface $responseMessageBinder
*/ */
public function __construct(Definition $definition, MessageBinderInterface $requestHeaderMessageBinder, MessageBinderInterface $requestMessageBinder, MessageBinderInterface $responseMessageBinder) { public function __construct(Definition $definition, MessageBinderInterface $requestHeaderMessageBinder, MessageBinderInterface $requestMessageBinder, MessageBinderInterface $responseMessageBinder)
{
$this->definition = $definition; $this->definition = $definition;
$this->requestHeaderMessageBinder = $requestHeaderMessageBinder; $this->requestHeaderMessageBinder = $requestHeaderMessageBinder;

View File

@ -18,6 +18,7 @@ class ComplexType extends Configuration
private $name; private $name;
private $value; private $value;
private $isNillable = false; private $isNillable = false;
private $minOccurs = 1;
public function getName() public function getName()
{ {
@ -34,6 +35,11 @@ class ComplexType extends Configuration
return $this->isNillable; return $this->isNillable;
} }
public function getIsNillable()
{
return $this->isNillable;
}
public function setName($name) public function setName($name)
{ {
$this->name = $name; $this->name = $name;
@ -49,6 +55,21 @@ class ComplexType extends Configuration
$this->isNillable = (bool) $isNillable; $this->isNillable = (bool) $isNillable;
} }
public function setIsNillable($isNillable)
{
$this->isNillable = (bool) $isNillable;
}
public function setMinOccurs($minOccurs)
{
$this->minOccurs = $minOccurs;
}
public function getMinOccurs()
{
return $this->minOccurs;
}
public function getAliasName() public function getAliasName()
{ {
return 'complextype'; return 'complextype';

View File

@ -22,5 +22,5 @@ interface ConfigurationInterface
* *
* @return string * @return string
*/ */
function getAliasName(); public function getAliasName();
} }

View File

@ -12,8 +12,8 @@ namespace BeSimple\SoapBundle\ServiceDefinition\Annotation;
interface TypedElementInterface interface TypedElementInterface
{ {
function getPhpType(); public function getPhpType();
function getXmlType(); public function getXmlType();
function setPhpType($phpType); public function setPhpType($phpType);
function setXmlType($xmlType); public function setXmlType($xmlType);
} }

View File

@ -20,6 +20,7 @@ class ComplexType
private $name; private $name;
private $value; private $value;
private $isNillable = false; private $isNillable = false;
private $minOccurs = 1;
public function getName() public function getName()
{ {
@ -50,4 +51,14 @@ class ComplexType
{ {
$this->isNillable = (bool) $isNillable; $this->isNillable = (bool) $isNillable;
} }
public function setMinOccurs($minOccurs)
{
$this->minOccurs = $minOccurs;
}
public function getMinOccurs()
{
return $this->minOccurs;
}
} }

View File

@ -96,6 +96,7 @@ class AnnotationClassLoader extends Loader
} }
$serviceReturn = $annotation->getPhpType(); $serviceReturn = $annotation->getPhpType();
$serviceXmlReturn = $annotation->getXmlType();
} }
} }
@ -116,7 +117,11 @@ class AnnotationClassLoader extends Loader
throw new \LogicException(sprintf('@Soap\Result non-existent for "%s".', $method->getName())); throw new \LogicException(sprintf('@Soap\Result non-existent for "%s".', $method->getName()));
} }
$serviceMethod->setOutput($this->loadType($serviceReturn)); if (!isset($serviceXmlReturn) || !$serviceXmlReturn) {
$serviceXmlReturn = 'return';
}
$serviceMethod->setOutput($this->loadType($serviceReturn), $serviceXmlReturn);
$definition->addMethod($serviceMethod); $definition->addMethod($serviceMethod);
} }
@ -133,7 +138,7 @@ class AnnotationClassLoader extends Loader
*/ */
private function getController(\ReflectionClass $class, \ReflectionMethod $method, Annotation\Method $annotation) private function getController(\ReflectionClass $class, \ReflectionMethod $method, Annotation\Method $annotation)
{ {
if(null !== $annotation->getService()) { if (null !== $annotation->getService()) {
return $annotation->getService() . ':' . $method->name; return $annotation->getService() . ':' . $method->name;
} else { } else {
return $class->name . '::' . $method->name; return $class->name . '::' . $method->name;
@ -155,7 +160,7 @@ class AnnotationClassLoader extends Loader
$loaded = $complexTypeResolver->load($phpType); $loaded = $complexTypeResolver->load($phpType);
$complexType = new ComplexType($phpType, isset($loaded['alias']) ? $loaded['alias'] : $phpType); $complexType = new ComplexType($phpType, isset($loaded['alias']) ? $loaded['alias'] : $phpType);
foreach ($loaded['properties'] as $name => $property) { foreach ($loaded['properties'] as $name => $property) {
$complexType->add($name, $this->loadType($property->getValue()), $property->isNillable()); $complexType->add($name, $this->loadType($property->getValue()), $property->isNillable(), $property->getMinOccurs());
} }
$this->typeRepository->addComplexType($complexType); $this->typeRepository->addComplexType($complexType);

View File

@ -43,7 +43,7 @@ class AnnotationComplexTypeLoader extends AnnotationClassLoader
throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class)); throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
} }
$annotations = array(); $annotations = [];
$class = new \ReflectionClass($class); $class = new \ReflectionClass($class);
if ($alias = $this->reader->getClassAnnotation($class, $this->aliasClass)) { if ($alias = $this->reader->getClassAnnotation($class, $this->aliasClass)) {
@ -59,6 +59,7 @@ class AnnotationComplexTypeLoader extends AnnotationClassLoader
$propertyComplexType->setValue($complexType->getValue()); $propertyComplexType->setValue($complexType->getValue());
$propertyComplexType->setNillable($complexType->isNillable()); $propertyComplexType->setNillable($complexType->isNillable());
$propertyComplexType->setName($property->getName()); $propertyComplexType->setName($property->getName());
$propertyComplexType->setMinOccurs($complexType->getMinOccurs());
$annotations['properties']->add($propertyComplexType); $annotations['properties']->add($propertyComplexType);
} }
} }
@ -72,7 +73,7 @@ class AnnotationComplexTypeLoader extends AnnotationClassLoader
* @param mixed $resource A resource * @param mixed $resource A resource
* @param string $type The resource type * @param string $type The resource type
* *
* @return Boolean True if this class supports the given resource, false otherwise * @return bool True if this class supports the given resource, false otherwise
*/ */
public function supports($resource, $type = null) public function supports($resource, $type = null)
{ {

View File

@ -1,36 +0,0 @@
<?php
namespace BeSimple\SoapBundle\Soap;
class SoapAttachmentList
{
private $soapAttachments;
/**
* @param SoapAttachment[] $soapAttachments
*/
public function __construct(array $soapAttachments = [])
{
$this->soapAttachments = $soapAttachments;
}
public function hasSoapAttachments()
{
return $this->soapAttachments !== null && count($this->soapAttachments) > 0;
}
public function getSoapAttachments()
{
return $this->soapAttachments;
}
public function getSoapAttachmentIds()
{
$ids = [];
foreach ($this->getSoapAttachments() as $soapAttachment) {
$ids[] = $soapAttachment->getId();
}
return $ids;
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace BeSimple\SoapBundle\Soap;
use BeSimple\SoapCommon\Classmap;
use BeSimple\SoapCommon\Converter\TypeConverterCollection;
use BeSimple\SoapClient\SoapClientBuilder as BaseSoapClientBuilder;
class SoapClientBuilder extends BaseSoapClientBuilder
{
protected $soapClient;
public function __construct($wsdl, array $options, Classmap $classmap = null, TypeConverterCollection $converters = null)
{
parent::__construct();
$this->checkOptions($options);
$this
->withWsdl($wsdl)
->withTrace($options['debug'])
;
if (isset($options['user_agent'])) {
$this->withUserAgent($options['user_agent']);
}
if (isset($options['cache_type'])) {
$this->withWsdlCache($options['cache_type']);
}
if ($classmap) {
$this->withClassmap($classmap);
}
if ($converters) {
$this->withTypeConverters($converters);
}
}
public function build()
{
if (!$this->soapClient) {
$this->soapClient = parent::build();
}
return $this->soapClient;
}
protected function checkOptions(array $options)
{
$checkOptions = array(
'debug' => false,
'cache_type' => null,
'exceptions' => true,
'user_agent' => 'BeSimpleSoap',
);
// check option names and live merge, if errors are encountered Exception will be thrown
$invalid = array();
$isInvalid = false;
foreach ($options as $key => $value) {
if (!array_key_exists($key, $checkOptions)) {
$isInvalid = true;
$invalid[] = $key;
}
}
if ($isInvalid) {
throw new \InvalidArgumentException(sprintf(
'The "%s" class does not support the following options: "%s".',
get_class($this),
implode('\', \'', $invalid)
));
}
}
}

View File

@ -12,7 +12,7 @@ namespace BeSimple\SoapBundle\Soap;
use BeSimple\SoapBundle\Util\Collection; use BeSimple\SoapBundle\Util\Collection;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Zend\Mime\Message; use Laminas\Mime\Message;
/** /**
* SoapRequest. * SoapRequest.
@ -69,7 +69,7 @@ class SoapRequest extends Request
*/ */
public function getSoapMessage() public function getSoapMessage()
{ {
if(null === $this->soapMessage) { if (null === $this->soapMessage) {
$this->soapMessage = $this->initializeSoapMessage(); $this->soapMessage = $this->initializeSoapMessage();
} }
@ -88,12 +88,12 @@ class SoapRequest extends Request
protected function initializeSoapMessage() protected function initializeSoapMessage()
{ {
if($this->server->has('CONTENT_TYPE')) { if ($this->server->has('CONTENT_TYPE')) {
$type = $this->splitContentTypeHeader($this->server->get('CONTENT_TYPE')); $type = $this->splitContentTypeHeader($this->server->get('CONTENT_TYPE'));
switch($type['_type']) { switch ($type['_type']) {
case 'multipart/related': case 'multipart/related':
if($type['type'] == 'application/xop+xml') { if ($type['type'] == 'application/xop+xml') {
return $this->initializeMtomSoapMessage($type, $this->getContent()); return $this->initializeMtomSoapMessage($type, $this->getContent());
} else { } else {
//log error //log error
@ -114,7 +114,7 @@ class SoapRequest extends Request
protected function initializeMtomSoapMessage(array $contentTypeHeader, $content) protected function initializeMtomSoapMessage(array $contentTypeHeader, $content)
{ {
if(!isset($contentTypeHeader['start']) || !isset($contentTypeHeader['start-info']) || !isset($contentTypeHeader['boundary'])) { if (!isset($contentTypeHeader['start']) || !isset($contentTypeHeader['start-info']) || !isset($contentTypeHeader['boundary'])) {
throw new \InvalidArgumentException(); throw new \InvalidArgumentException();
} }
@ -129,11 +129,11 @@ class SoapRequest extends Request
// TODO: add more checks to achieve full compatibility to MTOM spec // TODO: add more checks to achieve full compatibility to MTOM spec
// http://www.w3.org/TR/soap12-mtom/ // http://www.w3.org/TR/soap12-mtom/
if($rootPart->id != $soapMimePartId || $rootPartType['_type'] != 'application/xop+xml' || $rootPartType['type'] != $soapMimePartType) { if ($rootPart->id != $soapMimePartId || $rootPartType['_type'] != 'application/xop+xml' || $rootPartType['type'] != $soapMimePartType) {
throw new \InvalidArgumentException(); throw new \InvalidArgumentException();
} }
foreach($mimeParts as $mimePart) { foreach ($mimeParts as $mimePart) {
$this->soapAttachments->add(new SoapAttachment( $this->soapAttachments->add(new SoapAttachment(
$mimePart->id, $mimePart->id,
$mimePart->type, $mimePart->type,
@ -153,7 +153,7 @@ class SoapRequest extends Request
$result['_type'] = array_shift($parts); $result['_type'] = array_shift($parts);
foreach($parts as $part) { foreach ($parts as $part) {
list($key, $value) = explode('=', trim($part), 2); list($key, $value) = explode('=', trim($part), 2);
$result[$key] = trim($value, '"'); $result[$key] = trim($value, '"');

View File

@ -21,7 +21,7 @@ class Assert
public static function thatArgument($name, $condition, $message = self::ARGUMENT_INVALID) public static function thatArgument($name, $condition, $message = self::ARGUMENT_INVALID)
{ {
if(!$condition) { if (!$condition) {
throw new \InvalidArgumentException(sprintf($message, $name)); throw new \InvalidArgumentException(sprintf($message, $name));
} }
} }

View File

@ -15,7 +15,7 @@ namespace BeSimple\SoapBundle\Util;
* *
* @author Christian Kerl <christian-kerl@web.de> * @author Christian Kerl <christian-kerl@web.de>
*/ */
class String class BsString
{ {
/** /**
* Checks if a string starts with a given string. * Checks if a string starts with a given string.
@ -27,7 +27,7 @@ class String
*/ */
public static function startsWith($str, $substr) public static function startsWith($str, $substr)
{ {
if(is_string($str) && is_string($substr) && strlen($str) >= strlen($substr)) { if (is_string($str) && is_string($substr) && strlen($str) >= strlen($substr)) {
return $substr == substr($str, 0, strlen($substr)); return $substr == substr($str, 0, strlen($substr));
} }
} }
@ -42,7 +42,7 @@ class String
*/ */
public static function endsWith($str, $substr) public static function endsWith($str, $substr)
{ {
if(is_string($str) && is_string($substr) && strlen($str) >= strlen($substr)) { if (is_string($str) && is_string($substr) && strlen($str) >= strlen($substr)) {
return $substr == substr($str, strlen($str) - strlen($substr)); return $substr == substr($str, strlen($str) - strlen($substr));
} }
} }

View File

@ -13,8 +13,6 @@ namespace BeSimple\SoapBundle;
use BeSimple\SoapBundle\ServiceBinding\ServiceBinder; use BeSimple\SoapBundle\ServiceBinding\ServiceBinder;
use BeSimple\SoapCommon\Converter\TypeConverterCollection; use BeSimple\SoapCommon\Converter\TypeConverterCollection;
use BeSimple\SoapCommon\SoapOptionsBuilder;
use BeSimple\SoapServer\SoapServerOptionsBuilder;
use BeSimple\SoapWsdl\Dumper\Dumper; use BeSimple\SoapWsdl\Dumper\Dumper;
use BeSimple\SoapServer\SoapServerBuilder; use BeSimple\SoapServer\SoapServerBuilder;
use Symfony\Component\Config\ConfigCache; use Symfony\Component\Config\ConfigCache;
@ -70,10 +68,10 @@ class WebServiceContext
public function getWsdlFile($endpoint = null) public function getWsdlFile($endpoint = null)
{ {
$file = sprintf ('%s/%s.%s.wsdl', $this->options['cache_dir'], $this->options['name'], md5($endpoint)); $file = sprintf('%s/%s.%s.wsdl', $this->options['cache_dir'], $this->options['name'], md5($endpoint));
$cache = new ConfigCache($file, $this->options['debug']); $cache = new ConfigCache($file, $this->options['debug']);
if(!$cache->isFresh()) { if (!$cache->isFresh()) {
$definition = $this->getServiceDefinition(); $definition = $this->getServiceDefinition();
if ($endpoint) { if ($endpoint) {
@ -104,14 +102,15 @@ class WebServiceContext
public function getServerBuilder() public function getServerBuilder()
{ {
if (null === $this->serverBuilder) { if (null === $this->serverBuilder) {
$soapServerBuilder = new SoapServerBuilder(); $this->serverBuilder = SoapServerBuilder::createWithDefaults()
$this->serverBuilder = $soapServerBuilder->build( ->withWsdl($this->getWsdlFile())
SoapServerOptionsBuilder::createWithDefaults(), ->withClassmap($this->getServiceDefinition()->getTypeRepository()->getClassmap())
SoapOptionsBuilder::createWithClassMap( ->withTypeConverters($this->converters)
$this->getWsdlFile(), ;
$this->getServiceDefinition()->getTypeRepository()->getClassmap()
) if (null !== $this->options['cache_type']) {
); $this->serverBuilder->withWsdlCache($this->options['cache_type']);
}
} }
return $this->serverBuilder; return $this->serverBuilder;

View File

@ -22,16 +22,16 @@
"require": { "require": {
"php": ">=5.3.0", "php": ">=5.3.0",
"ext-soap": "*", "ext-soap": "*",
"besimple/soap-common": "0.3.*", "besimple/soap-common": "0.2.*",
"besimple/soap-wsdl": "0.3.*", "besimple/soap-wsdl": "0.2.*",
"ass/xmlsecurity": "~1.0", "ass/xmlsecurity": "~1.0",
"symfony/framework-bundle": "~2.6", "symfony/framework-bundle": "~2.0|~3.0",
"symfony/twig-bundle": "~2.6", "symfony/twig-bundle": "~2.0|~3.0",
"zendframework/zend-mime": "2.1.*" "zendframework/zend-mime": "2.1.*"
}, },
"suggest": { "suggest": {
"besimple/soap-client": "0.3.*", "besimple/soap-client": "0.2.*",
"besimple/soap-server": "0.3.*" "besimple/soap-server": "0.2.*"
}, },
"autoload": { "autoload": {
"psr-0": { "BeSimple\\SoapBundle": "" } "psr-0": { "BeSimple\\SoapBundle": "" }
@ -39,7 +39,7 @@
"target-dir": "BeSimple/SoapBundle", "target-dir": "BeSimple/SoapBundle",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "0.3-dev" "dev-master": "0.2-dev"
} }
} }
} }

View File

@ -0,0 +1,333 @@
<?php
/*
* This file is part of the BeSimpleSoapClient.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace BeSimple\SoapClient;
/**
* cURL wrapper class for doing HTTP requests that uses the soap class options.
*
* @author Andreas Schamberger <mail@andreass.net>
*/
class Curl
{
/**
* HTTP User Agent.
*
* @var string
*/
const USER_AGENT = 'PHP-SOAP/\BeSimple\SoapClient';
/**
* Curl resource.
*
* @var resource
*/
private $ch;
/**
* Maximum number of location headers to follow.
*
* @var int
*/
private $followLocationMaxRedirects;
/**
* Request response data.
*
* @var string
*/
private $response;
/**
* Constructor.
*
* @param array $options Options array from SoapClient constructor
* @param int $followLocationMaxRedirects Redirection limit for Location header
*/
public function __construct(array $options = array(), $followLocationMaxRedirects = 10)
{
// set the default HTTP user agent
if (!isset($options['user_agent'])) {
$options['user_agent'] = self::USER_AGENT;
}
$this->followLocationMaxRedirects = $followLocationMaxRedirects;
// make http request
$this->ch = curl_init();
$curlOptions = array(
CURLOPT_ENCODING => '',
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_FAILONERROR => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_HEADER => true,
CURLOPT_USERAGENT => $options['user_agent'],
CURLINFO_HEADER_OUT => true,
);
curl_setopt_array($this->ch, $curlOptions);
if (isset($options['compression']) && !($options['compression'] & SOAP_COMPRESSION_ACCEPT)) {
curl_setopt($this->ch, CURLOPT_ENCODING, 'identity');
}
curl_setopt($this->ch, CURLOPT_CONNECTTIMEOUT, 10);
if (isset($options['proxy_host'])) {
if (false !== $options['proxy_host']) {
$proxyHost = $options['proxy_host'].(isset($options['proxy_port']) ? $options['proxy_port'] : 8080);
} else {
$proxyHost = false;
}
curl_setopt($this->ch, CURLOPT_PROXY, $proxyHost);
if (false !== $proxyHost && isset($options['proxy_login'])) {
curl_setopt($this->ch, CURLOPT_PROXYUSERPWD, $options['proxy_login'].':'.$options['proxy_password']);
if (isset($options['proxy_auth'])) {
curl_setopt($this->ch, CURLOPT_PROXYAUTH, $options['proxy_auth']);
}
}
}
if (isset($options['login'])) {
curl_setopt($this->ch, CURLOPT_HTTPAUTH, isset($options['extra_options']['http_auth']) ? $options['extra_options']['http_auth'] : CURLAUTH_ANY);
curl_setopt($this->ch, CURLOPT_USERPWD, $options['login'].':'.$options['password']);
}
if (isset($options['local_cert'])) {
curl_setopt($this->ch, CURLOPT_SSLCERT, $options['local_cert']);
curl_setopt($this->ch, CURLOPT_SSLCERTPASSWD, $options['passphrase']);
}
if (isset($options['ca_info'])) {
curl_setopt($this->ch, CURLOPT_CAINFO, $options['ca_info']);
}
if (isset($options['ca_path'])) {
curl_setopt($this->ch, CURLOPT_CAPATH, $options['ca_path']);
}
}
/**
* Destructor.
*/
public function __destruct()
{
curl_close($this->ch);
}
/**
* Execute HTTP request.
* Returns true if request was successfull.
*
* @param string $location HTTP location
* @param string $request Request body
* @param array $requestHeaders Request header strings
* @param array $requestOptions An array of request options
*
* @return bool
*/
public function exec($location, $request = null, $requestHeaders = array(), $requestOptions = array())
{
curl_setopt($this->ch, CURLOPT_URL, $location);
if (!is_null($request)) {
curl_setopt($this->ch, CURLOPT_POST, true);
curl_setopt($this->ch, CURLOPT_POSTFIELDS, $request);
}
if (count($requestHeaders) > 0) {
curl_setopt($this->ch, CURLOPT_HTTPHEADER, $requestHeaders);
}
if (count($requestOptions) > 0) {
curl_setopt_array($this->ch, $requestOptions);
}
$this->response = $this->execManualRedirect();
return ($this->response === false) ? false : true;
}
/**
* Custom curl_exec wrapper that allows to follow redirects when specific
* http response code is set. SOAP only allows 307.
*
* @param int $redirects Current redirection count
*
* @return mixed
*/
private function execManualRedirect($redirects = 0)
{
if ($redirects > $this->followLocationMaxRedirects) {
// TODO Redirection limit reached, aborting
return false;
}
curl_setopt($this->ch, CURLOPT_HEADER, true);
curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($this->ch);
$httpResponseCode = curl_getinfo($this->ch, CURLINFO_HTTP_CODE);
if ($httpResponseCode == 307) {
$headerSize = curl_getinfo($this->ch, CURLINFO_HEADER_SIZE);
$header = substr($response, 0, $headerSize);
$matches = array();
preg_match('/Location:(.*?)\n/', $header, $matches);
$url = trim(array_pop($matches));
// @parse_url to suppress E_WARNING for invalid urls
if (($url = @parse_url($url)) !== false) {
$lastUrl = parse_url(curl_getinfo($this->ch, CURLINFO_EFFECTIVE_URL));
if (!isset($url['scheme'])) {
$url['scheme'] = $lastUrl['scheme'];
}
if (!isset($url['host'])) {
$url['host'] = $lastUrl['host'];
}
if (!isset($url['path'])) {
$url['path'] = $lastUrl['path'];
}
$newUrl = $url['scheme'].'://'.$url['host'].$url['path'].($url['query'] ? '?'.$url['query'] : '');
curl_setopt($this->ch, CURLOPT_URL, $newUrl);
return $this->execManualRedirect($redirects++);
}
}
return $response;
}
/**
* Error code mapping from cURL error codes to PHP ext/soap error messages
* (where applicable).
*
* http://curl.haxx.se/libcurl/c/libcurl-errors.html
*
* @return array(int=>string)
*/
protected function getErrorCodeMapping()
{
return array(
1 => 'Unknown protocol. Only http and https are allowed.', //CURLE_UNSUPPORTED_PROTOCOL
3 => 'Unable to parse URL', //CURLE_URL_MALFORMAT
5 => 'Could not connect to host', //CURLE_COULDNT_RESOLVE_PROXY
6 => 'Could not connect to host', //CURLE_COULDNT_RESOLVE_HOST
7 => 'Could not connect to host', //CURLE_COULDNT_CONNECT
9 => 'Could not connect to host', //CURLE_REMOTE_ACCESS_DENIED
28 => 'Failed Sending HTTP SOAP request', //CURLE_OPERATION_TIMEDOUT
35 => 'Could not connect to host', //CURLE_SSL_CONNECT_ERROR
41 => 'Can\'t uncompress compressed response', //CURLE_FUNCTION_NOT_FOUND
51 => 'Could not connect to host', //CURLE_PEER_FAILED_VERIFICATION
52 => 'Error Fetching http body, No Content-Length, connection closed or chunked data', //CURLE_GOT_NOTHING
53 => 'SSL support is not available in this build', //CURLE_SSL_ENGINE_NOTFOUND
54 => 'SSL support is not available in this build', //CURLE_SSL_ENGINE_SETFAILED
55 => 'Failed Sending HTTP SOAP request', //CURLE_SEND_ERROR
56 => 'Error Fetching http body, No Content-Length, connection closed or chunked data', //CURLE_RECV_ERROR
58 => 'Could not connect to host', //CURLE_SSL_CERTPROBLEM
59 => 'Could not connect to host', //CURLE_SSL_CIPHER
60 => 'Could not connect to host', //CURLE_SSL_CACERT
61 => 'Unknown Content-Encoding', //CURLE_BAD_CONTENT_ENCODING
65 => 'Failed Sending HTTP SOAP request', //CURLE_SEND_FAIL_REWIND
66 => 'SSL support is not available in this build', //CURLE_SSL_ENGINE_INITFAILED
67 => 'Could not connect to host', //CURLE_LOGIN_DENIED
77 => 'Could not connect to host', //CURLE_SSL_CACERT_BADFILE
80 => 'Error Fetching http body, No Content-Length, connection closed or chunked data', //CURLE_SSL_SHUTDOWN_FAILED
);
}
/**
* Gets the curl error message.
*
* @return string
*/
public function getErrorMessage()
{
$errorCodeMapping = $this->getErrorCodeMapping();
$errorNumber = curl_errno($this->ch);
if (isset($errorCodeMapping[$errorNumber])) {
return $errorCodeMapping[$errorNumber];
}
return curl_error($this->ch);
}
/**
* Gets the request headers as a string.
*
* @return string
*/
public function getRequestHeaders()
{
return curl_getinfo($this->ch, CURLINFO_HEADER_OUT);
}
/**
* Gets the whole response (including headers) as a string.
*
* @return string
*/
public function getResponse()
{
return $this->response;
}
/**
* Gets the response body as a string.
*
* @return string
*/
public function getResponseBody()
{
$headerSize = curl_getinfo($this->ch, CURLINFO_HEADER_SIZE);
return substr($this->response, $headerSize);
}
/**
* Gets the response content type.
*
* @return string
*/
public function getResponseContentType()
{
return curl_getinfo($this->ch, CURLINFO_CONTENT_TYPE);
}
/**
* Gets the response headers as a string.
*
* @return string
*/
public function getResponseHeaders()
{
$headerSize = curl_getinfo($this->ch, CURLINFO_HEADER_SIZE);
return substr($this->response, 0, $headerSize);
}
/**
* Gets the response http status code.
*
* @return string
*/
public function getResponseStatusCode()
{
return curl_getinfo($this->ch, CURLINFO_HTTP_CODE);
}
/**
* Gets the response http status message.
*
* @return string
*/
public function getResponseStatusMessage()
{
preg_match('/HTTP\/(1\.[0-1]+) ([0-9]{3}) (.*)/', $this->response, $matches);
return trim(array_pop($matches));
}
}

View File

@ -1,234 +0,0 @@
<?php
namespace BeSimple\SoapClient\Curl;
use BeSimple\SoapClient\Curl\Http\HttpAuthenticationBasicOptions;
use BeSimple\SoapClient\Curl\Http\HttpAuthenticationDigestOptions;
use BeSimple\SoapClient\Curl\Http\SslCertificateOptions;
use Exception;
class Curl
{
const CURL_SUCCESS = true;
const CURL_FAILED = false;
private $curlSession;
private $options;
/**
* @param CurlOptions $options
*/
public function __construct(CurlOptions $options)
{
$this->curlSession = $this->acquireNewCurlSession($options);
$this->options = $options;
}
public function __destruct()
{
$this->closeCurlSession($this->curlSession);
}
/**
* @param string $location HTTP location
* @param string $request Request body
* @param array $requestHeaders Request header strings
* @return CurlResponse
*/
public function executeCurlWithCachedSession($location, $request = null, $requestHeaders = [])
{
return $this->executeCurlSession($this->curlSession, $this->options, $location, $request, $requestHeaders);
}
/**
* @param CurlOptions $options
* @param string $location HTTP location
* @param string $request Request body
* @param array $requestHeaders Request header strings
* @return CurlResponse
*/
public function executeCurl(CurlOptions $options, $location, $request = null, $requestHeaders = [])
{
$curlSession = $this->acquireNewCurlSession($options);
$curlResponse = $this->executeCurlSession($curlSession, $options, $location, $request, $requestHeaders);
$this->closeCurlSession($curlSession);
return $curlResponse;
}
private function acquireNewCurlSession(CurlOptions $options)
{
$curlSession = curl_init();
curl_setopt_array($curlSession, [
CURLOPT_ENCODING => '',
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_FAILONERROR => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_HEADER => true,
CURLOPT_USERAGENT => $options->getUserAgent(),
CURLINFO_HEADER_OUT => true,
CURLOPT_CONNECTTIMEOUT => $options->getConnectionTimeout()
]);
return $curlSession;
}
private function closeCurlSession($curlSession)
{
curl_close($curlSession);
}
/**
* @param mixed $curlSession Result of curl_init() handle
* @param CurlOptions $options
* @param string $location HTTP location
* @param string $request Request body
* @param array $requestHeaders Request header strings
* @return CurlResponse
*/
private function executeCurlSession($curlSession, CurlOptions $options, $location, $request = null, $requestHeaders = [])
{
curl_setopt($curlSession, CURLOPT_URL, $location);
curl_setopt($curlSession, CURLOPT_HEADER, true);
curl_setopt($curlSession, CURLOPT_RETURNTRANSFER, true);
if (!is_null($request)) {
curl_setopt($curlSession, CURLOPT_POST, true);
curl_setopt($curlSession, CURLOPT_POSTFIELDS, $request);
} else {
curl_setopt($curlSession, CURLOPT_POST, false);
}
if (count($requestHeaders) > 0) {
curl_setopt($curlSession, CURLOPT_HTTPHEADER, $requestHeaders);
}
if (!$options->getSoapCompression() & SOAP_COMPRESSION_ACCEPT) {
curl_setopt($curlSession, CURLOPT_ENCODING, 'identity');
}
if ($options->hasProxy()) {
$proxyHost = $options->getProxy()->getHost() . $options->getProxy()->getPort();
curl_setopt($curlSession, CURLOPT_PROXY, $proxyHost);
if ($options->getProxy()->hasCredentials()) {
curl_setopt($curlSession, CURLOPT_PROXYUSERPWD, $options->getProxy()->getLogin() . ':' . $options->getProxy()->getPassword());
if ($options->getProxy()->hasAuthenticationType()) {
curl_setopt($curlSession, CURLOPT_PROXYAUTH, $options->getProxy()->getAuthenticationType());
}
}
}
if ($options->hasHttpAuthentication()) {
if ($options->hasHttpAuthenticationBasic()) {
/** @var HttpAuthenticationBasicOptions $httpAuthenticationBasic */
$httpAuthenticationBasic = $options->getHttpAuthentication();
curl_setopt($curlSession, CURLOPT_HTTPAUTH, $httpAuthenticationBasic->getAuthenticationType());
curl_setopt($curlSession, CURLOPT_USERPWD, $httpAuthenticationBasic->getUsername() . ':' . $httpAuthenticationBasic->getPassword());
} else if ($options->hasHttpAuthenticationDigest()) {
/** @var HttpAuthenticationDigestOptions $httpAuthenticationDigest */
$httpAuthenticationDigest = $options->getHttpAuthentication();
curl_setopt($curlSession, CURLOPT_HTTPAUTH, $httpAuthenticationDigest->getAuthenticationType());
} else {
throw new Exception('Unresolved authentication type: '.get_class($options->getHttpAuthentication()));
}
}
if ($options->hasSslCertificateOptions()) {
$sslCertificateOptions = $options->getSslCertificateOptions();
curl_setopt($curlSession, CURLOPT_SSLCERT, $sslCertificateOptions->getCertificateLocalPath());
if ($sslCertificateOptions->hasCertificatePassPhrase()) {
curl_setopt($curlSession, CURLOPT_SSLCERTPASSWD, $sslCertificateOptions->getCertificatePassPhrase());
}
if ($sslCertificateOptions->hasCertificateAuthorityInfo()) {
curl_setopt($curlSession, CURLOPT_CAINFO, $sslCertificateOptions->getCertificateAuthorityInfo());
}
if ($sslCertificateOptions->hasCertificateAuthorityPath()) {
curl_setopt($curlSession, CURLOPT_CAPATH, $sslCertificateOptions->hasCertificateAuthorityPath());
}
}
$executeSoapCallResponse = $this->executeHttpCall($curlSession, $options);
$httpRequestHeadersAsString = curl_getinfo($curlSession, CURLINFO_HEADER_OUT);
$headerSize = curl_getinfo($curlSession, CURLINFO_HEADER_SIZE);
$httpResponseCode = curl_getinfo($curlSession, CURLINFO_HTTP_CODE);
$httpResponseContentType = curl_getinfo($curlSession, CURLINFO_CONTENT_TYPE);;
preg_match('/HTTP\/(1\.[0-1]+) ([0-9]{3}) (.*)/', $executeSoapCallResponse, $httpResponseMessages);
$httpResponseMessage = trim(array_pop($httpResponseMessages));
$curlErrorMessage = sprintf(
'Curl error "%s" with message: %s occurred while connecting to %s',
curl_errno($curlSession),
curl_error($curlSession),
$location
);
if ($executeSoapCallResponse === false) {
return new CurlResponse(
$httpRequestHeadersAsString,
$httpResponseCode,
$httpResponseMessage,
$httpResponseContentType,
self::CURL_FAILED,
$curlErrorMessage
);
}
return new CurlResponse(
$httpRequestHeadersAsString,
$httpResponseCode,
$httpResponseMessage,
$httpResponseContentType,
self::CURL_SUCCESS,
null,
substr($executeSoapCallResponse, 0, $headerSize),
substr($executeSoapCallResponse, $headerSize)
);
}
/**
* Custom curl_exec wrapper that allows to follow redirects when specific
* http response code is set. SOAP only allows 307.
*
* @param mixed $curlSession Result of curl_init() handle
* @param CurlOptions $options
* @param int $executedRedirects
* @return string|null
* @throws Exception
*/
private function executeHttpCall($curlSession, CurlOptions $options, $executedRedirects = 0)
{
if ($executedRedirects > $options->getFollowLocationMaxRedirects()) {
throw new Exception('Cannot executeHttpCall - too many redirects: ' . $executedRedirects);
}
$curlExecResponse = curl_exec($curlSession);
$httpResponseCode = curl_getinfo($curlSession, CURLINFO_HTTP_CODE);
if ($httpResponseCode === 307) {
$newUrl = $this->getRedirectUrlFromResponseHeaders($curlSession, $curlExecResponse);
curl_setopt($curlSession, CURLOPT_URL, $newUrl);
return $this->executeHttpCall($curlSession, $options, ++$executedRedirects);
}
return $curlExecResponse;
}
private function getRedirectUrlFromResponseHeaders($curlSession, $curlExecResponse)
{
$curlExecResponseHeaders = substr($curlExecResponse, 0, curl_getinfo($curlSession, CURLINFO_HEADER_SIZE));
$matches = [];
preg_match('/Location:(.*?)\n/', $curlExecResponseHeaders, $matches);
$url = trim(array_pop($matches));
if (($url = @parse_url($url)) !== false) {
$lastUrl = parse_url(curl_getinfo($curlSession, CURLINFO_EFFECTIVE_URL));
if (!isset($url['scheme'])) {
$url['scheme'] = $lastUrl['scheme'];
}
if (!isset($url['host'])) {
$url['host'] = $lastUrl['host'];
}
if (!isset($url['path'])) {
$url['path'] = $lastUrl['path'];
}
return $url['scheme'] . '://' . $url['host'] . $url['path'] . ($url['query'] ? '?' . $url['query'] : '');
}
throw new Exception('Cannot parse WSDL url redirect: ' . $url);
}
}

View File

@ -1,126 +0,0 @@
<?php
namespace BeSimple\SoapClient\Curl;
use BeSimple\SoapClient\Curl\Http\HttpAuthenticationDigestOptions;
use BeSimple\SoapClient\Curl\Http\HttpAuthenticationInterface;
use BeSimple\SoapClient\Curl\Http\HttpAuthenticationBasicOptions;
use BeSimple\SoapClient\Curl\Http\SslCertificateOptions;
use BeSimple\SoapClient\SoapServerProxy\SoapServerProxy;
class CurlOptions
{
const DEFAULT_USER_AGENT = 'BeSimpleSoap';
const SOAP_COMPRESSION_NONE = null;
const SOAP_COMPRESSION_GZIP = SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP;
const SOAP_COMPRESSION_DEFLATE = SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_DEFLATE;
private $userAgent;
private $followLocationMaxRedirects;
private $soapCompression;
private $connectionTimeout;
private $proxy;
private $httpAuthentication;
private $sslCertificateOptions;
/**
* @param string $userAgent
* @param int $followLocationMaxRedirects
* @param CurlOptions::SOAP_COMPRESSION_NONE|CurlOptions::SOAP_COMPRESSION_GZIP|CurlOptions::SOAP_COMPRESSION_DEFLATE $soapCompression
* @param int $connectionTimeout
* @param SoapServerProxy|null $proxy
* @param HttpAuthenticationInterface|null $httpAuthentication
* @param SslCertificateOptions|null $sslCertificateOptions
*/
public function __construct(
$userAgent,
$followLocationMaxRedirects,
$soapCompression,
$connectionTimeout,
SoapServerProxy $proxy = null,
HttpAuthenticationInterface $httpAuthentication = null,
SslCertificateOptions $sslCertificateOptions = null
) {
$this->userAgent = $userAgent;
$this->followLocationMaxRedirects = $followLocationMaxRedirects;
$this->soapCompression = $soapCompression;
$this->connectionTimeout = $connectionTimeout;
$this->proxy = $proxy;
$this->httpAuthentication = $httpAuthentication;
$this->sslCertificateOptions = $sslCertificateOptions;
}
public function getUserAgent()
{
return $this->userAgent;
}
public function getFollowLocationMaxRedirects()
{
return $this->followLocationMaxRedirects;
}
public function getSoapCompression()
{
return $this->soapCompression;
}
public function getConnectionTimeout()
{
return $this->connectionTimeout;
}
public function getProxy()
{
return $this->proxy;
}
public function getHttpAuthentication()
{
return $this->httpAuthentication;
}
public function getSslCertificateOptions()
{
return $this->sslCertificateOptions;
}
public function hasProxy()
{
return $this->proxy !== null;
}
public function hasHttpAuthentication()
{
return $this->httpAuthentication !== null;
}
public function hasSslCertificateOptions()
{
return $this->sslCertificateOptions !== null;
}
public function hasHttpAuthenticationBasic()
{
if ($this->hasHttpAuthentication()) {
if ($this->getHttpAuthentication() instanceof HttpAuthenticationBasicOptions) {
return true;
}
}
return false;
}
public function hasHttpAuthenticationDigest()
{
if ($this->hasHttpAuthentication()) {
if ($this->getHttpAuthentication() instanceof HttpAuthenticationDigestOptions) {
return true;
}
}
return false;
}
}

View File

@ -1,79 +0,0 @@
<?php
namespace BeSimple\SoapClient\Curl;
use BeSimple\SoapClient\Curl\Http\HttpAuthenticationDigestOptions;
use BeSimple\SoapClient\Curl\Http\SslCertificateOptions;
use BeSimple\SoapClient\SoapOptions\SoapClientOptions;
use BeSimple\SoapClient\SoapServerAuthentication\SoapServerAuthenticationBasic;
use BeSimple\SoapClient\SoapServerAuthentication\SoapServerAuthenticationDigest;
use BeSimple\SoapClient\Curl\Http\HttpAuthenticationBasicOptions;
use Exception;
class CurlOptionsBuilder
{
const DEFAULT_MAX_REDIRECTS = 10;
const DEFAULT_CONNECTION_TIMEOUT = 10;
public static function buildDefault()
{
return new CurlOptions(
CurlOptions::DEFAULT_USER_AGENT,
self::DEFAULT_MAX_REDIRECTS,
CurlOptions::SOAP_COMPRESSION_NONE,
self::DEFAULT_CONNECTION_TIMEOUT
);
}
public static function buildForSoapClient(SoapClientOptions $soapClientOptions)
{
return new CurlOptions(
$soapClientOptions->getUserAgent(),
self::DEFAULT_MAX_REDIRECTS,
$soapClientOptions->getCompression(),
self::DEFAULT_CONNECTION_TIMEOUT,
$soapClientOptions->getProxy(),
self::getHttpAuthOptions($soapClientOptions),
self::getSslCertificateOptions($soapClientOptions)
);
}
private static function getHttpAuthOptions(SoapClientOptions $soapClientOptions)
{
if ($soapClientOptions->hasAuthentication()) {
if ($soapClientOptions->hasAuthenticationBasic()) {
/** @var SoapServerAuthenticationBasic $basicAuthentication */
$basicAuthentication = $soapClientOptions->getAuthentication();
return new HttpAuthenticationBasicOptions(
$basicAuthentication->getLogin(),
$basicAuthentication->getPassword()
);
} else if ($soapClientOptions->hasAuthenticationDigest()) {
return new HttpAuthenticationDigestOptions();
} else {
throw new Exception('Unresolved authentication type: '.get_class($soapClientOptions->getAuthentication()));
}
}
return null;
}
private static function getSslCertificateOptions(SoapClientOptions $soapClientOptions)
{
if ($soapClientOptions->hasAuthenticationDigest()) {
/** @var SoapServerAuthenticationDigest $digestAuthentication */
$digestAuthentication = $soapClientOptions->getAuthentication();
return new SslCertificateOptions(
$digestAuthentication->getLocalCert(),
$digestAuthentication->getPassPhrase()
);
}
return null;
}
}

View File

@ -1,100 +0,0 @@
<?php
namespace BeSimple\SoapClient\Curl;
class CurlResponse
{
private $httpRequestHeaders;
private $httpResponseStatusCode;
private $httpResponseStatusMessage;
private $httpResponseContentType;
private $curlStatus;
private $curlErrorMessage;
private $responseHeader;
private $responseBody;
public function __construct(
$httpRequestHeaders,
$httpResponseStatusCode,
$httpResponseStatusMessage,
$httpResponseContentType,
$curlStatus,
$curlErrorMessage = null,
$responseHeader = null,
$responseBody = null
) {
$this->httpRequestHeaders = $httpRequestHeaders;
$this->httpResponseStatusCode = $httpResponseStatusCode;
$this->httpResponseStatusMessage = $httpResponseStatusMessage;
$this->httpResponseContentType = $httpResponseContentType;
$this->curlStatus = $curlStatus;
$this->curlErrorMessage = $curlErrorMessage;
$this->responseHeader = $responseHeader;
$this->responseBody = $responseBody;
}
public function getHttpRequestHeaders()
{
return $this->httpRequestHeaders;
}
public function getHttpResponseStatusCode()
{
return $this->httpResponseStatusCode;
}
public function getHttpResponseStatusMessage()
{
return $this->httpResponseStatusMessage;
}
public function getHttpResponseContentType()
{
return $this->httpResponseContentType;
}
public function getCurlStatus()
{
return $this->curlStatus;
}
public function curlStatusSuccess()
{
return $this->curlStatus === Curl::CURL_SUCCESS;
}
public function curlStatusFailed()
{
return $this->curlStatus === Curl::CURL_FAILED;
}
public function hasCurlErrorMessage()
{
return $this->curlErrorMessage !== null;
}
public function getCurlErrorMessage()
{
return $this->curlErrorMessage;
}
public function hasResponseHeader()
{
return $this->responseHeader !== null;
}
public function getResponseHeader()
{
return $this->responseHeader;
}
public function hasResponseBody()
{
return $this->responseBody !== null;
}
public function getResponseBody()
{
return $this->responseBody;
}
}

View File

@ -1,34 +0,0 @@
<?php
namespace BeSimple\SoapClient\Curl\Http;
class HttpAuthenticationBasicOptions implements HttpAuthenticationInterface
{
private $username;
private $password;
/**
* @param string $username
* @param string $password
*/
public function __construct($username, $password)
{
$this->username = $username;
$this->password = $password;
}
public function getUsername()
{
return $this->username;
}
public function getPassword()
{
return $this->password;
}
public function getAuthenticationType()
{
return HttpAuthenticationInterface::AUTHENTICATION_TYPE_BASIC;
}
}

View File

@ -1,11 +0,0 @@
<?php
namespace BeSimple\SoapClient\Curl\Http;
class HttpAuthenticationDigestOptions implements HttpAuthenticationInterface
{
public function getAuthenticationType()
{
return HttpAuthenticationInterface::AUTHENTICATION_TYPE_DIGEST;
}
}

View File

@ -1,15 +0,0 @@
<?php
namespace BeSimple\SoapClient\Curl\Http;
interface HttpAuthenticationInterface
{
const AUTHENTICATION_TYPE_ANY = CURLAUTH_ANY;
const AUTHENTICATION_TYPE_BASIC = CURLAUTH_BASIC;
const AUTHENTICATION_TYPE_DIGEST = CURLAUTH_DIGEST;
/**
* @return string choice from self::AUTHENTICATION_TYPE_ANY|self::AUTHENTICATION_TYPE_BASIC|self::AUTHENTICATION_TYPE_DIGEST
*/
public function getAuthenticationType();
}

View File

@ -1,64 +0,0 @@
<?php
namespace BeSimple\SoapClient\Curl\Http;
class SslCertificateOptions
{
private $certificateLocalPath;
private $certificatePassPhrase;
private $certificateAuthorityInfo;
private $certificateAuthorityPath;
/**
* @param string $certificateLocalPath
* @param string $certificatePassPhrase
* @param string $certificateAuthorityInfo
* @param string $certificateAuthorityPath
*/
public function __construct(
$certificateLocalPath,
$certificatePassPhrase = null,
$certificateAuthorityInfo = null,
$certificateAuthorityPath = null
) {
$this->certificateLocalPath = $certificateLocalPath;
$this->certificatePassPhrase = $certificatePassPhrase;
$this->certificateAuthorityInfo = $certificateAuthorityInfo;
$this->certificateAuthorityPath = $certificateAuthorityPath;
}
public function getCertificateLocalPath()
{
return $this->certificateLocalPath;
}
public function getCertificatePassPhrase()
{
return $this->certificatePassPhrase;
}
public function getCertificateAuthorityInfo()
{
return $this->certificateAuthorityInfo;
}
public function getCertificateAuthorityPath()
{
return $this->certificateAuthorityPath;
}
public function hasCertificatePassPhrase()
{
return $this->certificatePassPhrase !== null;
}
public function hasCertificateAuthorityInfo()
{
return $this->certificateAuthorityInfo !== null;
}
public function hasCertificateAuthorityPath()
{
return $this->certificateAuthorityPath !== null;
}
}

View File

@ -16,10 +16,9 @@ use BeSimple\SoapCommon\Helper;
use BeSimple\SoapCommon\Mime\MultiPart as MimeMultiPart; use BeSimple\SoapCommon\Mime\MultiPart as MimeMultiPart;
use BeSimple\SoapCommon\Mime\Parser as MimeParser; use BeSimple\SoapCommon\Mime\Parser as MimeParser;
use BeSimple\SoapCommon\Mime\Part as MimePart; use BeSimple\SoapCommon\Mime\Part as MimePart;
use BeSimple\SoapCommon\Mime\Part;
use BeSimple\SoapCommon\SoapRequest; use BeSimple\SoapCommon\SoapRequest;
use BeSimple\SoapCommon\SoapRequestFilter; use BeSimple\SoapCommon\SoapRequestFilter;
use BeSimple\SoapCommon\SoapResponse as CommonSoapResponse; use BeSimple\SoapCommon\SoapResponse;
use BeSimple\SoapCommon\SoapResponseFilter; use BeSimple\SoapCommon\SoapResponseFilter;
/** /**
@ -29,61 +28,111 @@ use BeSimple\SoapCommon\SoapResponseFilter;
*/ */
class MimeFilter implements SoapRequestFilter, SoapResponseFilter class MimeFilter implements SoapRequestFilter, SoapResponseFilter
{ {
public function filterRequest(SoapRequest $request, $attachmentType) /**
* Attachment type.
*
* @var int Helper::ATTACHMENTS_TYPE_SWA | Helper::ATTACHMENTS_TYPE_MTOM
*/
protected $attachmentType = Helper::ATTACHMENTS_TYPE_SWA;
/**
* Constructor.
*
* @param int $attachmentType Helper::ATTACHMENTS_TYPE_SWA | Helper::ATTACHMENTS_TYPE_MTOM
*/
public function __construct($attachmentType)
{ {
$this->attachmentType = $attachmentType;
}
/**
* Reset all properties to default values.
*/
public function resetFilter()
{
$this->attachmentType = Helper::ATTACHMENTS_TYPE_SWA;
}
/**
* Modify the given request XML.
*
* @param \BeSimple\SoapCommon\SoapRequest $request SOAP request
*
* @return void
*/
public function filterRequest(SoapRequest $request)
{
// get attachments from request object
$attachmentsToSend = $request->getAttachments(); $attachmentsToSend = $request->getAttachments();
// build mime message if we have attachments
if (count($attachmentsToSend) > 0) { if (count($attachmentsToSend) > 0) {
$multipart = new MimeMultiPart('Part_' . rand(10, 15) . '_' . uniqid() . '.' . uniqid()); $multipart = new MimeMultiPart();
$soapPart = new MimePart($request->getContent(), 'text/xml', 'utf-8', MimePart::ENCODING_EIGHT_BIT); $soapPart = new MimePart($request->getContent(), 'text/xml', 'utf-8', MimePart::ENCODING_EIGHT_BIT);
$soapVersion = $request->getVersion(); $soapVersion = $request->getVersion();
// change content type headers for MTOM with SOAP 1.1
if ($soapVersion == SOAP_1_1 && $attachmentType & Helper::ATTACHMENTS_TYPE_MTOM) { if ($soapVersion == SOAP_1_1 && $this->attachmentType & Helper::ATTACHMENTS_TYPE_MTOM) {
$multipart->setHeader('Content-Type', 'type', 'application/xop+xml'); $multipart->setHeader('Content-Type', 'type', 'application/xop+xml');
$multipart->setHeader('Content-Type', 'start-info', 'text/xml'); $multipart->setHeader('Content-Type', 'start-info', 'text/xml');
$soapPart->setHeader('Content-Type', 'application/xop+xml'); $soapPart->setHeader('Content-Type', 'application/xop+xml');
$soapPart->setHeader('Content-Type', 'type', 'text/xml'); $soapPart->setHeader('Content-Type', 'type', 'text/xml');
} elseif ($soapVersion == SOAP_1_2) { }
// change content type headers for SOAP 1.2
elseif ($soapVersion == SOAP_1_2) {
$multipart->setHeader('Content-Type', 'type', 'application/soap+xml'); $multipart->setHeader('Content-Type', 'type', 'application/soap+xml');
$soapPart->setHeader('Content-Type', 'application/soap+xml'); $soapPart->setHeader('Content-Type', 'application/soap+xml');
} }
$multipart->addPart($soapPart, true); $multipart->addPart($soapPart, true);
foreach ($attachmentsToSend as $cid => $attachment) { foreach ($attachmentsToSend as $cid => $attachment) {
$multipart->addPart($attachment, false); $multipart->addPart($attachment, false);
} }
$request->setContent($multipart->getMimeMessage()); $request->setContent($multipart->getMimeMessage());
// TODO
$headers = $multipart->getHeadersForHttp(); $headers = $multipart->getHeadersForHttp();
list(, $contentType) = explode(': ', $headers[0]); list(, $contentType) = explode(': ', $headers[0]);
$request->setContentType($contentType); $request->setContentType($contentType);
} }
return $request;
} }
public function filterResponse(CommonSoapResponse $response, $attachmentType) /**
* Modify the given response XML.
*
* @param \BeSimple\SoapCommon\SoapResponse $response SOAP response
*
* @return void
*/
public function filterResponse(SoapResponse $response)
{ {
$multiPartMessage = MimeParser::parseMimeMessage( // array to store attachments
$response->getContent(), $attachmentsRecieved = array();
['Content-Type' => trim($response->getContentType())]
// check content type if it is a multipart mime message
$responseContentType = $response->getContentType();
if (false !== stripos($responseContentType, 'multipart/related')) {
// parse mime message
$headers = array(
'Content-Type' => trim($responseContentType),
); );
$soapPart = $multiPartMessage->getMainPart(); $multipart = MimeParser::parseMimeMessage($response->getContent(), $headers);
$attachments = $multiPartMessage->getAttachments(); // get soap payload and update SoapResponse object
$soapPart = $multipart->getPart();
$response->setContent($this->sanitizePhpExceptionOnHrefs($soapPart));
$response->setContentType($soapPart->getHeader('Content-Type'));
if (count($attachments) > 0) {
$response->setAttachments($attachments);
}
return $response;
}
private function sanitizePhpExceptionOnHrefs(Part $soapPart)
{
// convert href -> myhref for external references as PHP throws exception in this case // convert href -> myhref for external references as PHP throws exception in this case
// http://svn.php.net/viewvc/php/php-src/branches/PHP_5_4/ext/soap/php_encoding.c?view=markup#l3436 // http://svn.php.net/viewvc/php/php-src/branches/PHP_5_4/ext/soap/php_encoding.c?view=markup#l3436
return preg_replace('/href=(?!#)/', 'myhref=', $soapPart->getContent()); $content = preg_replace('/href=(?!#)/', 'myhref=', $soapPart->getContent());
$response->setContent($content);
$response->setContentType($soapPart->getHeader('Content-Type'));
// store attachments
$attachments = $multipart->getParts(false);
foreach ($attachments as $cid => $attachment) {
$attachmentsRecieved[$cid] = $attachment;
}
}
// add attachments to response object
if (count($attachmentsRecieved) > 0) {
$response->setAttachments($attachmentsRecieved);
}
} }
} }

View File

@ -12,20 +12,10 @@
namespace BeSimple\SoapClient; namespace BeSimple\SoapClient;
use BeSimple\SoapBundle\Soap\SoapAttachment; use BeSimple\SoapCommon\Helper;
use BeSimple\SoapBundle\Soap\SoapAttachmentList; use BeSimple\SoapCommon\Converter\MtomTypeConverter;
use BeSimple\SoapClient\Curl\Curl; use BeSimple\SoapCommon\Converter\SwaTypeConverter;
use BeSimple\SoapClient\Curl\CurlOptionsBuilder; use BeSimple\SoapCommon\SoapMessage;
use BeSimple\SoapClient\Curl\CurlResponse;
use BeSimple\SoapClient\SoapOptions\SoapClientOptions;
use BeSimple\SoapCommon\Fault\SoapFaultEnum;
use BeSimple\SoapCommon\Mime\PartFactory;
use BeSimple\SoapCommon\SoapKernel;
use BeSimple\SoapCommon\SoapOptions\SoapOptions;
use BeSimple\SoapCommon\SoapRequest;
use BeSimple\SoapCommon\SoapRequestFactory;
use Exception;
use SoapFault;
/** /**
* Extended SoapClient that uses a a cURL wrapper for all underlying HTTP * Extended SoapClient that uses a a cURL wrapper for all underlying HTTP
@ -34,92 +24,172 @@ use SoapFault;
* allows caching of all remote referenced items. * allows caching of all remote referenced items.
* *
* @author Andreas Schamberger <mail@andreass.net> * @author Andreas Schamberger <mail@andreass.net>
* @author Petr Bechyně <mail@petrbechyne.com>
*/ */
class SoapClient extends \SoapClient class SoapClient extends \SoapClient
{ {
protected $soapClientOptions;
protected $soapOptions;
private $curl;
public function __construct(SoapClientOptions $soapClientOptions, SoapOptions $soapOptions)
{
$this->soapClientOptions = $soapClientOptions;
$this->soapOptions = $soapOptions;
$this->curl = new Curl(
CurlOptionsBuilder::buildForSoapClient($soapClientOptions)
);
try {
@parent::__construct(
$this->loadWsdl(
$this->curl,
$soapOptions->getWsdlFile(),
$soapOptions->getWsdlCacheType()
),
$soapClientOptions->toArray() + $soapOptions->toArray()
);
} catch (Exception $e) {
throw new SoapFault(
SoapFaultEnum::SOAP_FAULT_SOAP_CLIENT_ERROR,
'Could not create SoapClient instance with message: '.$e->getMessage()
);
}
}
/** /**
* Avoid using __call directly, it's deprecated even in \SoapClient. * Soap version.
* *
* @deprecated * @var int
*/ */
public function __call($function_name, $arguments) protected $soapVersion = SOAP_1_1;
{
throw new Exception(
'The __call method is deprecated. Use __soapCall/soapCall instead.'
);
}
/** /**
* Using __soapCall returns only response string, use soapCall instead. * Tracing enabled?
* *
* @param string $functionName * @var boolean
* @param array $arguments
* @param array|null $options
* @param null $inputHeaders
* @param array|null $outputHeaders
* @return string
*/ */
public function __soapCall($functionName, $arguments, $options = null, $inputHeaders = null, &$outputHeaders = null) protected $tracingEnabled = false;
{
return $this->soapCall($functionName, $arguments, $options, $inputHeaders, $outputHeaders)->getContent();
}
/** /**
* @param string $functionName * cURL instance.
* @param array $arguments *
* @param array|null $options * @var \BeSimple\SoapClient\Curl
* @param SoapAttachment[] $soapAttachments */
* @param null $inputHeaders protected $curl = null;
* @param array|null $outputHeaders
/**
* Last request headers.
*
* @var string
*/
private $lastRequestHeaders = '';
/**
* Last request.
*
* @var string
*/
private $lastRequest = '';
/**
* Last response headers.
*
* @var string
*/
private $lastResponseHeaders = '';
/**
* Last response.
*
* @var string
*/
private $lastResponse = '';
/**
* Soap kernel.
*
* @var \BeSimple\SoapClient\SoapKernel
*/
protected $soapKernel = null;
/**
* Constructor.
*
* @param string $wsdl WSDL file
* @param array(string=>mixed) $options Options array
*/
public function __construct($wsdl, array $options = array())
{
// tracing enabled: store last request/response header and body
if (isset($options['trace']) && $options['trace'] === true) {
$this->tracingEnabled = true;
}
// store SOAP version
if (isset($options['soap_version'])) {
$this->soapVersion = $options['soap_version'];
}
$this->curl = new Curl($options);
if (isset($options['extra_options'])) {
unset($options['extra_options']);
}
$wsdlFile = $this->loadWsdl($wsdl, $options);
// TODO $wsdlHandler = new WsdlHandler($wsdlFile, $this->soapVersion);
$this->soapKernel = new SoapKernel();
// set up type converter and mime filter
$this->configureMime($options);
// we want the exceptions option to be set
$options['exceptions'] = true;
// disable obsolete trace option for native SoapClient as we need to do our own tracing anyways
$options['trace'] = false;
// disable WSDL caching as we handle WSDL caching for remote URLs ourself
$options['cache_wsdl'] = WSDL_CACHE_NONE;
parent::__construct($wsdlFile, $options);
}
/**
* Perform HTTP request with cURL.
*
* @param SoapRequest $soapRequest SoapRequest object
*
* @return SoapResponse * @return SoapResponse
*/ */
public function soapCall($functionName, array $arguments, array $soapAttachments = [], array $options = null, $inputHeaders = null, array &$outputHeaders = null) private function __doHttpRequest(SoapRequest $soapRequest)
{ {
ob_start(); // HTTP headers
parent::__soapCall($functionName, $arguments, $options, $inputHeaders, $outputHeaders); $soapVersion = $soapRequest->getVersion();
$nativeSoapClientRequest = $this->mapNativeDataJsonToDto(ob_get_clean()); $soapAction = $soapRequest->getAction();
if (SOAP_1_1 == $soapVersion) {
return $this->performSoapRequest( $headers = array(
$nativeSoapClientRequest->request, 'Content-Type:' . $soapRequest->getContentType(),
$nativeSoapClientRequest->location, 'SOAPAction: "' . $soapAction . '"',
$nativeSoapClientRequest->action, );
$nativeSoapClientRequest->version, } else {
$soapAttachments $headers = array(
'Content-Type:' . $soapRequest->getContentType() . '; action="' . $soapAction . '"',
); );
} }
$location = $soapRequest->getLocation();
$content = $soapRequest->getContent();
$headers = $this->filterRequestHeaders($soapRequest, $headers);
$options = $this->filterRequestOptions($soapRequest);
// execute HTTP request with cURL
$responseSuccessfull = $this->curl->exec(
$location,
$content,
$headers,
$options
);
// tracing enabled: store last request header and body
if ($this->tracingEnabled === true) {
$this->lastRequestHeaders = $this->curl->getRequestHeaders();
$this->lastRequest = $soapRequest->getContent();
}
// in case of an error while making the http request throw a soapFault
if ($responseSuccessfull === false) {
// get error message from curl
$faultstring = $this->curl->getErrorMessage();
throw new \SoapFault('HTTP', $faultstring);
}
// tracing enabled: store last response header and body
if ($this->tracingEnabled === true) {
$this->lastResponseHeaders = $this->curl->getResponseHeaders();
$this->lastResponse = $this->curl->getResponseBody();
}
// wrap response data in SoapResponse object
$soapResponse = SoapResponse::create(
$this->curl->getResponseBody(),
$soapRequest->getLocation(),
$soapRequest->getAction(),
$soapRequest->getVersion(),
$this->curl->getResponseContentType()
);
return $soapResponse;
}
/** /**
* This is not performing any HTTP requests, but it is getting data from SoapClient that are needed for this Client * Custom request method to be able to modify the SOAP messages.
* $oneWay parameter is not used at the moment.
* *
* @param string $request Request string * @param string $request Request string
* @param string $location Location * @param string $location Location
@ -131,280 +201,183 @@ class SoapClient extends \SoapClient
*/ */
public function __doRequest($request, $location, $action, $version, $oneWay = 0) public function __doRequest($request, $location, $action, $version, $oneWay = 0)
{ {
$soapClientNativeDataTransferObject = new SoapClientNativeDataTransferObject( // wrap request data in SoapRequest object
$request, $soapRequest = SoapRequest::create($request, $location, $action, $version);
$location,
$action,
$version
);
echo json_encode($soapClientNativeDataTransferObject);
return $request; // do actual SOAP request
$soapResponse = $this->__doRequest2($soapRequest);
// return SOAP response to ext/soap
return $soapResponse->getContent();
} }
/** /**
* Custom request method to be able to modify the SOAP messages. * Runs the currently registered request filters on the request, performs
* $oneWay parameter is not used at the moment. * the HTTP request and runs the response filters.
* *
* @param mixed $request Request object * @param SoapRequest $soapRequest SOAP request object
* @param string $location Location
* @param string $action SOAP action
* @param int $version SOAP version
* @param SoapAttachment[] $soapAttachments SOAP attachments array
* *
* @return SoapResponse * @return SoapResponse
*/ */
public function performSoapRequest($request, $location, $action, $version, array $soapAttachments = []) protected function __doRequest2(SoapRequest $soapRequest)
{ {
$soapRequest = $this->createSoapRequest($location, $action, $version, $request, $soapAttachments); // run SoapKernel on SoapRequest
$this->soapKernel->filterRequest($soapRequest);
return $this->performHttpSoapRequest($soapRequest); // perform HTTP request with cURL
} $soapResponse = $this->__doHttpRequest($soapRequest);
/** @deprecated */ // run SoapKernel on SoapResponse
public function __getLastRequestHeaders() $this->soapKernel->filterResponse($soapResponse);
{
$this->checkTracing();
throw new Exception(
'The __getLastRequestHeaders method is now deprecated. Use callSoapRequest instead and get the tracing information from SoapResponseTracingData.'
);
}
/** @deprecated */
public function __getLastRequest()
{
$this->checkTracing();
throw new Exception(
'The __getLastRequest method is now deprecated. Use callSoapRequest instead and get the tracing information from SoapResponseTracingData.'
);
}
/** @deprecated */
public function __getLastResponseHeaders()
{
$this->checkTracing();
throw new Exception(
'The __getLastResponseHeaders method is now deprecated. Use callSoapRequest instead and get the tracing information from SoapResponseTracingData.'
);
}
/** @deprecated */
public function __getLastResponse()
{
$this->checkTracing();
throw new Exception(
'The __getLastResponse method is now deprecated. Use callSoapRequest instead and get the tracing information from SoapResponseTracingData.'
);
}
/**
* @param string $location Location
* @param string $action SOAP action
* @param int $version SOAP version
* @param string $request SOAP request body
* @param SoapAttachment[] $soapAttachments array of SOAP attachments
*
* @return SoapRequest
*/
private function createSoapRequest($location, $action, $version, $request, array $soapAttachments = [])
{
$soapAttachmentList = new SoapAttachmentList($soapAttachments);
$soapRequest = SoapRequestFactory::create($location, $action, $version, $request);
if (count($soapAttachments) > 0) {
if ($this->soapOptions->hasAttachments() === true) {
$soapRequest->setAttachments(PartFactory::createAttachmentParts($soapAttachments));
$soapRequest = SoapKernel::filterRequest(
$soapRequest,
$this->getAttachmentFilters(),
$this->soapOptions->getAttachmentType()
);
} else {
throw new Exception(
'Non SWA SoapClient cannot handle SOAP action '.$action.' with attachments: '.implode(', ', $soapAttachmentList->getSoapAttachmentIds())
);
}
}
return $soapRequest;
}
/**
* Perform HTTP request with cURL.
*
* @param SoapRequest $soapRequest SoapRequest object
* @return SoapResponse
* @throws SoapFault
*/
private function performHttpSoapRequest(SoapRequest $soapRequest)
{
if ($soapRequest->getVersion() === SOAP_1_1) {
$headers = [
'Content-Type:' . $soapRequest->getContentType(),
'SOAPAction: "' . $soapRequest->getAction() . '"',
];
} else {
$headers = [
'Content-Type:' . $soapRequest->getContentType() . '; action="' . $soapRequest->getAction() . '"',
];
}
$curlResponse = $this->curl->executeCurlWithCachedSession(
$soapRequest->getLocation(),
$soapRequest->getContent(),
$headers
);
$soapResponseTracingData = new SoapResponseTracingData(
$curlResponse->getHttpRequestHeaders(),
$soapRequest->getContent(),
$curlResponse->getResponseHeader(),
$curlResponse->getResponseBody()
);
if ($curlResponse->curlStatusSuccess()) {
$soapResponse = $this->returnSoapResponseByTracing(
$this->soapClientOptions->getTrace(),
$soapRequest,
$curlResponse,
$soapResponseTracingData
);
if ($this->soapOptions->hasAttachments()) {
return SoapKernel::filterResponse(
$soapResponse,
$this->getAttachmentFilters(),
$this->soapOptions->getAttachmentType()
);
} else {
return $soapResponse; return $soapResponse;
} }
} else if ($curlResponse->curlStatusFailed()) {
return $this->throwSoapFaultByTracing( /**
$this->soapClientOptions->getTrace(), * Filters HTTP headers which will be sent
SoapFaultEnum::SOAP_FAULT_HTTP.'-'.$curlResponse->getHttpResponseStatusCode(), *
$curlResponse->getCurlErrorMessage(), * @param SoapRequest $soapRequest SOAP request object
$soapResponseTracingData * @param array $headers An array of HTTP headers
); *
} else { * @return array
*/
protected function filterRequestHeaders(SoapRequest $soapRequest, array $headers)
{
return $headers;
}
return $this->throwSoapFaultByTracing( /**
$this->soapClientOptions->getTrace(), * Adds additional cURL options for the request
SoapFaultEnum::SOAP_FAULT_SOAP_CLIENT_ERROR, *
'Cannot process curl response with unresolved status: ' . $curlResponse->getCurlStatus(), * @param SoapRequest $soapRequest SOAP request object
$soapResponseTracingData *
* @return array
*/
protected function filterRequestOptions(SoapRequest $soapRequest)
{
return array();
}
/**
* Get last request HTTP headers.
*
* @return string
*/
public function __getLastRequestHeaders()
{
return $this->lastRequestHeaders;
}
/**
* Get last request HTTP body.
*
* @return string
*/
public function __getLastRequest()
{
return $this->lastRequest;
}
/**
* Get last response HTTP headers.
*
* @return string
*/
public function __getLastResponseHeaders()
{
return $this->lastResponseHeaders;
}
/**
* Get last response HTTP body.
*
* @return string
*/
public function __getLastResponse()
{
return $this->lastResponse;
}
/**
* Get SoapKernel instance.
*
* @return \BeSimple\SoapClient\SoapKernel
*/
public function getSoapKernel()
{
return $this->soapKernel;
}
/**
* Configure filter and type converter for SwA/MTOM.
*
* @param array &$options SOAP constructor options array.
*
* @return void
*/
private function configureMime(array &$options)
{
if (isset($options['attachment_type']) && Helper::ATTACHMENTS_TYPE_BASE64 !== $options['attachment_type']) {
// register mime filter in SoapKernel
$mimeFilter = new MimeFilter($options['attachment_type']);
$this->soapKernel->registerFilter($mimeFilter);
// configure type converter
if (Helper::ATTACHMENTS_TYPE_SWA === $options['attachment_type']) {
$converter = new SwaTypeConverter();
$converter->setKernel($this->soapKernel);
} elseif (Helper::ATTACHMENTS_TYPE_MTOM === $options['attachment_type']) {
$xmlMimeFilter = new XmlMimeFilter($options['attachment_type']);
$this->soapKernel->registerFilter($xmlMimeFilter);
$converter = new MtomTypeConverter();
$converter->setKernel($this->soapKernel);
}
// configure typemap
if (!isset($options['typemap'])) {
$options['typemap'] = array();
}
$options['typemap'][] = array(
'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);
},
); );
} }
} }
/** /**
* @param Curl $curl * Downloads WSDL files with cURL. Uses all SoapClient options for
* @param string $wsdlPath * authentication. Uses the WSDL_CACHE_* constants and the 'soap.wsdl_*'
* @param int $wsdlCacheType * ini settings. Does only file caching as SoapClient only supports a file
* @param bool $resolveRemoteIncludes * name parameter.
*
* @param string $wsdl WSDL file
* @param array(string=>mixed) $options Options array
* *
* @return string * @return string
*/ */
private function loadWsdl(Curl $curl, $wsdlPath, $wsdlCacheType, $resolveRemoteIncludes = true) protected function loadWsdl($wsdl, array $options)
{ {
// option to resolve wsdl/xsd includes
$wsdlDownloader = new WsdlDownloader($curl); $resolveRemoteIncludes = true;
if (isset($options['resolve_wsdl_remote_includes'])) {
$resolveRemoteIncludes = $options['resolve_wsdl_remote_includes'];
}
// option to enable cache
$wsdlCache = WSDL_CACHE_DISK;
if (isset($options['cache_wsdl'])) {
$wsdlCache = $options['cache_wsdl'];
}
$wsdlDownloader = new WsdlDownloader($this->curl, $resolveRemoteIncludes, $wsdlCache);
try { try {
$loadedWsdlFilePath = $wsdlDownloader->getWsdlPath($curl, $wsdlPath, $wsdlCacheType, $resolveRemoteIncludes); $cacheFileName = $wsdlDownloader->download($wsdl);
} catch (Exception $e) { } catch (\RuntimeException $e) {
throw new SoapFault( throw new \SoapFault('WSDL', "SOAP-ERROR: Parsing WSDL: Couldn't load from '" . $wsdl . "' : failed to load external entity \"" . $wsdl . "\"");
SoapFaultEnum::SOAP_FAULT_WSDL,
'Unable to load WsdlPath: ' . $e->getMessage()
);
} }
return $loadedWsdlFilePath; return $cacheFileName;
}
private function getAttachmentFilters()
{
$filters = [];
if ($this->soapOptions->getAttachmentType() !== SoapOptions::SOAP_ATTACHMENTS_TYPE_BASE64) {
$filters[] = new MimeFilter();
}
if ($this->soapOptions->getAttachmentType() === SoapOptions::SOAP_ATTACHMENTS_TYPE_MTOM) {
$filters[] = new XmlMimeFilter();
}
return $filters;
}
private function mapNativeDataJsonToDto($nativeDataJson)
{
$nativeData = json_decode($nativeDataJson);
return new SoapClientNativeDataTransferObject(
$nativeData->request,
$nativeData->location,
$nativeData->action,
$nativeData->version
);
}
private function returnSoapResponseByTracing(
$isTracingEnabled,
SoapRequest $soapRequest,
CurlResponse $curlResponse,
SoapResponseTracingData $soapResponseTracingData,
array $soapAttachments = []
) {
if ($isTracingEnabled === true) {
return SoapResponseFactory::createWithTracingData(
$curlResponse->getResponseBody(),
$soapRequest->getLocation(),
$soapRequest->getAction(),
$soapRequest->getVersion(),
$curlResponse->getHttpResponseContentType(),
$soapResponseTracingData,
$soapAttachments
);
} else {
return SoapResponseFactory::create(
$curlResponse->getResponseBody(),
$soapRequest->getLocation(),
$soapRequest->getAction(),
$soapRequest->getVersion(),
$curlResponse->getHttpResponseContentType(),
$soapAttachments
);
}
}
private function throwSoapFaultByTracing($isTracingEnabled, $soapFaultCode, $soapFaultMessage, SoapResponseTracingData $soapResponseTracingData)
{
if ($isTracingEnabled === true) {
throw new SoapFaultWithTracingData(
$soapFaultCode,
$soapFaultMessage,
$soapResponseTracingData
);
} else {
throw new SoapFault(
$soapFaultCode,
$soapFaultMessage
);
}
}
private function checkTracing()
{
if ($this->soapClientOptions->getTrace() === false) {
throw new Exception('SoapClientOptions tracing disabled, turn on trace attribute');
}
} }
} }

View File

@ -12,44 +12,237 @@
namespace BeSimple\SoapClient; namespace BeSimple\SoapClient;
use BeSimple\SoapBundle\Cache; use BeSimple\SoapCommon\AbstractSoapBuilder;
use BeSimple\SoapClient\SoapOptions\SoapClientOptions; use BeSimple\SoapCommon\Helper;
use BeSimple\SoapCommon\SoapOptions\SoapOptions;
use Exception;
use SoapHeader;
/** /**
* Provides a SoapClient instance. * Fluent interface builder for SoapClient instance.
* *
* @author Francis Besset <francis.besset@gmail.com> * @author Francis Besset <francis.besset@gmail.com>
* @author Christian Kerl <christian-kerl@web.de> * @author Christian Kerl <christian-kerl@web.de>
* @author Petr Bechyně <mail@petrbechyne.com>
*/ */
class SoapClientBuilder class SoapClientBuilder extends AbstractSoapBuilder
{ {
public function build(SoapClientOptions $soapClientOptions, SoapOptions $soapOptions) /**
* Authentication options.
*
* @var array(string=>mixed)
*/
protected $soapOptionAuthentication = array();
/**
* Create new instance with default options.
*
* @return \BeSimple\SoapClient\SoapClientBuilder
*/
public static function createWithDefaults()
{ {
$cache = new Cache($soapOptions); return parent::createWithDefaults()
$cache->validateSettings($soapOptions); ->withUserAgent('BeSimpleSoap');
return new SoapClient(
$soapClientOptions,
$soapOptions
);
} }
public function buildWithSoapHeader( /**
SoapClientOptions $soapClientOptions, * Finally returns a SoapClient instance.
SoapOptions $soapOptions, *
SoapHeader $soapHeader * @return \BeSimple\SoapClient\SoapClient
) { */
$soapClient = $this->build($soapClientOptions, $soapOptions); public function build()
if ($soapClient->__setSoapHeaders($soapHeader) === false) { {
throw new Exception( $this->validateOptions();
'Could not set SoapHeader: '.var_export($soapHeader, true)
); return new SoapClient($this->wsdl, $this->getSoapOptions());
} }
return $soapClient; /**
* Get final array of SOAP options.
*
* @return array(string=>mixed)
*/
public function getSoapOptions()
{
return parent::getSoapOptions() + $this->soapOptionAuthentication;
}
/**
* Configure option 'trace'.
*
* @param boolean $trace Enable/Disable
*
* @return \BeSimple\SoapClient\SoapClientBuilder
*/
public function withTrace($trace = true)
{
$this->soapOptions['trace'] = $trace;
return $this;
}
/**
* Configure option 'exceptions'.
*
* @param boolean $exceptions Enable/Disable
*
* @return \BeSimple\SoapClient\SoapClientBuilder
*/
public function withExceptions($exceptions = true)
{
$this->soapOptions['exceptions'] = $exceptions;
return $this;
}
/**
* Configure option 'user_agent'.
*
* @param string $userAgent User agent string
*
* @return \BeSimple\SoapClient\SoapClientBuilder
*/
public function withUserAgent($userAgent)
{
$this->soapOptions['user_agent'] = $userAgent;
return $this;
}
/**
* Enable gzip compression.
*
* @return \BeSimple\SoapClient\SoapClientBuilder
*/
public function withCompressionGzip()
{
$this->soapOptions['compression'] = SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP;
return $this;
}
/**
* Enable deflate compression.
*
* @return \BeSimple\SoapClient\SoapClientBuilder
*/
public function withCompressionDeflate()
{
$this->soapOptions['compression'] = SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_DEFLATE;
return $this;
}
/**
* Configure basic authentication
*
* @param string $username Username
* @param string $password Password
*
* @return \BeSimple\SoapClient\SoapClientBuilder
*/
public function withBasicAuthentication($username, $password)
{
$this->soapOptionAuthentication = array(
'authentication' => SOAP_AUTHENTICATION_BASIC,
'login' => $username,
'password' => $password,
);
return $this;
}
/**
* Configure digest authentication.
*
* @param string $certificate Certificate
* @param string $passphrase Passphrase
*
* @return \BeSimple\SoapClient\SoapClientBuilder
*/
public function withDigestAuthentication($certificate, $passphrase = null)
{
$this->soapOptionAuthentication = array(
'authentication' => SOAP_AUTHENTICATION_DIGEST,
'local_cert' => $certificate,
);
if ($passphrase) {
$this->soapOptionAuthentication['passphrase'] = $passphrase;
}
return $this;
}
/**
* Configure proxy.
*
* @param string $host Host
* @param int $port Port
* @param string $login Login
* @param string $password Password
* @param int $auth Authentication method
*
* @return \BeSimple\SoapClient\SoapClientBuilder
*/
public function withProxy($host, $port, $login = null, $password = null, $auth = null)
{
$this->soapOptions['proxy_host'] = $host;
$this->soapOptions['proxy_port'] = $port;
if ($login) {
$this->soapOptions['proxy_login'] = $login;
$this->soapOptions['proxy_password'] = $password;
if ($auth) {
if (!in_array($auth, array(\CURLAUTH_BASIC, \CURLAUTH_NTLM), true)) {
throw new \InvalidArgumentException('Invalid authentication method: CURLAUTH_BASIC or CURLAUTH_NTLM constants are availables.');
}
$this->soapOptions['proxy_auth'] = $auth;
}
}
return $this;
}
/**
* SOAP attachment type Base64.
*
* @return \BeSimple\SoapServer\SoapServerBuilder
*/
public function withBase64Attachments()
{
$this->options['attachment_type'] = Helper::ATTACHMENTS_TYPE_BASE64;
return $this;
}
/**
* SOAP attachment type SwA.
*
* @return \BeSimple\SoapServer\SoapServerBuilder
*/
public function withSwaAttachments()
{
$this->options['attachment_type'] = Helper::ATTACHMENTS_TYPE_SWA;
return $this;
}
/**
* SOAP attachment type MTOM.
*
* @return \BeSimple\SoapServer\SoapServerBuilder
*/
public function withMtomAttachments()
{
$this->options['attachment_type'] = Helper::ATTACHMENTS_TYPE_MTOM;
return $this;
}
/**
* Validate options.
*/
protected function validateOptions()
{
$this->validateWsdl();
} }
} }

View File

@ -1,7 +0,0 @@
<?php
namespace BeSimple\SoapClient;
class SoapClientMessageWithAttachments
{
}

View File

@ -1,19 +0,0 @@
<?php
namespace BeSimple\SoapClient;
class SoapClientNativeDataTransferObject
{
public $request;
public $location;
public $action;
public $version;
public function __construct($request, $location, $action, $version)
{
$this->request = $request;
$this->location = $location;
$this->action = $action;
$this->version = $version;
}
}

View File

@ -1,58 +0,0 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace BeSimple\SoapClient;
use BeSimple\SoapClient\Curl\CurlOptions;
use BeSimple\SoapClient\SoapOptions\SoapClientOptions;
use BeSimple\SoapClient\SoapServerAuthentication\SoapServerAuthenticationInterface;
/**
* Provides a SoapClient instance.
*
* @author Francis Besset <francis.besset@gmail.com>
* @author Christian Kerl <christian-kerl@web.de>
* @author Petr Bechyně <mail@petrbechyne.com>
*/
class SoapClientOptionsBuilder
{
public static function createWithDefaults()
{
return new SoapClientOptions(
SoapClientOptions::SOAP_CLIENT_TRACE_OFF,
SoapClientOptions::SOAP_CLIENT_EXCEPTIONS_ON,
CurlOptions::DEFAULT_USER_AGENT,
SoapClientOptions::SOAP_CLIENT_COMPRESSION_NONE
);
}
public static function createWithTracing()
{
return new SoapClientOptions(
SoapClientOptions::SOAP_CLIENT_TRACE_ON,
SoapClientOptions::SOAP_CLIENT_EXCEPTIONS_ON,
CurlOptions::DEFAULT_USER_AGENT,
SoapClientOptions::SOAP_CLIENT_COMPRESSION_NONE
);
}
public static function createWithAuthentication(SoapServerAuthenticationInterface $authentication)
{
return new SoapClientOptions(
SoapClientOptions::SOAP_CLIENT_TRACE_ON,
SoapClientOptions::SOAP_CLIENT_EXCEPTIONS_ON,
CurlOptions::DEFAULT_USER_AGENT,
SoapClientOptions::SOAP_CLIENT_COMPRESSION_NONE,
$authentication
);
}
}

View File

@ -1,21 +0,0 @@
<?php
namespace BeSimple\SoapClient;
use SoapFault;
class SoapFaultWithTracingData extends SoapFault
{
private $soapResponseTracingData;
public function __construct($code = 0, $message = "", SoapResponseTracingData $soapResponseTracingData)
{
$this->soapResponseTracingData = $soapResponseTracingData;
parent::__construct($code, $message);
}
public function getSoapResponseTracingData()
{
return $this->soapResponseTracingData;
}
}

View File

@ -0,0 +1,47 @@
<?php
/*
* This file is part of the BeSimpleSoapCommon.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
* (c) Andreas Schamberger <mail@andreass.net>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace BeSimple\SoapClient;
use BeSimple\SoapCommon\SoapKernel as CommonSoapKernel;
use BeSimple\SoapCommon\SoapRequest as CommonSoapRequest;
use BeSimple\SoapCommon\SoapResponse as CommonSoapResponse;
/**
* SoapKernel for Client.
*
* @author Andreas Schamberger <mail@andreass.net>
*/
class SoapKernel extends CommonSoapKernel
{
/**
* {@inheritDoc}
*/
public function filterRequest(CommonSoapRequest $request)
{
$request->setAttachments($this->attachments);
$this->attachments = array();
parent::filterRequest($request);
}
/**
* {@inheritDoc}
*/
public function filterResponse(CommonSoapResponse $response)
{
parent::filterResponse($response);
$this->attachments = $response->getAttachments();
}
}

View File

@ -1,120 +0,0 @@
<?php
namespace BeSimple\SoapClient\SoapOptions;
use BeSimple\SoapClient\Curl\CurlOptions;
use BeSimple\SoapClient\SoapServerAuthentication\SoapServerAuthenticationBasic;
use BeSimple\SoapClient\SoapServerAuthentication\SoapServerAuthenticationDigest;
use BeSimple\SoapClient\SoapServerAuthentication\SoapServerAuthenticationInterface;
use BeSimple\SoapClient\SoapServerProxy\SoapServerProxy;
class SoapClientOptions
{
const SOAP_CLIENT_TRACE_ON = true;
const SOAP_CLIENT_TRACE_OFF = false;
const SOAP_CLIENT_EXCEPTIONS_ON = true;
const SOAP_CLIENT_EXCEPTIONS_OFF = false;
const SOAP_CLIENT_COMPRESSION_NONE = CurlOptions::SOAP_COMPRESSION_NONE;
const SOAP_CLIENT_COMPRESSION_GZIP = CurlOptions::SOAP_COMPRESSION_GZIP;
const SOAP_CLIENT_COMPRESSION_DEFLATE = CurlOptions::SOAP_COMPRESSION_DEFLATE;
private $trace;
private $exceptions;
private $userAgent;
private $compression;
private $authentication;
private $proxy;
/**
* @param bool $trace = SoapClientOptions::SOAP_CLIENT_TRACE_ON|SoapClientOptions::SOAP_CLIENT_TRACE_OFF
* @param bool $exceptions = SoapClientOptions::SOAP_CLIENT_EXCEPTIONS_ON|SoapClientOptions::SOAP_CLIENT_EXCEPTIONS_OFF
* @param string $userAgent
* @param int $compression = SoapClientOptions::SOAP_CLIENT_COMPRESSION_NONE|SoapClientOptions::SOAP_CLIENT_COMPRESSION_GZIP|SoapClientOptions::SOAP_CLIENT_COMPRESSION_DEFLATE
* @param SoapServerAuthenticationInterface $authentication = null
* @param SoapServerProxy $proxy = null
*/
public function __construct($trace, $exceptions, $userAgent, $compression = null, SoapServerAuthenticationInterface $authentication = null, SoapServerProxy $proxy = null)
{
$this->trace = $trace;
$this->exceptions = $exceptions;
$this->userAgent = $userAgent;
$this->compression = $compression;
$this->authentication = $authentication;
$this->proxy = $proxy;
}
public function getTrace()
{
return $this->trace;
}
public function getExceptions()
{
return $this->exceptions;
}
public function getUserAgent()
{
return $this->userAgent;
}
public function hasCompression()
{
return $this->compression !== self::SOAP_CLIENT_COMPRESSION_NONE;
}
public function getCompression()
{
return $this->compression;
}
public function hasAuthentication()
{
return $this->authentication !== null;
}
public function hasAuthenticationBasic()
{
return $this->hasAuthentication() && $this->getAuthentication() instanceof SoapServerAuthenticationBasic;
}
public function hasAuthenticationDigest()
{
return $this->hasAuthentication() && $this->getAuthentication() instanceof SoapServerAuthenticationDigest;
}
public function hasProxy()
{
return $this->proxy !== null;
}
public function getAuthentication()
{
return $this->authentication;
}
public function getProxy()
{
return $this->proxy;
}
public function toArray()
{
$optionsAsArray = [
'trace' => $this->getTrace(),
'exceptions' => $this->getExceptions(),
'user_agent' => $this->getUserAgent(),
];
if ($this->hasCompression()) {
$optionsAsArray['compression'] = $this->getCompression();
}
if ($this->hasAuthentication()) {
$optionsAsArray += $this->getAuthentication()->toArray();
}
if ($this->hasProxy()) {
$optionsAsArray += $this->getProxy()->toArray();
}
return $optionsAsArray;
}
}

View File

@ -0,0 +1,48 @@
<?php
/*
* This file is part of the BeSimpleSoapClient.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace BeSimple\SoapClient;
use BeSimple\SoapCommon\SoapRequest as CommonSoapRequest;
use BeSimple\SoapCommon\SoapMessage;
/**
* SoapRequest class for SoapClient. Provides factory function for request object.
*
* @author Andreas Schamberger <mail@andreass.net>
*/
class SoapRequest extends CommonSoapRequest
{
/**
* Factory function for SoapRequest.
*
* @param string $content Content
* @param string $location Location
* @param string $action SOAP action
* @param string $version SOAP version
*
* @return BeSimple\SoapClient\SoapRequest
*/
public static function create($content, $location, $action, $version)
{
$request = new SoapRequest();
// $content is if unmodified from SoapClient not a php string type!
$request->setContent((string) $content);
$request->setLocation($location);
$request->setAction($action);
$request->setVersion($version);
$contentType = SoapMessage::getContentTypeForVersion($version);
$request->setContentType($contentType);
return $request;
}
}

View File

@ -1,13 +1,46 @@
<?php <?php
/*
* This file is part of the BeSimpleSoapClient.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace BeSimple\SoapClient; namespace BeSimple\SoapClient;
use BeSimple\SoapCommon\SoapResponse as CommonSoapResponse; use BeSimple\SoapCommon\SoapResponse as CommonSoapResponse;
/**
* SoapResponse class for SoapClient. Provides factory function for response object.
*
* @author Andreas Schamberger <mail@andreass.net>
*/
class SoapResponse extends CommonSoapResponse class SoapResponse extends CommonSoapResponse
{ {
public function getResponseContent() /**
* Factory function for SoapResponse.
*
* @param string $content Content
* @param string $location Location
* @param string $action SOAP action
* @param string $version SOAP version
* @param string $contentType Content type header
*
* @return BeSimple\SoapClient\SoapResponse
*/
public static function create($content, $location, $action, $version, $contentType)
{ {
return $this->getContent(); $response = new SoapResponse();
$response->setContent($content);
$response->setLocation($location);
$response->setAction($action);
$response->setVersion($version);
$response->setContentType($contentType);
return $response;
} }
} }

View File

@ -1,98 +0,0 @@
<?php
/*
* This file is part of the BeSimpleSoapClient.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace BeSimple\SoapClient;
use BeSimple\SoapBundle\Soap\SoapAttachment;
use BeSimple\SoapCommon\Mime\PartFactory;
/**
* SoapResponseFactory for SoapClient. Provides factory function for SoapResponse object.
*
* @author Andreas Schamberger <mail@andreass.net>
* @author Petr Bechyně <mail@petrbechyne.com>
*/
class SoapResponseFactory
{
/**
* Factory method for SoapClient\SoapResponse.
*
* @param string $content Content
* @param string $location Location
* @param string $action SOAP action
* @param string $version SOAP version
* @param string $contentType Content type header
* @param SoapAttachment[] $attachments SOAP attachments
* @return SoapResponse
*/
public static function create(
$content,
$location,
$action,
$version,
$contentType,
array $attachments = []
) {
$response = new SoapResponse();
$response->setContent($content);
$response->setLocation($location);
$response->setAction($action);
$response->setVersion($version);
$response->setContentType($contentType);
if (count($attachments) > 0) {
$response->setAttachments(
self::createAttachmentParts($attachments)
);
}
return $response;
}
/**
* Factory method for SoapClient\SoapResponse with SoapResponseTracingData.
*
* @param string $content Content
* @param string $location Location
* @param string $action SOAP action
* @param string $version SOAP version
* @param string $contentType Content type header
* @param SoapResponseTracingData $tracingData Data value object suitable for tracing SOAP traffic
* @param SoapAttachment[] $attachments SOAP attachments
* @return SoapResponse
*/
public static function createWithTracingData(
$content,
$location,
$action,
$version,
$contentType,
SoapResponseTracingData $tracingData,
array $attachments = []
) {
$response = new SoapResponse();
$response->setContent($content);
$response->setLocation($location);
$response->setAction($action);
$response->setVersion($version);
$response->setContentType($contentType);
if ($tracingData !== null) {
$response->setTracingData($tracingData);
}
if (count($attachments) > 0) {
$response->setAttachments(
PartFactory::createAttachmentParts($attachments)
);
}
return $response;
}
}

View File

@ -1,39 +0,0 @@
<?php
namespace BeSimple\SoapClient;
class SoapResponseTracingData
{
private $lastRequestHeaders;
private $lastRequest;
private $lastResponseHeaders;
private $lastResponse;
public function __construct($lastRequestHeaders, $lastRequest, $lastResponseHeaders, $lastResponse)
{
$this->lastRequestHeaders = $lastRequestHeaders;
$this->lastRequest = $lastRequest;
$this->lastResponseHeaders = $lastResponseHeaders;
$this->lastResponse = $lastResponse;
}
public function getLastRequestHeaders()
{
return $this->lastRequestHeaders;
}
public function getLastRequest()
{
return $this->lastRequest;
}
public function getLastResponseHeaders()
{
return $this->lastResponseHeaders;
}
public function getLastResponse()
{
return $this->lastResponse;
}
}

View File

@ -1,39 +0,0 @@
<?php
namespace BeSimple\SoapClient\SoapServerAuthentication;
class SoapServerAuthenticationBasic implements SoapServerAuthenticationInterface
{
private $login;
private $password;
public function __construct($login, $password)
{
$this->login = $login;
$this->password = $password;
}
public function getAuthentication()
{
return \SOAP_AUTHENTICATION_BASIC;
}
public function getLogin()
{
return $this->login;
}
public function getPassword()
{
return $this->password;
}
public function toArray()
{
return [
'authentication' => $this->getAuthentication(),
'login' => $this->getLogin(),
'password' => $this->getPassword(),
];
}
}

View File

@ -1,52 +0,0 @@
<?php
namespace BeSimple\SoapClient\SoapServerAuthentication;
class SoapServerAuthenticationDigest implements SoapServerAuthenticationInterface
{
private $localCert;
private $passPhrase;
/**
* @param string $localCert
* @param string $passPhrase = null
*/
public function __construct($localCert, $passPhrase = null)
{
$this->localCert = $localCert;
$this->passPhrase = $passPhrase;
}
public function getLocalCert()
{
return $this->localCert;
}
public function hasPassPhrase()
{
return $this->passPhrase !== null;
}
public function getPassPhrase()
{
return $this->passPhrase;
}
public function getAuthentication()
{
return \SOAP_AUTHENTICATION_DIGEST;
}
public function toArray()
{
$authenticationAsArray = [
'authentication' => $this->getAuthentication(),
'local_cert' => $this->getLocalCert()
];
if ($this->hasPassPhrase()) {
$authenticationAsArray['passphrase'] = $this->getPassPhrase();
}
return $authenticationAsArray;
}
}

View File

@ -1,16 +0,0 @@
<?php
namespace BeSimple\SoapClient\SoapServerAuthentication;
interface SoapServerAuthenticationInterface
{
/**
* @return int
*/
public function getAuthentication();
/**
* @return array
*/
public function toArray();
}

View File

@ -1,84 +0,0 @@
<?php
namespace BeSimple\SoapClient\SoapServerProxy;
class SoapServerProxy
{
const PROXY_AUTHENTICATION_TYPE_NONE = null;
const PROXY_AUTHENTICATION_TYPE_BASIC = \CURLAUTH_BASIC;
const PROXY_AUTHENTICATION_TYPE_NTLM = \CURLAUTH_NTLM;
private $host;
private $port;
private $login;
private $password;
private $authenticationType;
/**
* @param string $host
* @param int $port
* @param string $login = null
* @param string $password = null
* @param int $authenticationType = null|SoapServerProxy::PROXY_AUTHENTICATION_TYPE_BASIC|SoapServerProxy::PROXY_AUTHENTICATION_TYPE_NTLM
*/
public function __construct($host, $port, $login = null, $password = null, $authenticationType = null)
{
$this->host = $host;
$this->port = $port;
$this->login = $login;
$this->password = $password;
$this->authenticationType = $authenticationType;
}
public function getHost()
{
return $this->host;
}
public function getPort()
{
return $this->port;
}
public function hasCredentials()
{
return $this->login !== null;
}
public function getLogin()
{
return $this->login;
}
public function getPassword()
{
return $this->password;
}
public function hasAuthenticationType()
{
return $this->authenticationType !== self::PROXY_AUTHENTICATION_TYPE_NONE;
}
public function getAuthenticationType()
{
return $this->authenticationType;
}
public function toArray()
{
$proxyAsArray = [
'proxy_host' => $this->getHost(),
'proxy_port' => $this->getPort(),
];
if ($this->hasCredentials()) {
$proxyAsArray['proxy_login'] = $this->getLogin();
$proxyAsArray['proxy_password'] = $this->getPassword();
}
if ($this->hasAuthenticationType()) {
$proxyAsArray['proxy_auth'] = $this->getAuthenticationType();
}
return $proxyAsArray;
}
}

View File

@ -23,8 +23,7 @@ abstract class AbstractWebServerTest extends \PHPUnit_Framework_TestCase
/** /**
* @var ProcessBuilder * @var ProcessBuilder
*/ */
static protected $webserver; protected static $webserver;
static protected $websererPortLength;
public static function setUpBeforeClass() public static function setUpBeforeClass()
{ {
@ -44,8 +43,6 @@ abstract class AbstractWebServerTest extends \PHPUnit_Framework_TestCase
self::$webserver->start(); self::$webserver->start();
usleep(100000); usleep(100000);
self::$websererPortLength = strlen(WEBSERVER_PORT);
} }
public static function tearDownAfterClass() public static function tearDownAfterClass()

View File

@ -74,7 +74,7 @@ class WsSecurityUserPassAxisInteropTest extends TestCase
$sc = new BeSimpleSoapClient(__DIR__.'/Fixtures/WsSecurityUserPass.wsdl', $this->options); $sc = new BeSimpleSoapClient(__DIR__.'/Fixtures/WsSecurityUserPass.wsdl', $this->options);
$wssFilter = new BeSimpleWsSecurityFilter(true, 600); $wssFilter = new BeSimpleWsSecurityFilter(true, 600);
$wssFilter->addUserData( 'libuser', 'books', BeSimpleWsSecurityFilter::PASSWORD_TYPE_DIGEST ); $wssFilter->addUserData('libuser', 'books', BeSimpleWsSecurityFilter::PASSWORD_TYPE_DIGEST);
$soapKernel = $sc->getSoapKernel(); $soapKernel = $sc->getSoapKernel();
$soapKernel->registerFilter($wssFilter); $soapKernel->registerFilter($wssFilter);

View File

@ -12,8 +12,7 @@
namespace BeSimple\SoapClient\Tests; namespace BeSimple\SoapClient\Tests;
use BeSimple\SoapClient\Curl\Curl; use BeSimple\SoapClient\Curl;
use BeSimple\SoapClient\Curl\CurlOptionsBuilder;
/** /**
* @author Andreas Schamberger <mail@andreass.net> * @author Andreas Schamberger <mail@andreass.net>
@ -22,12 +21,11 @@ class CurlTest extends AbstractWebserverTest
{ {
public function testExec() public function testExec()
{ {
$curlOptions = CurlOptionsBuilder::buildDefault(); $curl = new Curl(array(
$curl = new Curl( 'proxy_host' => false,
$curlOptions ));
);
$this->assertTrue($curl->executeCurl($curlOptions, sprintf('http://localhost:%d/curl.txt', WEBSERVER_PORT))); $this->assertTrue($curl->exec(sprintf('http://localhost:%d/curl.txt', WEBSERVER_PORT)));
$this->assertTrue($curl->exec(sprintf('http://localhost:%d/404.txt', WEBSERVER_PORT))); $this->assertTrue($curl->exec(sprintf('http://localhost:%d/404.txt', WEBSERVER_PORT)));
} }
@ -47,19 +45,6 @@ class CurlTest extends AbstractWebserverTest
$this->assertEquals('Unable to parse URL', $curl->getErrorMessage()); $this->assertEquals('Unable to parse URL', $curl->getErrorMessage());
} }
public function testGetRequestHeaders()
{
$curl = new Curl(array(
'proxy_host' => false,
));
$curl->exec(sprintf('http://localhost:%d/curl.txt', WEBSERVER_PORT));
$this->assertEquals(132 + self::$websererPortLength, strlen($curl->getRequestHeaders()));
$curl->exec(sprintf('http://localhost:%s/404.txt', WEBSERVER_PORT));
$this->assertEquals(131 + self::$websererPortLength, strlen($curl->getRequestHeaders()));
}
public function testGetResponse() public function testGetResponse()
{ {
$curl = new Curl(array( $curl = new Curl(array(
@ -68,7 +53,6 @@ class CurlTest extends AbstractWebserverTest
$curl->exec(sprintf('http://localhost:%d/curl.txt', WEBSERVER_PORT)); $curl->exec(sprintf('http://localhost:%d/curl.txt', WEBSERVER_PORT));
$this->assertSame('OK', $curl->getResponseStatusMessage()); $this->assertSame('OK', $curl->getResponseStatusMessage());
$this->assertEquals(145 + self::$websererPortLength, strlen($curl->getResponse()));
$curl->exec(sprintf('http://localhost:%d/404.txt', WEBSERVER_PORT)); $curl->exec(sprintf('http://localhost:%d/404.txt', WEBSERVER_PORT));
$this->assertSame('Not Found', $curl->getResponseStatusMessage()); $this->assertSame('Not Found', $curl->getResponseStatusMessage());
@ -83,4 +67,30 @@ class CurlTest extends AbstractWebserverTest
$curl->exec(sprintf('http://localhost:%d/curl.txt', WEBSERVER_PORT)); $curl->exec(sprintf('http://localhost:%d/curl.txt', WEBSERVER_PORT));
$this->assertEquals('This is a testfile for cURL.', $curl->getResponseBody()); $this->assertEquals('This is a testfile for cURL.', $curl->getResponseBody());
} }
public function testGetResponseContentType()
{
$curl = new Curl(array(
'proxy_host' => false,
));
$curl->exec(sprintf('http://localhost:%d/curl.txt', WEBSERVER_PORT));
$this->assertEquals('text/plain; charset=UTF-8', $curl->getResponseContentType());
$curl->exec(sprintf('http://localhost:%d/404.txt', WEBSERVER_PORT));
$this->assertEquals('text/html; charset=UTF-8', $curl->getResponseContentType());
}
public function testGetResponseStatusCode()
{
$curl = new Curl(array(
'proxy_host' => false,
));
$curl->exec(sprintf('http://localhost:%d/curl.txt', WEBSERVER_PORT));
$this->assertEquals(200, $curl->getResponseStatusCode());
$curl->exec(sprintf('http://localhost:%d/404.txt', WEBSERVER_PORT));
$this->assertEquals(404, $curl->getResponseStatusCode());
}
} }

View File

@ -1,8 +0,0 @@
<?php
namespace BeSimple\SoapClient\Tests;
class GenerateTestRequest
{
public $salutation;
}

View File

@ -1,8 +0,0 @@
<?php
namespace BeSimple\SoapClient\Tests;
class GetUKLocationByCounty
{
public $County;
}

View File

@ -1,23 +0,0 @@
# HOW TO PREPARE Mock SWA Service
1. Create an test endpoint by using tools such as mockable.io, that will return response (expect POST requests with SOAP v1.1)
similar to the one provided in example file src/BeSimple/SoapClient/Tests/Mock/MockSwaService.example.response
and Content-Type headers from src/BeSimple/SoapClient/Tests/Mock/MockSwaService.example.response.headers
Example Endpoint URL: https://demo0580999.mockable.io/soap/testGenerator
2. Create a test WSDL endpoint that will return WSDL file from (expect GET requests)
an example file src/BeSimple/SoapClient/Tests/Mock/MockSwaService.wsdl
Example WSDL endpoint URL: https://demo0580999.mockable.io/soap/testGenerator?WSDL
3. Take the two endpoints and configure SoapClientBuilderTest::TEST_ENDPOINT_SWA
and SoapClientBuilderTest::TEST_REMOTE_WSDL_SWA variables
4. The test BeSimple\SoapClient\Tests\SoapClientBuilderTest::testSoapCallSwaWithAttachmentsOnResponse should work correctly.
If not, try to catch SoapFaultWithTracingData thrown by the soapCall method:
$soapClient->soapCall('generateTest', [$generateTestRequest]);
You can print the SoapFaultWithTracingData attributes in order to investigate the SoapClient request and request headers.

View File

@ -1,18 +0,0 @@
--Part_13_58a1b01a466a6.58a1b01a466e8
Content-Type: application/soap+xml; charset=utf-8
Content-Transfer-Encoding: 8bit
Content-ID: <part-72f5d209-2631-42ee-81d1-e554af739ce6@response.info>
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://schema.testcase"><env:Body xmlns:rpc="http://www.w3.org/2003/05/soap-rpc"><ns1:generateTestResponse><rpc:result>generateTestReturn</rpc:result><generateTestReturn><fileName>dummy-attachment.txt</fileName></generateTestReturn></ns1:generateTestResponse></env:Body></env:Envelope>
--Part_13_58a1b01a466a6.58a1b01a466e8
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
Content-ID: <dummy-attachment.txt>
Content-Location: dummy-attachment.txt
Hello world!
--Part_13_58a1b01a466a6.58a1b01a466e8--

View File

@ -1 +0,0 @@
multipart/related; type="application/soap+xml"; charset=utf-8; boundary=Part_13_58a1b01a466a6.58a1b01a466e8; start="<part-72f5d209-2631-42ee-81d1-e554af739ce6@response.info>"

View File

@ -1,61 +0,0 @@
<?xml version="1.0"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://schema.testcase" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://schema.testcase">
<wsdl:types>
<xsd:schema targetNamespace="http://schema.testcase">
<xsd:complexType name="SoapHeaderEntity">
<xsd:sequence>
<xsd:element name="user" type="xsd:string" minOccurs="1">
<xsd:annotation>
<xsd:documentation>User name for authorization</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="SoapHeader" type="tns:SoapHeaderEntity"/>
<xsd:complexType name="GenerateTestRequest">
<xsd:sequence>
<xsd:element name="salutation" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="GenerateTestResponse">
<xsd:sequence>
<xsd:element name="fileName" type="xsd:string" minOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
</wsdl:types>
<message name="SoapHeader">
<part name="SoapHeader" element="tns:SoapHeader"/>
</message>
<message name="GenerateTestRequest">
<part name="request" type="tns:GenerateTestRequest"/>
</message>
<message name="GenerateTestResponse">
<part name="generateTestReturn" type="tns:GenerateTestResponse"/>
</message>
<wsdl:portType name="TestGeneratorServiceSoapPortType">
<wsdl:operation name="generateTest">
<wsdl:input message="tns:GenerateTestRequest"/>
<wsdl:output message="tns:GenerateTestResponse"/>
</wsdl:operation>
</wsdl:portType>
<binding name="TestGeneratorServiceSoapBinding" type="tns:TestGeneratorServiceSoapPortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="generateTest">
<soap:operation soapAction="TestGeneratorService.generateTest" style="rpc"/>
<wsdl:input>
<soap:header use="literal" message="tns:SoapHeader" part="SoapHeader" namespace="http://schema.testcase"/>
<soap:body use="literal" part="request" namespace="http://schema.testcase"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal" namespace="http://schema.testcase"/>
</wsdl:output>
</wsdl:operation>
</binding>
<wsdl:service name="TestGeneratorService">
<xsd:documentation>WSDL file for TestGeneratorService</xsd:documentation>
<port name="TestGeneratorServiceSoapPortType" binding="tns:TestGeneratorServiceSoapBinding">
<soap:address location="https://demo0580999.mockable.io/soap/testGenerator"/>
</port>
</wsdl:service>
</wsdl:definitions>

View File

@ -36,7 +36,6 @@ try {
$attachment->binaryData = $b64; $attachment->binaryData = $b64;
var_dump($sc->attachment($attachment)); var_dump($sc->attachment($attachment));
} catch (Exception $e) { } catch (Exception $e) {
var_dump($e); var_dump($e);
} }

View File

@ -29,7 +29,6 @@ $options = array(
$sc = new BeSimpleSoapClient(__DIR__.'/Fixtures/SwA.wsdl', $options); $sc = new BeSimpleSoapClient(__DIR__.'/Fixtures/SwA.wsdl', $options);
try { try {
$upload = new uploadFile(); $upload = new uploadFile();
$upload->name = 'upload.txt'; $upload->name = 'upload.txt';
$upload->data = 'This is a test. :)'; $upload->data = 'This is a test. :)';

View File

@ -69,7 +69,6 @@ try {
$ab->type = 'scifi'; $ab->type = 'scifi';
var_dump($sc->addBook($ab)); var_dump($sc->addBook($ab));
} catch (Exception $e) { } catch (Exception $e) {
var_dump($e); var_dump($e);
} }

View File

@ -54,7 +54,6 @@ try {
$ab->type = 'scifi'; $ab->type = 'scifi';
var_dump($sc->addBook($ab)); var_dump($sc->addBook($ab));
} catch (Exception $e) { } catch (Exception $e) {
var_dump($e); var_dump($e);
} }

View File

@ -63,7 +63,7 @@ class WsSecurityUserPassServerInteropTest extends TestCase
$sc = new BeSimpleSoapClient(__DIR__.'/Fixtures/WsSecurityUserPass.wsdl', $this->options); $sc = new BeSimpleSoapClient(__DIR__.'/Fixtures/WsSecurityUserPass.wsdl', $this->options);
$wssFilter = new BeSimpleWsSecurityFilter(true, 600); $wssFilter = new BeSimpleWsSecurityFilter(true, 600);
$wssFilter->addUserData( 'libuser', 'books', BeSimpleWsSecurityFilter::PASSWORD_TYPE_DIGEST ); $wssFilter->addUserData('libuser', 'books', BeSimpleWsSecurityFilter::PASSWORD_TYPE_DIGEST);
$soapKernel = $sc->getSoapKernel(); $soapKernel = $sc->getSoapKernel();
$soapKernel->registerFilter($wssFilter); $soapKernel->registerFilter($wssFilter);

View File

@ -12,286 +12,113 @@
namespace BeSimple\SoapClient\Tests; namespace BeSimple\SoapClient\Tests;
use BeSimple\SoapBundle\Soap\SoapAttachment;
use BeSimple\SoapClient\Curl\CurlOptions;
use BeSimple\SoapClient\SoapClientBuilder; use BeSimple\SoapClient\SoapClientBuilder;
use BeSimple\SoapClient\SoapClientOptionsBuilder;
use BeSimple\SoapClient\SoapFaultWithTracingData;
use BeSimple\SoapClient\SoapOptions\SoapClientOptions;
use BeSimple\SoapCommon\ClassMap;
use BeSimple\SoapCommon\SoapOptions\SoapOptions;
use BeSimple\SoapCommon\SoapOptionsBuilder;
use Exception;
use SoapHeader;
class SoapClientBuilderTest extends \PHPUnit_Framework_TestCase class SoapClientBuilderTest extends \PHPUnit_Framework_TestCase
{ {
const CACHE_DIR = __DIR__ . '/../../../../cache'; private $defaultOptions = array(
const TEST_ENDPOINT_UK = 'http://www.webservicex.net/uklocation.asmx'; 'features' => 0,
const TEST_REMOTE_WSDL_UK = 'http://www.webservicex.net/uklocation.asmx?WSDL'; 'classmap' => array(),
const TEST_LOCAL_WSDL_UK = __DIR__.'/localWsdl.wsdl'; 'typemap' => array(),
const TEST_REMOTE_WSDL_NOT_WORKING = 'http://www.nosuchserverexist.tld/doesnotexist.endpoint?wsdl'; );
const TEST_ENDPOINT_SWA = 'https://demo2815480.mockable.io/soap/testGenerator';
const TEST_REMOTE_WSDL_SWA = 'https://demo2815480.mockable.io/soap/testGenerator?WSDL';
public function testSoapOptionsCreateWithDefaults() public function testContruct()
{ {
$defaultOptions = SoapOptionsBuilder::createWithDefaults(self::TEST_LOCAL_WSDL_UK); $options = $this
->getSoapBuilder()
->getSoapOptions()
;
self::assertInstanceOf(SoapOptions::class, $defaultOptions); $this->assertEquals($this->mergeOptions(array()), $options);
self::assertEquals(self::TEST_LOCAL_WSDL_UK, $defaultOptions->getWsdlFile());
} }
public function testSoapClientOptionsCreateWithDefaults() public function testWithTrace()
{ {
$defaultOptions = SoapClientOptionsBuilder::createWithDefaults(); $builder = $this->getSoapBuilder();
self::assertInstanceOf(SoapClientOptions::class, $defaultOptions); $builder->withTrace();
self::assertEquals(CurlOptions::DEFAULT_USER_AGENT, $defaultOptions->getUserAgent()); $this->assertEquals($this->mergeOptions(array('trace' => true)), $builder->getSoapOptions());
$builder->withTrace(false);
$this->assertEquals($this->mergeOptions(array('trace' => false)), $builder->getSoapOptions());
} }
public function testConstructSoapClientWithDefaults() public function testWithExceptions()
{ {
$soapClient = $this->getSoapBuilder()->build( $builder = $this->getSoapBuilder();
SoapClientOptionsBuilder::createWithDefaults(),
SoapOptionsBuilder::createWithDefaults(self::TEST_REMOTE_WSDL_UK)
);
self::assertInstanceOf(\SoapClient::class, $soapClient); $builder->withExceptions();
$this->assertEquals($this->mergeOptions(array('exceptions' => true)), $builder->getSoapOptions());
$builder->withExceptions(false);
$this->assertEquals($this->mergeOptions(array('exceptions' => false)), $builder->getSoapOptions());
} }
public function testConstructSoapClientWithSwaAndClassMapAndCacheDisk() public function testWithUserAgent()
{ {
$soapOptions = SoapOptionsBuilder::createSwaWithClassMap( $builder = $this->getSoapBuilder();
self::TEST_REMOTE_WSDL_UK,
new ClassMap(),
SoapOptions::SOAP_CACHE_TYPE_DISK,
__DIR__.'/../../../../cache'
);
$soapClient = $this->getSoapBuilder()->build( $builder->withUserAgent('BeSimpleSoap Test');
SoapClientOptionsBuilder::createWithDefaults(), $this->assertEquals($this->mergeOptions(array('user_agent' => 'BeSimpleSoap Test')), $builder->getSoapOptions());
$soapOptions
);
self::assertInstanceOf(\SoapClient::class, $soapClient);
} }
public function testConstructSoapClientWithDefaultsAndLocalWsdlFile() public function testWithCompression()
{ {
$soapClient = $this->getSoapBuilder()->build( $builder = $this->getSoapBuilder();
SoapClientOptionsBuilder::createWithDefaults(),
SoapOptionsBuilder::createWithDefaults(self::TEST_LOCAL_WSDL_UK)
);
self::assertInstanceOf(\SoapClient::class, $soapClient); $builder->withCompressionGzip();
$this->assertEquals($this->mergeOptions(array('compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP)), $builder->getSoapOptions());
$builder->withCompressionDeflate();
$this->assertEquals($this->mergeOptions(array('compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_DEFLATE)), $builder->getSoapOptions());
} }
public function testConstructSoapClientWithSwaAndClassMapAndCacheDiskAndLocalWsdlFile() public function testWithAuthentication()
{ {
$soapOptions = SoapOptionsBuilder::createSwaWithClassMap( $builder = $this->getSoapBuilder();
self::TEST_LOCAL_WSDL_UK,
new ClassMap(),
SoapOptions::SOAP_CACHE_TYPE_DISK,
__DIR__ .'/../../../../cache'
);
$soapClient = $this->getSoapBuilder()->build( $builder->withDigestAuthentication(__DIR__.'/Fixtures/cert.pem', 'foobar');
SoapClientOptionsBuilder::createWithDefaults(), $this->assertEquals($this->mergeOptions(array('authentication' => SOAP_AUTHENTICATION_DIGEST, 'local_cert' => __DIR__.'/Fixtures/cert.pem', 'passphrase' => 'foobar')), $builder->getSoapOptions());
$soapOptions
);
self::assertInstanceOf(\SoapClient::class, $soapClient); $builder->withDigestAuthentication(__DIR__.'/Fixtures/cert.pem');
$this->assertEquals($this->mergeOptions(array('authentication' => SOAP_AUTHENTICATION_DIGEST, 'local_cert' => __DIR__.'/Fixtures/cert.pem')), $builder->getSoapOptions());
$builder->withBasicAuthentication('foo', 'bar');
$this->assertEquals($this->mergeOptions(array('authentication' => SOAP_AUTHENTICATION_BASIC, 'login' => 'foo', 'password' => 'bar')), $builder->getSoapOptions());
} }
public function testSoapCall() public function testWithProxy()
{ {
$soapClient = $this->getSoapBuilder()->build( $builder = $this->getSoapBuilder();
SoapClientOptionsBuilder::createWithDefaults(),
SoapOptionsBuilder::createWithDefaults(self::TEST_REMOTE_WSDL_UK)
);
$getUKLocationByCountyRequest = new GetUKLocationByCounty();
$getUKLocationByCountyRequest->County = 'London';
$soapResponse = $soapClient->soapCall('GetUKLocationByCounty', [$getUKLocationByCountyRequest]);
self::assertContains('GetUKLocationByCountyResult', $soapResponse->getContent()); $builder->withProxy('localhost', 8080);
self::assertContains('</GetUKLocationByCountyResponse>', $soapResponse->getContent()); $this->assertEquals($this->mergeOptions(array('proxy_host' => 'localhost', 'proxy_port' => 8080)), $builder->getSoapOptions());
self::assertEquals(self::TEST_ENDPOINT_UK, $soapResponse->getLocation());
}
public function testSoapCallWithCacheEndpointDownShouldFail() $builder->withProxy('127.0.0.1', 8585, 'foo', 'bar');
{ $this->assertEquals($this->mergeOptions(array('proxy_host' => '127.0.0.1', 'proxy_port' => 8585, 'proxy_login' => 'foo', 'proxy_password' => 'bar')), $builder->getSoapOptions());
$this->setExpectedException(Exception::class, 'Could not write WSDL cache file: Download failed with message');
$this->getSoapBuilder()->build( $builder->withProxy('127.0.0.1', 8585, 'foo', 'bar', \CURLAUTH_BASIC);
SoapClientOptionsBuilder::createWithDefaults(), $this->assertEquals($this->mergeOptions(array('proxy_host' => '127.0.0.1', 'proxy_port' => 8585, 'proxy_login' => 'foo', 'proxy_password' => 'bar', 'proxy_auth' => \CURLAUTH_BASIC)), $builder->getSoapOptions());
SoapOptionsBuilder::createWithDefaults(
self::TEST_REMOTE_WSDL_NOT_WORKING,
SoapOptions::SOAP_CACHE_TYPE_DISK,
__DIR__ .'/../../../../cache'
)
);
}
public function testSoapCallEndpointDownShouldFail() $builder->withProxy('127.0.0.1', 8585, 'foo', 'bar', \CURLAUTH_NTLM);
{ $this->assertEquals($this->mergeOptions(array('proxy_host' => '127.0.0.1', 'proxy_port' => 8585, 'proxy_login' => 'foo', 'proxy_password' => 'bar', 'proxy_auth' => \CURLAUTH_NTLM)), $builder->getSoapOptions());
$this->setExpectedException(Exception::class, 'Parsing WSDL: Couldn\'t load from');
$this->getSoapBuilder()->build(
SoapClientOptionsBuilder::createWithDefaults(),
SoapOptionsBuilder::createWithDefaults(self::TEST_REMOTE_WSDL_NOT_WORKING)
);
}
public function testSoapCallNoSwaWithAttachmentMustFail()
{
$this->setExpectedException(Exception::class, 'Non SWA SoapClient cannot handle SOAP action');
$soapClient = $this->getSoapBuilder()->build(
SoapClientOptionsBuilder::createWithDefaults(),
SoapOptionsBuilder::createWithDefaults(self::TEST_REMOTE_WSDL_UK)
);
$getUKLocationByCountyRequest = new GetUKLocationByCounty();
$getUKLocationByCountyRequest->County = 'London';
$soapClient->soapCall(
'GetUKLocationByCounty',
[$getUKLocationByCountyRequest],
[
new SoapAttachment(
'first-file.txt',
'text/plain',
'unexpected file - no SWA - must fail'
),
]
);
}
public function testSoapCallSwaWithTwoAttachments()
{
$soapClient = $this->getSoapBuilder()->build(
SoapClientOptionsBuilder::createWithTracing(),
SoapOptionsBuilder::createSwaWithClassMap(
self::TEST_REMOTE_WSDL_UK,
new ClassMap(),
SoapOptions::SOAP_CACHE_TYPE_DISK,
__DIR__ .'/../../../../cache'
)
);
$getUKLocationByCountyRequest = new GetUKLocationByCounty();
$getUKLocationByCountyRequest->County = 'London';
try { try {
$soapResponse = $soapClient->soapCall( $builder->withProxy('127.0.0.1', 8585, 'foo', 'bar', -100);
'GetUKLocationByCounty',
[$getUKLocationByCountyRequest], $this->fail('An expected exception has not been raised.');
[ } catch (\Exception $e) {
new SoapAttachment( $this->assertInstanceOf('InvalidArgumentException', $e);
'first-file.txt', }
'text/plain',
'hello world'
),
new SoapAttachment(
'second-file.txt',
'text/plain',
'hello world'
)
]
);
$tracingData = $soapResponse->getTracingData();
} catch (SoapFaultWithTracingData $e) {
$tracingData = $e->getSoapResponseTracingData();
} }
self::assertEquals( public function testCreateWithDefaults()
$this->getContentId($tracingData->getLastRequestHeaders()),
$this->getContentId($tracingData->getLastRequest()),
'Content ID must match in request XML and Content-Type: ...; start header'
);
self::assertEquals(
$this->getMultiPartBoundary($tracingData->getLastRequestHeaders()),
$this->getMultiPartBoundary($tracingData->getLastRequest()),
'MultiPart boundary must match in request XML and Content-Type: ...; boundary header'
);
self::assertContains('boundary=Part_', $tracingData->getLastRequestHeaders(), 'Headers should link to boundary');
self::assertContains('start="<part-', $tracingData->getLastRequestHeaders(), 'Headers should link to first MultiPart');
self::assertContains('action="', $tracingData->getLastRequestHeaders(), 'Headers should contain SOAP action');
self::assertEquals(
$this->removeOneTimeData(file_get_contents(__DIR__.'/soapRequestWithTwoAttachments.request')),
$this->removeOneTimeData($tracingData->getLastRequest()),
'Requests must match after onetime data were removed'
);
}
public function testSoapCallSwaWithNoAttachments()
{ {
$soapClient = $this->getSoapBuilder()->build( $builder = SoapClientBuilder::createWithDefaults();
SoapClientOptionsBuilder::createWithTracing(),
SoapOptionsBuilder::createSwaWithClassMap(
self::TEST_REMOTE_WSDL_UK,
new ClassMap(),
SoapOptions::SOAP_CACHE_TYPE_DISK,
__DIR__ .'/../../../../cache'
)
);
$getUKLocationByCountyRequest = new GetUKLocationByCounty();
$getUKLocationByCountyRequest->County = 'London';
try { $this->assertInstanceOf('BeSimple\SoapClient\SoapClientBuilder', $builder);
$soapResponse = $soapClient->soapCall(
'GetUKLocationByCounty',
[$getUKLocationByCountyRequest]
);
$tracingData = $soapResponse->getTracingData();
} catch (SoapFaultWithTracingData $e) {
$tracingData = $e->getSoapResponseTracingData();
}
self::assertNotContains('boundary=Part_', $tracingData->getLastRequestHeaders(), 'Headers should link to boundary'); $this->assertEquals($this->mergeOptions(array('soap_version' => SOAP_1_2, 'encoding' => 'UTF-8', 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, 'user_agent' => 'BeSimpleSoap')), $builder->getSoapOptions());
self::assertNotContains('start="<part-', $tracingData->getLastRequestHeaders(), 'Headers should link to first MultiPart');
self::assertContains('action="', $tracingData->getLastRequestHeaders(), 'Headers should contain SOAP action');
self::assertEquals(
file_get_contents(__DIR__.'/soapRequestWithNoAttachments.request'),
$tracingData->getLastRequest(),
'Requests must match'
);
}
/**
* @see This test needs a working SWA endpoint. Examine Tests/Mock directory for details
*/
public function testSoapCallSwaWithAttachmentsOnResponse()
{
$soapClient = $this->getSoapBuilder()->buildWithSoapHeader(
SoapClientOptionsBuilder::createWithTracing(),
SoapOptionsBuilder::createSwaWithClassMapV11(
self::TEST_REMOTE_WSDL_SWA,
new ClassMap([
'GenerateTestRequest' => GenerateTestRequest::class,
]),
SoapOptions::SOAP_CACHE_TYPE_DISK,
__DIR__ . '/../../../../cache'
),
new SoapHeader('http://schema.testcase', 'SoapHeader', [
'user' => 'admin',
])
);
$generateTestRequest = new GenerateTestRequest();
$generateTestRequest->salutation = 'World';
$soapResponse = $soapClient->soapCall('generateTest', [$generateTestRequest]);
$attachments = $soapResponse->getAttachments();
self::assertContains('</generateTestReturn>', $soapResponse->getResponseContent());
self::assertTrue($soapResponse->hasAttachments());
self::assertCount(1, $attachments);
$firstAttachment = reset($attachments);
self::assertEquals('text/plain', $firstAttachment->getHeader('Content-Type'));
file_put_contents(self::CACHE_DIR . '/testSoapCallSwaWithAttachmentsOnResponse.xml', $soapResponse->getContent());
file_put_contents(self::CACHE_DIR . '/testSoapCallSwaWithAttachmentsOnResponse.txt', $firstAttachment->getContent());
} }
private function getSoapBuilder() private function getSoapBuilder()
@ -299,41 +126,8 @@ class SoapClientBuilderTest extends \PHPUnit_Framework_TestCase
return new SoapClientBuilder(); return new SoapClientBuilder();
} }
public function removeOneTimeData($string) private function mergeOptions(array $options)
{ {
$contentId = $this->getContentId($string); return array_merge($this->defaultOptions, $options);
$multiPartBoundary = $this->getMultiPartBoundary($string);
return str_replace(
$contentId,
'{content-id-placeholder}',
str_replace(
$multiPartBoundary,
'{multipart-boundary-placeholder}',
$string
)
);
}
private function getMultiPartBoundary($string)
{
$realMultiParts = null;
preg_match('/Part\_[0-9]{2}\_[a-zA-Z0-9]{13}\.[a-zA-Z0-9]{13}/', $string, $realMultiParts);
if (count($realMultiParts) > 0) {
return $realMultiParts[0];
}
throw new Exception('Could not find real MultiPart boundary');
}
private function getContentId($string)
{
$realContentIds = null;
preg_match('/part\-[0-9a-f]{8}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{12}\@response\.info/', $string, $realContentIds);
if (count($realContentIds) > 0) {
return $realContentIds[0];
}
throw new Exception('Could not find real contentId');
} }
} }

View File

@ -25,9 +25,9 @@ use org\bovigo\vfs\vfsStreamWrapper;
*/ */
class WsdlDownloaderTest extends AbstractWebserverTest class WsdlDownloaderTest extends AbstractWebserverTest
{ {
static protected $filesystem; protected static $filesystem;
static protected $fixturesPath; protected static $fixturesPath;
/** /**
* @dataProvider provideDownload * @dataProvider provideDownload
@ -278,7 +278,7 @@ class WsdlDownloaderTest extends AbstractWebserverTest
$content = file_get_contents(self::$fixturesPath.$file); $content = file_get_contents(self::$fixturesPath.$file);
$content = preg_replace('#'.preg_quote('%location%').'#', sprintf('localhost:%d', WEBSERVER_PORT), $content); $content = preg_replace('#'.preg_quote('%location%').'#', sprintf('localhost:%d', WEBSERVER_PORT), $content);
self::$filesystem->dumpFile(self::$fixturesPath.'build_include'.DIRECTORY_SEPARATOR.pathinfo($file, PATHINFO_BASENAME), $content); file_put_contents(self::$fixturesPath.'build_include'.DIRECTORY_SEPARATOR.pathinfo($file, PATHINFO_BASENAME), $content);
} }
} }

View File

@ -1,380 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="http://www.webserviceX.NET" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" targetNamespace="http://www.webserviceX.NET" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get UK Postcode,Town,County and Validate UK Address</wsdl:documentation>
<wsdl:types>
<s:schema elementFormDefault="qualified" targetNamespace="http://www.webserviceX.NET">
<s:element name="GetUKLocationByCounty">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="County" type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="GetUKLocationByCountyResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="GetUKLocationByCountyResult" type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="GetUKLocationByTown">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="Town" type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="GetUKLocationByTownResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="GetUKLocationByTownResult" type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="GetUKLocationByPostCode">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="PostCode" type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="GetUKLocationByPostCodeResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="GetUKLocationByPostCodeResult" type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="ValidateUKAddress">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="Town" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="County" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="PostCode" type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="ValidateUKAddressResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="ValidateUKAddressResult" type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="string" nillable="true" type="s:string" />
</s:schema>
</wsdl:types>
<wsdl:message name="GetUKLocationByCountySoapIn">
<wsdl:part name="parameters" element="tns:GetUKLocationByCounty" />
</wsdl:message>
<wsdl:message name="GetUKLocationByCountySoapOut">
<wsdl:part name="parameters" element="tns:GetUKLocationByCountyResponse" />
</wsdl:message>
<wsdl:message name="GetUKLocationByTownSoapIn">
<wsdl:part name="parameters" element="tns:GetUKLocationByTown" />
</wsdl:message>
<wsdl:message name="GetUKLocationByTownSoapOut">
<wsdl:part name="parameters" element="tns:GetUKLocationByTownResponse" />
</wsdl:message>
<wsdl:message name="GetUKLocationByPostCodeSoapIn">
<wsdl:part name="parameters" element="tns:GetUKLocationByPostCode" />
</wsdl:message>
<wsdl:message name="GetUKLocationByPostCodeSoapOut">
<wsdl:part name="parameters" element="tns:GetUKLocationByPostCodeResponse" />
</wsdl:message>
<wsdl:message name="ValidateUKAddressSoapIn">
<wsdl:part name="parameters" element="tns:ValidateUKAddress" />
</wsdl:message>
<wsdl:message name="ValidateUKAddressSoapOut">
<wsdl:part name="parameters" element="tns:ValidateUKAddressResponse" />
</wsdl:message>
<wsdl:message name="GetUKLocationByCountyHttpGetIn">
<wsdl:part name="County" type="s:string" />
</wsdl:message>
<wsdl:message name="GetUKLocationByCountyHttpGetOut">
<wsdl:part name="Body" element="tns:string" />
</wsdl:message>
<wsdl:message name="GetUKLocationByTownHttpGetIn">
<wsdl:part name="Town" type="s:string" />
</wsdl:message>
<wsdl:message name="GetUKLocationByTownHttpGetOut">
<wsdl:part name="Body" element="tns:string" />
</wsdl:message>
<wsdl:message name="GetUKLocationByPostCodeHttpGetIn">
<wsdl:part name="PostCode" type="s:string" />
</wsdl:message>
<wsdl:message name="GetUKLocationByPostCodeHttpGetOut">
<wsdl:part name="Body" element="tns:string" />
</wsdl:message>
<wsdl:message name="ValidateUKAddressHttpGetIn">
<wsdl:part name="Town" type="s:string" />
<wsdl:part name="County" type="s:string" />
<wsdl:part name="PostCode" type="s:string" />
</wsdl:message>
<wsdl:message name="ValidateUKAddressHttpGetOut">
<wsdl:part name="Body" element="tns:string" />
</wsdl:message>
<wsdl:message name="GetUKLocationByCountyHttpPostIn">
<wsdl:part name="County" type="s:string" />
</wsdl:message>
<wsdl:message name="GetUKLocationByCountyHttpPostOut">
<wsdl:part name="Body" element="tns:string" />
</wsdl:message>
<wsdl:message name="GetUKLocationByTownHttpPostIn">
<wsdl:part name="Town" type="s:string" />
</wsdl:message>
<wsdl:message name="GetUKLocationByTownHttpPostOut">
<wsdl:part name="Body" element="tns:string" />
</wsdl:message>
<wsdl:message name="GetUKLocationByPostCodeHttpPostIn">
<wsdl:part name="PostCode" type="s:string" />
</wsdl:message>
<wsdl:message name="GetUKLocationByPostCodeHttpPostOut">
<wsdl:part name="Body" element="tns:string" />
</wsdl:message>
<wsdl:message name="ValidateUKAddressHttpPostIn">
<wsdl:part name="Town" type="s:string" />
<wsdl:part name="County" type="s:string" />
<wsdl:part name="PostCode" type="s:string" />
</wsdl:message>
<wsdl:message name="ValidateUKAddressHttpPostOut">
<wsdl:part name="Body" element="tns:string" />
</wsdl:message>
<wsdl:portType name="UKLocationSoap">
<wsdl:operation name="GetUKLocationByCounty">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get UK town,Postcode and County by full /partial County</wsdl:documentation>
<wsdl:input message="tns:GetUKLocationByCountySoapIn" />
<wsdl:output message="tns:GetUKLocationByCountySoapOut" />
</wsdl:operation>
<wsdl:operation name="GetUKLocationByTown">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get UK town,Postcode and County by full /partial Town</wsdl:documentation>
<wsdl:input message="tns:GetUKLocationByTownSoapIn" />
<wsdl:output message="tns:GetUKLocationByTownSoapOut" />
</wsdl:operation>
<wsdl:operation name="GetUKLocationByPostCode">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get UK town,Postcode and County by Postcode(First Section of Post Code)</wsdl:documentation>
<wsdl:input message="tns:GetUKLocationByPostCodeSoapIn" />
<wsdl:output message="tns:GetUKLocationByPostCodeSoapOut" />
</wsdl:operation>
<wsdl:operation name="ValidateUKAddress">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Validate UK address,Use First Section of Poscode for Postcode atribute</wsdl:documentation>
<wsdl:input message="tns:ValidateUKAddressSoapIn" />
<wsdl:output message="tns:ValidateUKAddressSoapOut" />
</wsdl:operation>
</wsdl:portType>
<wsdl:portType name="UKLocationHttpGet">
<wsdl:operation name="GetUKLocationByCounty">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get UK town,Postcode and County by full /partial County</wsdl:documentation>
<wsdl:input message="tns:GetUKLocationByCountyHttpGetIn" />
<wsdl:output message="tns:GetUKLocationByCountyHttpGetOut" />
</wsdl:operation>
<wsdl:operation name="GetUKLocationByTown">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get UK town,Postcode and County by full /partial Town</wsdl:documentation>
<wsdl:input message="tns:GetUKLocationByTownHttpGetIn" />
<wsdl:output message="tns:GetUKLocationByTownHttpGetOut" />
</wsdl:operation>
<wsdl:operation name="GetUKLocationByPostCode">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get UK town,Postcode and County by Postcode(First Section of Post Code)</wsdl:documentation>
<wsdl:input message="tns:GetUKLocationByPostCodeHttpGetIn" />
<wsdl:output message="tns:GetUKLocationByPostCodeHttpGetOut" />
</wsdl:operation>
<wsdl:operation name="ValidateUKAddress">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Validate UK address,Use First Section of Poscode for Postcode atribute</wsdl:documentation>
<wsdl:input message="tns:ValidateUKAddressHttpGetIn" />
<wsdl:output message="tns:ValidateUKAddressHttpGetOut" />
</wsdl:operation>
</wsdl:portType>
<wsdl:portType name="UKLocationHttpPost">
<wsdl:operation name="GetUKLocationByCounty">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get UK town,Postcode and County by full /partial County</wsdl:documentation>
<wsdl:input message="tns:GetUKLocationByCountyHttpPostIn" />
<wsdl:output message="tns:GetUKLocationByCountyHttpPostOut" />
</wsdl:operation>
<wsdl:operation name="GetUKLocationByTown">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get UK town,Postcode and County by full /partial Town</wsdl:documentation>
<wsdl:input message="tns:GetUKLocationByTownHttpPostIn" />
<wsdl:output message="tns:GetUKLocationByTownHttpPostOut" />
</wsdl:operation>
<wsdl:operation name="GetUKLocationByPostCode">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get UK town,Postcode and County by Postcode(First Section of Post Code)</wsdl:documentation>
<wsdl:input message="tns:GetUKLocationByPostCodeHttpPostIn" />
<wsdl:output message="tns:GetUKLocationByPostCodeHttpPostOut" />
</wsdl:operation>
<wsdl:operation name="ValidateUKAddress">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Validate UK address,Use First Section of Poscode for Postcode atribute</wsdl:documentation>
<wsdl:input message="tns:ValidateUKAddressHttpPostIn" />
<wsdl:output message="tns:ValidateUKAddressHttpPostOut" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="UKLocationSoap" type="tns:UKLocationSoap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="GetUKLocationByCounty">
<soap:operation soapAction="http://www.webserviceX.NET/GetUKLocationByCounty" style="document" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="GetUKLocationByTown">
<soap:operation soapAction="http://www.webserviceX.NET/GetUKLocationByTown" style="document" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="GetUKLocationByPostCode">
<soap:operation soapAction="http://www.webserviceX.NET/GetUKLocationByPostCode" style="document" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="ValidateUKAddress">
<soap:operation soapAction="http://www.webserviceX.NET/ValidateUKAddress" style="document" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:binding name="UKLocationSoap12" type="tns:UKLocationSoap">
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="GetUKLocationByCounty">
<soap12:operation soapAction="http://www.webserviceX.NET/GetUKLocationByCounty" style="document" />
<wsdl:input>
<soap12:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap12:body use="literal" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="GetUKLocationByTown">
<soap12:operation soapAction="http://www.webserviceX.NET/GetUKLocationByTown" style="document" />
<wsdl:input>
<soap12:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap12:body use="literal" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="GetUKLocationByPostCode">
<soap12:operation soapAction="http://www.webserviceX.NET/GetUKLocationByPostCode" style="document" />
<wsdl:input>
<soap12:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap12:body use="literal" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="ValidateUKAddress">
<soap12:operation soapAction="http://www.webserviceX.NET/ValidateUKAddress" style="document" />
<wsdl:input>
<soap12:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap12:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:binding name="UKLocationHttpGet" type="tns:UKLocationHttpGet">
<http:binding verb="GET" />
<wsdl:operation name="GetUKLocationByCounty">
<http:operation location="/GetUKLocationByCounty" />
<wsdl:input>
<http:urlEncoded />
</wsdl:input>
<wsdl:output>
<mime:mimeXml part="Body" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="GetUKLocationByTown">
<http:operation location="/GetUKLocationByTown" />
<wsdl:input>
<http:urlEncoded />
</wsdl:input>
<wsdl:output>
<mime:mimeXml part="Body" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="GetUKLocationByPostCode">
<http:operation location="/GetUKLocationByPostCode" />
<wsdl:input>
<http:urlEncoded />
</wsdl:input>
<wsdl:output>
<mime:mimeXml part="Body" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="ValidateUKAddress">
<http:operation location="/ValidateUKAddress" />
<wsdl:input>
<http:urlEncoded />
</wsdl:input>
<wsdl:output>
<mime:mimeXml part="Body" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:binding name="UKLocationHttpPost" type="tns:UKLocationHttpPost">
<http:binding verb="POST" />
<wsdl:operation name="GetUKLocationByCounty">
<http:operation location="/GetUKLocationByCounty" />
<wsdl:input>
<mime:content type="application/x-www-form-urlencoded" />
</wsdl:input>
<wsdl:output>
<mime:mimeXml part="Body" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="GetUKLocationByTown">
<http:operation location="/GetUKLocationByTown" />
<wsdl:input>
<mime:content type="application/x-www-form-urlencoded" />
</wsdl:input>
<wsdl:output>
<mime:mimeXml part="Body" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="GetUKLocationByPostCode">
<http:operation location="/GetUKLocationByPostCode" />
<wsdl:input>
<mime:content type="application/x-www-form-urlencoded" />
</wsdl:input>
<wsdl:output>
<mime:mimeXml part="Body" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="ValidateUKAddress">
<http:operation location="/ValidateUKAddress" />
<wsdl:input>
<mime:content type="application/x-www-form-urlencoded" />
</wsdl:input>
<wsdl:output>
<mime:mimeXml part="Body" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="UKLocation">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get UK Postcode,Town,County and Validate UK Address</wsdl:documentation>
<wsdl:port name="UKLocationSoap" binding="tns:UKLocationSoap">
<soap:address location="http://www.webservicex.net/uklocation.asmx" />
</wsdl:port>
<wsdl:port name="UKLocationSoap12" binding="tns:UKLocationSoap12">
<soap12:address location="http://www.webservicex.net/uklocation.asmx" />
</wsdl:port>
<wsdl:port name="UKLocationHttpGet" binding="tns:UKLocationHttpGet">
<http:address location="http://www.webservicex.net/uklocation.asmx" />
</wsdl:port>
<wsdl:port name="UKLocationHttpPost" binding="tns:UKLocationHttpPost">
<http:address location="http://www.webservicex.net/uklocation.asmx" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

View File

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://www.webserviceX.NET"><env:Body><ns1:GetUKLocationByCounty><ns1:County>London</ns1:County></ns1:GetUKLocationByCounty></env:Body></env:Envelope>

View File

@ -1,24 +0,0 @@
--Part_10_589b2dcf4f7fb.589b2dcf4f804
Content-Type: application/soap+xml; charset=utf-8
Content-Transfer-Encoding: 8bit
Content-ID: <part-7e61b8e0-f84d-4cf7-8043-3c27d90767af@response.info>
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://www.webserviceX.NET"><env:Body><ns1:GetUKLocationByCounty><ns1:County>London</ns1:County></ns1:GetUKLocationByCounty></env:Body></env:Envelope>
--Part_10_589b2dcf4f7fb.589b2dcf4f804
Content-Type: application/pdf; charset=utf-8
Content-Transfer-Encoding: binary
Content-ID: <first-file.txt>
Content-Location: first-file.txt
hello world
--Part_10_589b2dcf4f7fb.589b2dcf4f804
Content-Type: application/pdf; charset=utf-8
Content-Transfer-Encoding: binary
Content-ID: <second-file.txt>
Content-Location: second-file.txt
hello world
--Part_10_589b2dcf4f7fb.589b2dcf4f804--

View File

@ -157,7 +157,6 @@ class WsAddressingFilter implements SoapRequestFilter, SoapResponseFilter
public function getReferenceParameter($ns, $parameter) public function getReferenceParameter($ns, $parameter)
{ {
if (isset($this->referenceParametersRecieved[$ns][$parameter])) { if (isset($this->referenceParametersRecieved[$ns][$parameter])) {
return $this->referenceParametersRecieved[$ns][$parameter]; return $this->referenceParametersRecieved[$ns][$parameter];
} }

View File

@ -151,7 +151,6 @@ class WsSecurityFilter extends WsSecurityFilterClientServer implements SoapReque
if (null !== $this->password if (null !== $this->password
&& (null === $this->userSecurityKey && (null === $this->userSecurityKey
|| (null !== $this->userSecurityKey && !$this->userSecurityKey->hasPrivateKey()))) { || (null !== $this->userSecurityKey && !$this->userSecurityKey->hasPrivateKey()))) {
if (self::PASSWORD_TYPE_DIGEST === $this->passwordType) { if (self::PASSWORD_TYPE_DIGEST === $this->passwordType) {
$nonce = mt_rand(); $nonce = mt_rand();
$password = base64_encode(sha1($nonce . $createdTimestamp . $this->password, true)); $password = base64_encode(sha1($nonce . $createdTimestamp . $this->password, true));

View File

@ -12,13 +12,8 @@
namespace BeSimple\SoapClient; namespace BeSimple\SoapClient;
use BeSimple\SoapClient\Curl\Curl;
use BeSimple\SoapCommon\Cache; use BeSimple\SoapCommon\Cache;
use BeSimple\SoapCommon\Helper; use BeSimple\SoapCommon\Helper;
use DOMDocument;
use DOMElement;
use DOMXPath;
use Exception;
/** /**
* Downloads WSDL files with cURL. Uses the WSDL_CACHE_* constants and the * Downloads WSDL files with cURL. Uses the WSDL_CACHE_* constants and the
@ -31,178 +26,191 @@ use Exception;
class WsdlDownloader class WsdlDownloader
{ {
/** /**
* @param Curl $curl * Cache enabled.
* @param string $wsdlPath WSDL file URL/path *
* @param int $wsdCacheType = Cache::TYPE_NONE|Cache::WSDL_CACHE_DISK|Cache::WSDL_CACHE_BOTH|Cache::WSDL_CACHE_MEMORY * @var bool
* @param boolean $resolveRemoteIncludes
* @return string
*/ */
public function getWsdlPath(Curl $curl, $wsdlPath, $wsdCacheType, $resolveRemoteIncludes = true) protected $cacheEnabled;
/**
* Cache dir.
*
* @var string
*/
protected $cacheDir;
/**
* Cache TTL.
*
* @var int
*/
protected $cacheTtl;
/**
* cURL instance for downloads.
*
* @var unknown_type
*/
protected $curl;
/**
* Resolve WSDl/XSD includes.
*
* @var bool
*/
protected $resolveRemoteIncludes = true;
/**
* Constructor.
*
* @param \BeSimple\SoapClient\Curl $curl Curl instance
* @param bool $resolveRemoteIncludes WSDL/XSD include enabled?
* @param bool $cacheWsdl Cache constant
*/
public function __construct(Curl $curl, $resolveRemoteIncludes = true, $cacheWsdl = Cache::TYPE_DISK)
{ {
$isRemoteFile = $this->isRemoteFile($wsdlPath); $this->curl = $curl;
$isCacheEnabled = $wsdCacheType === Cache::TYPE_NONE ? false : Cache::isEnabled(); $this->resolveRemoteIncludes = (bool) $resolveRemoteIncludes;
if ($isCacheEnabled === true) {
$cacheFilePath = Cache::getDirectory().DIRECTORY_SEPARATOR.'wsdl_'.md5($wsdlPath).'.cache';
$isCacheExisting = file_exists($cacheFilePath);
if ($isCacheExisting) {
$fileModificationTime = filemtime($cacheFilePath);
if ($fileModificationTime === false) {
throw new Exception('File modification time could not be get for wsdl path: ' . $cacheFilePath);
}
$isCacheValid = ($fileModificationTime + Cache::getLifetime()) >= time();
} else {
$isCacheExisting = $isCacheValid = false;
}
if ($isCacheExisting === false || $isCacheValid === false) {
$this->writeCacheFile($curl, $wsdCacheType, $wsdlPath, $cacheFilePath, $resolveRemoteIncludes, $isRemoteFile);
}
return $this->getLocalWsdlPath($cacheFilePath); // get current WSDL caching config
$this->cacheEnabled = $cacheWsdl === Cache::TYPE_NONE ? Cache::DISABLED : Cache::ENABLED == Cache::isEnabled();
} else { $this->cacheDir = Cache::getDirectory();
$this->cacheTtl = Cache::getLifetime();
if ($isRemoteFile === true) {
return $wsdlPath;
}
return $this->getLocalWsdlPath($wsdlPath);
}
}
private function writeCacheFile(Curl $curl, $cacheType, $wsdlPath, $cacheFilePath, $resolveRemoteIncludes, $isRemoteFile)
{
if ($isRemoteFile === true) {
$curlResponse = $curl->executeCurlWithCachedSession($wsdlPath);
if ($curlResponse->curlStatusSuccess()) {
if (mb_strlen($curlResponse->getResponseBody()) === 0) {
throw new Exception('Could not write WSDL cache file: curl response empty');
}
if ($resolveRemoteIncludes === true) {
$document = $this->getXmlFileDOMDocument($curl, $cacheType, $curlResponse->getResponseBody(), $wsdlPath);
$this->saveXmlDOMDocument($document, $cacheFilePath);
} else {
file_put_contents($cacheFilePath, $curlResponse->getResponseBody());
}
} else {
throw new Exception('Could not write WSDL cache file: Download failed with message: '.$curlResponse->getCurlErrorMessage());
}
} else {
if (file_exists($wsdlPath)) {
$document = $this->getXmlFileDOMDocument($curl, $cacheType, file_get_contents($wsdlPath));
$this->saveXmlDOMDocument($document, $cacheFilePath);
} else {
throw new Exception('Could write WSDL cache file: local file does not exist: '.$wsdlPath);
}
}
}
private function getLocalWsdlPath($wsdlPath)
{
if (file_exists($wsdlPath)) {
return realpath($wsdlPath);
} else {
throw new Exception('Could not download WSDL: local file does not exist: '.$wsdlPath);
}
} }
/** /**
* @param string $wsdlPath File URL/path * Download given WSDL file and return name of cache file.
* @return boolean *
* @param string $wsdl WSDL file URL/path
*
* @return string
*/ */
private function isRemoteFile($wsdlPath) public function download($wsdl)
{ {
$parsedUrlOrFalse = @parse_url($wsdlPath); // download and cache remote WSDL files or local ones where we want to
if ($parsedUrlOrFalse !== false) { // resolve remote XSD includes
if (isset($parsedUrlOrFalse['scheme']) && substr($parsedUrlOrFalse['scheme'], 0, 4) === 'http') { $isRemoteFile = $this->isRemoteFile($wsdl);
if ($isRemoteFile || $this->resolveRemoteIncludes) {
$cacheFilePath = $this->cacheDir.DIRECTORY_SEPARATOR.'wsdl_'.md5($wsdl).'.cache';
return true; if (!$this->cacheEnabled || !file_exists($cacheFilePath) || (filemtime($cacheFilePath) + $this->cacheTtl) < time()) {
if ($isRemoteFile) {
// execute request
$responseSuccessfull = $this->curl->exec($wsdl);
// get content
if ($responseSuccessfull) {
$response = $this->curl->getResponseBody();
libxml_use_internal_errors(true);
$doc = simplexml_load_string($response);
if (!$doc) {
$errors = libxml_get_errors();
if (count($errors)) {
throw new \Exception('There is something wrong with the WSDL file formatting. The file can\'t be downloaded to be cached.');
}
libxml_clear_errors();
}
if ($this->resolveRemoteIncludes) {
$this->resolveRemoteIncludes($response, $cacheFilePath, $wsdl);
} else { } else {
file_put_contents($cacheFilePath, $response);
}
} else {
throw new \ErrorException("SOAP-ERROR: Parsing WSDL: Couldn't load from '".$wsdl."'");
}
} elseif (file_exists($wsdl)) {
$response = file_get_contents($wsdl);
$this->resolveRemoteIncludes($response, $cacheFilePath);
} else {
throw new \ErrorException("SOAP-ERROR: Parsing WSDL: Couldn't load from '".$wsdl."'");
}
}
return $cacheFilePath;
} elseif (file_exists($wsdl)) {
return realpath($wsdl);
}
throw new \ErrorException("SOAP-ERROR: Parsing WSDL: Couldn't load from '".$wsdl."'");
}
/**
* Do we have a remote file?
*
* @param string $file File URL/path
*
* @return bool
*/
private function isRemoteFile($file)
{
// @parse_url to suppress E_WARNING for invalid urls
if (false !== $url = @parse_url($file)) {
if (isset($url['scheme']) && 'http' === substr($url['scheme'], 0, 4)) {
return true;
}
}
return false; return false;
} }
}
throw new Exception('Could not determine wsdlPath is remote: '.$wsdlPath);
}
/** /**
* Resolves remote WSDL/XSD includes within the WSDL files. * Resolves remote WSDL/XSD includes within the WSDL files.
* *
* @param Curl $curl * @param string $xml XML file
* @param int $cacheType * @param string $cacheFilePath Cache file name
* @param string $xmlFileSource XML file contents * @param bool $parentFilePath Parent file name
* @param boolean $parentFilePath Parent file name
* @return DOMDocument
*/ */
private function getXmlFileDOMDocument(Curl $curl, $cacheType, $xmlFileSource, $parentFilePath = null) private function resolveRemoteIncludes($xml, $cacheFilePath, $parentFilePath = null)
{ {
$document = new DOMDocument('1.0', 'utf-8'); $doc = new \DOMDocument();
if ($document->loadXML($xmlFileSource) === false) { $doc->loadXML($xml);
throw new Exception('Could not save downloaded WSDL cache: '.$xmlFileSource);
}
$xpath = new DOMXPath($document); $xpath = new \DOMXPath($doc);
$this->updateXmlDocument($curl, $cacheType, $xpath, Helper::PFX_WSDL, Helper::NS_WSDL, 'location', $parentFilePath); $xpath->registerNamespace(Helper::PFX_XML_SCHEMA, Helper::NS_XML_SCHEMA);
$this->updateXmlDocument($curl, $cacheType, $xpath, Helper::PFX_XML_SCHEMA, Helper::NS_XML_SCHEMA, 'schemaLocation', $parentFilePath); $xpath->registerNamespace(Helper::PFX_WSDL, Helper::NS_WSDL);
return $document; // WSDL include/import
} $query = './/'.Helper::PFX_WSDL.':include | .//'.Helper::PFX_WSDL.':import';
$nodes = $xpath->query($query);
private function saveXmlDOMDocument(DOMDocument $document, $cacheFilePath)
{
try {
$xmlContents = $document->saveXML();
if ($xmlContents === '') {
throw new Exception('Could not write WSDL cache file: DOMDocument returned empty XML file');
}
file_put_contents($cacheFilePath, $xmlContents);
} catch (Exception $e) {
unlink($cacheFilePath);
throw new Exception('Could not write WSDL cache file: save method returned error: ' . $e->getMessage());
}
}
private function updateXmlDocument(
Curl $curl,
$cacheType,
DOMXPath $xpath,
$schemaPrefix,
$schemaUrl,
$locationAttributeName,
$parentFilePath = null
) {
$xpath->registerNamespace($schemaPrefix, $schemaUrl);
$nodes = $xpath->query('.//'.$schemaPrefix.':include | .//'.$schemaPrefix.':import');
if ($nodes->length > 0) { if ($nodes->length > 0) {
foreach ($nodes as $node) { foreach ($nodes as $node) {
/** @var DOMElement $node */ $location = $node->getAttribute('location');
$locationPath = $node->getAttribute($locationAttributeName); if ($this->isRemoteFile($location)) {
if ($this->isRemoteFile($locationPath)) { $location = $this->download($location);
$node->setAttribute( $node->setAttribute('location', $location);
$locationAttributeName, } elseif (null !== $parentFilePath) {
$this->getWsdlPath( $location = $this->resolveRelativePathInUrl($parentFilePath, $location);
$curl, $location = $this->download($location);
$locationPath, $node->setAttribute('location', $location);
$cacheType,
true
)
);
} else if ($parentFilePath !== null) {
$node->setAttribute(
$locationAttributeName,
$this->getWsdlPath(
$curl,
$this->resolveRelativePathInUrl($parentFilePath, $locationPath),
$cacheType,
true
)
);
} }
} }
} }
// XML schema include/import
$query = './/'.Helper::PFX_XML_SCHEMA.':include | .//'.Helper::PFX_XML_SCHEMA.':import';
$nodes = $xpath->query($query);
if ($nodes->length > 0) {
foreach ($nodes as $node) {
if ($node->hasAttribute('schemaLocation')) {
$schemaLocation = $node->getAttribute('schemaLocation');
if ($this->isRemoteFile($schemaLocation)) {
$schemaLocation = $this->download($schemaLocation);
$node->setAttribute('schemaLocation', $schemaLocation);
} elseif (null !== $parentFilePath) {
$schemaLocation = $this->resolveRelativePathInUrl($parentFilePath, $schemaLocation);
$schemaLocation = $this->download($schemaLocation);
$node->setAttribute('schemaLocation', $schemaLocation);
}
}
}
}
$doc->save($cacheFilePath);
} }
/** /**
@ -218,10 +226,10 @@ class WsdlDownloader
$urlParts = parse_url($base); $urlParts = parse_url($base);
// combine base path with relative path // combine base path with relative path
if (isset($urlParts['path']) && '/' === $relative{0}) { if (isset($urlParts['path']) && '/' === $relative[0]) {
// $relative is absolute path from domain (starts with /) // $relative is absolute path from domain (starts with /)
$path = $relative; $path = $relative;
} elseif (isset($urlParts['path']) && strrpos($urlParts['path'], '/') === (strlen($urlParts['path']) )) { } elseif (isset($urlParts['path']) && strrpos($urlParts['path'], '/') === (strlen($urlParts['path']))) {
// base path is directory // base path is directory
$path = $urlParts['path'].$relative; $path = $urlParts['path'].$relative;
} elseif (isset($urlParts['path'])) { } elseif (isset($urlParts['path'])) {
@ -241,8 +249,9 @@ class WsdlDownloader
// resolve /../ // resolve /../
foreach ($parts as $key => $part) { foreach ($parts as $key => $part) {
if ($part === '..') { if ('..' === $part) {
$keyToDelete = $key - 1; $keyToDelete = $key - 1;
while ($keyToDelete > 0) { while ($keyToDelete > 0) {
if (isset($parts[$keyToDelete])) { if (isset($parts[$keyToDelete])) {
unset($parts[$keyToDelete]); unset($parts[$keyToDelete]);
@ -250,7 +259,7 @@ class WsdlDownloader
break; break;
} }
$keyToDelete--; --$keyToDelete;
} }
unset($parts[$key]); unset($parts[$key]);

View File

@ -1,5 +1,15 @@
<?php <?php
/*
* This file is part of the BeSimpleSoapClient.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace BeSimple\SoapClient; namespace BeSimple\SoapClient;
use BeSimple\SoapCommon\FilterHelper; use BeSimple\SoapCommon\FilterHelper;
@ -14,7 +24,21 @@ use BeSimple\SoapCommon\SoapRequestFilter;
*/ */
class XmlMimeFilter implements SoapRequestFilter class XmlMimeFilter implements SoapRequestFilter
{ {
public function filterRequest(SoapRequest $request, $attachmentType) /**
* Reset all properties to default values.
*/
public function resetFilter()
{
}
/**
* Modify the given request XML.
*
* @param \BeSimple\SoapCommon\SoapRequest $request SOAP request
*
* @return void
*/
public function filterRequest(SoapRequest $request)
{ {
// get \DOMDocument from SOAP request // get \DOMDocument from SOAP request
$dom = $request->getContentDocument(); $dom = $request->getContentDocument();
@ -41,7 +65,5 @@ class XmlMimeFilter implements SoapRequestFilter
} }
} }
} }
return $request;
} }
} }

View File

@ -23,12 +23,12 @@
"php": ">=5.3.0", "php": ">=5.3.0",
"ext-soap": "*", "ext-soap": "*",
"ext-curl": "*", "ext-curl": "*",
"besimple/soap-common": "0.3.*", "besimple/soap-common": "0.2.*",
"ass/xmlsecurity": "~1.0" "ass/xmlsecurity": "~1.0"
}, },
"require-dev": { "require-dev": {
"mikey179/vfsStream": "~1.0", "mikey179/vfsStream": "~1.0",
"symfony/filesystem": "~2.3", "symfony/filesystem": "~2.0",
"symfony/process": "~2.3" "symfony/process": "~2.3"
}, },
"autoload": { "autoload": {
@ -37,7 +37,7 @@
"target-dir": "BeSimple/SoapClient", "target-dir": "BeSimple/SoapClient",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "0.3-dev" "dev-master": "0.2-dev"
} }
} }
} }

View File

@ -0,0 +1,246 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace BeSimple\SoapCommon;
use BeSimple\SoapCommon\Converter\TypeConverterCollection;
use BeSimple\SoapCommon\Converter\TypeConverterInterface;
/**
* @author Christian Kerl <christian-kerl@web.de>
* @author Francis Besset <francis.besset@gmail.com>
*/
abstract class AbstractSoapBuilder
{
protected $wsdl;
protected $soapOptions = array();
/**
* @return AbstractSoapBuilder
*/
public static function createWithDefaults()
{
$builder = new static();
return $builder
->withSoapVersion12()
->withEncoding('UTF-8')
->withSingleElementArrays()
;
}
public function __construct()
{
$this->soapOptions['features'] = 0;
$this->soapOptions['classmap'] = new Classmap();
$this->soapOptions['typemap'] = new TypeConverterCollection();
}
public function getWsdl()
{
return $this->wsdl;
}
public function getSoapOptions()
{
$options = $this->soapOptions;
$options['classmap'] = $this->soapOptions['classmap']->all();
$options['typemap'] = $this->soapOptions['typemap']->getTypemap();
return $options;
}
/**
* @return AbstractSoapBuilder
*/
public function withWsdl($wsdl)
{
$this->wsdl = $wsdl;
return $this;
}
/**
* @return AbstractSoapBuilder
*/
public function withSoapVersion11()
{
$this->soapOptions['soap_version'] = \SOAP_1_1;
return $this;
}
/**
* @return AbstractSoapBuilder
*/
public function withSoapVersion12()
{
$this->soapOptions['soap_version'] = \SOAP_1_2;
return $this;
}
public function withEncoding($encoding)
{
$this->soapOptions['encoding'] = $encoding;
return $this;
}
public function withWsdlCache($cache)
{
if (!in_array($cache, Cache::getTypes(), true)) {
throw new \InvalidArgumentException();
}
$this->soapOptions['cache_wsdl'] = $cache;
return $this;
}
/**
* @return AbstractSoapBuilder
*/
public function withWsdlCacheNone()
{
$this->soapOptions['cache_wsdl'] = Cache::TYPE_NONE;
return $this;
}
/**
* @return AbstractSoapBuilder
*/
public function withWsdlCacheDisk()
{
$this->soapOptions['cache_wsdl'] = Cache::TYPE_DISK;
return $this;
}
/**
* @return AbstractSoapBuilder
*/
public function withWsdlCacheMemory()
{
$this->soapOptions['cache_wsdl'] = Cache::TYPE_MEMORY;
return $this;
}
/**
* @return AbstractSoapBuilder
*/
public function withWsdlCacheDiskAndMemory()
{
$this->soapOptions['cache_wsdl'] = Cache::TYPE_DISK_MEMORY;
return $this;
}
/**
* Enables the SOAP_SINGLE_ELEMENT_ARRAYS feature.
* If enabled arrays containing only one element will be passed as arrays otherwise the single element is extracted and directly passed.
*
* @return AbstractSoapBuilder
*/
public function withSingleElementArrays()
{
$this->soapOptions['features'] |= \SOAP_SINGLE_ELEMENT_ARRAYS;
return $this;
}
/**
* Enables the SOAP_WAIT_ONE_WAY_CALLS feature.
*
* @return AbstractSoapBuilder
*/
public function withWaitOneWayCalls()
{
$this->soapOptions['features'] |= \SOAP_WAIT_ONE_WAY_CALLS;
return $this;
}
/**
* Enables the SOAP_USE_XSI_ARRAY_TYPE feature.
*
* @return AbstractSoapBuilder
*/
public function withUseXsiArrayType()
{
$this->soapOptions['features'] |= \SOAP_USE_XSI_ARRAY_TYPE;
return $this;
}
public function withTypeConverter(TypeConverterInterface $converter)
{
$this->soapOptions['typemap']->add($converter);
return $this;
}
public function withTypeConverters(TypeConverterCollection $converters, $merge = true)
{
if ($merge) {
$this->soapOptions['typemap']->addCollection($converters);
} else {
$this->soapOptions['typemap']->set($converters->all());
}
return $this;
}
/**
* Adds a class mapping to the classmap.
*
* @param string $xmlType
* @param string $phpType
*
* @return AbstractSoapBuilder
*/
public function withClassMapping($xmlType, $phpType)
{
$this->soapOptions['classmap']->add($xmlType, $phpType);
return $this;
}
/**
* Sets the classmap.
*
* @param array $classmap The classmap.
* @param boolean $merge If true the given classmap is merged into the existing one, otherwise the existing one is overwritten.
*
* @return AbstractSoapBuilder
*/
public function withClassmap(Classmap $classmap, $merge = true)
{
if ($merge) {
$this->soapOptions['classmap']->addClassmap($classmap);
} else {
$this->soapOptions['classmap']->set($classmap->all());
}
return $this;
}
protected function validateWsdl()
{
if (null === $this->wsdl) {
throw new \InvalidArgumentException('The WSDL has to be configured!');
}
}
}

View File

@ -1,15 +0,0 @@
<?php
namespace BeSimple\SoapCommon;
use BeSimple\SoapCommon\Storage\RequestHandlerAttachmentsStorage;
interface AttachmentsHandlerInterface
{
public function addAttachmentStorage(RequestHandlerAttachmentsStorage $requestHandlerAttachmentsStorage);
/**
* @return RequestHandlerAttachmentsStorage
*/
public function getAttachmentStorage();
}

View File

@ -12,8 +12,6 @@
namespace BeSimple\SoapCommon; namespace BeSimple\SoapCommon;
use InvalidArgumentException;
/** /**
* @author Francis Besset <francis.besset@gmail.com> * @author Francis Besset <francis.besset@gmail.com>
*/ */
@ -27,26 +25,21 @@ class Cache
const TYPE_MEMORY = WSDL_CACHE_MEMORY; const TYPE_MEMORY = WSDL_CACHE_MEMORY;
const TYPE_DISK_MEMORY = WSDL_CACHE_BOTH; const TYPE_DISK_MEMORY = WSDL_CACHE_BOTH;
static protected $types = [ protected static $types = array(
self::TYPE_NONE, self::TYPE_NONE,
self::TYPE_DISK, self::TYPE_DISK,
self::TYPE_MEMORY, self::TYPE_MEMORY,
self::TYPE_DISK_MEMORY, self::TYPE_DISK_MEMORY,
]; );
public static function getTypes() public static function getTypes()
{ {
return self::$types; return self::$types;
} }
public static function hasType($cacheType)
{
return in_array($cacheType, self::$types);
}
public static function isEnabled() public static function isEnabled()
{ {
return self::iniGet('soap.wsdl_cache_enabled') === '1'; return self::iniGet('soap.wsdl_cache_enabled');
} }
public static function setEnabled($enabled) public static function setEnabled($enabled)
@ -66,9 +59,7 @@ class Cache
public static function setType($type) public static function setType($type)
{ {
if (!in_array($type, self::getTypes(), true)) { if (!in_array($type, self::getTypes(), true)) {
throw new InvalidArgumentException( throw new \InvalidArgumentException('The cache type has to be either Cache::TYPE_NONE, Cache::TYPE_DISK, Cache::TYPE_MEMORY or Cache::TYPE_DISK_MEMORY');
'The cache type has to be either Cache::TYPE_NONE, Cache::TYPE_DISK, Cache::TYPE_MEMORY or Cache::TYPE_DISK_MEMORY'
);
} }
self::iniSet('soap.wsdl_cache', $type); self::iniSet('soap.wsdl_cache', $type);
@ -81,6 +72,10 @@ class Cache
public static function setDirectory($directory) public static function setDirectory($directory)
{ {
if (!is_dir($directory)) {
mkdir($directory, 0777, true);
}
self::iniSet('soap.wsdl_cache_dir', $directory); self::iniSet('soap.wsdl_cache_dir', $directory);
} }

View File

@ -15,30 +15,27 @@ namespace BeSimple\SoapCommon;
/** /**
* @author Francis Besset <francis.besset@gmail.com> * @author Francis Besset <francis.besset@gmail.com>
*/ */
class ClassMap class Classmap
{ {
protected $classMap; /**
protected $inverseClassMap; * @var array
*/
protected $classmap = array();
public function __construct(array $classMap = [])
{
$this->classmap = [];
foreach ($classMap as $type => $className) {
$this->add($type, $className);
}
}
/** /**
* @return array * @return array
*/ */
public function getAll() public function all()
{ {
return $this->classMap; return $this->classmap;
} }
/** /**
* @param string $type * @param string $type
*
* @return string * @return string
*
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
*/ */
public function get($type) public function get($type)
@ -47,26 +44,39 @@ class ClassMap
throw new \InvalidArgumentException(sprintf('The type "%s" does not exists', $type)); throw new \InvalidArgumentException(sprintf('The type "%s" does not exists', $type));
} }
return $this->classMap[$type]; return $this->classmap[$type];
} }
/** /**
* @param string $type * @param string $type
* @param string $className * @param string $classname
*
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
*/ */
public function add($type, $className) public function add($type, $classname)
{ {
if ($this->has($type)) { if ($this->has($type)) {
throw new \InvalidArgumentException(sprintf('The type "%s" already exists', $type)); throw new \InvalidArgumentException(sprintf('The type "%s" already exists', $type));
} }
$this->classMap[$type] = $className; $this->classmap[$type] = $classname;
$this->inverseClassMap[$className] = $type; }
/**
* @param array $classmap
*/
public function set(array $classmap)
{
$this->classmap = array();
foreach ($classmap as $type => $classname) {
$this->add($type, $classname);
}
} }
/** /**
* @param string $type * @param string $type
*
* @return boolean * @return boolean
*/ */
public function has($type) public function has($type)
@ -74,24 +84,10 @@ class ClassMap
return isset($this->classmap[$type]); return isset($this->classmap[$type]);
} }
public function getByClassName($className) public function addClassmap(Classmap $classmap)
{ {
if (!$this->hasByClassName($className)) { foreach ($classmap->all() as $type => $classname) {
throw new \InvalidArgumentException(sprintf('The className "%s" was not found in %s', $className, __CLASS__)); $this->add($type, $classname);
}
return $this->inverseClassMap[$className];
}
public function hasByClassName($className)
{
return isset($this->inverseClassMap[$className]);
}
public function addClassMap(ClassMap $classMap)
{
foreach ($classMap->getAll() as $type => $className) {
$this->add($type, $className);
} }
} }
} }

View File

@ -44,4 +44,3 @@ class DateTimeTypeConverter implements TypeConverterInterface
return sprintf('<%1$s>%2$s</%1$s>', $this->getTypeName(), $data->format('Y-m-d\TH:i:sP')); return sprintf('<%1$s>%2$s</%1$s>', $this->getTypeName(), $data->format('Y-m-d\TH:i:sP'));
} }
} }

View File

@ -44,4 +44,3 @@ class DateTypeConverter implements TypeConverterInterface
return sprintf('<%1$s>%2$s</%1$s>', $this->getTypeName(), $data->format('Y-m-d')); return sprintf('<%1$s>%2$s</%1$s>', $this->getTypeName(), $data->format('Y-m-d'));
} }
} }

View File

@ -14,14 +14,22 @@ namespace BeSimple\SoapCommon\Converter;
use BeSimple\SoapCommon\Helper; use BeSimple\SoapCommon\Helper;
use BeSimple\SoapCommon\Mime\Part as MimePart; use BeSimple\SoapCommon\Mime\Part as MimePart;
use BeSimple\SoapCommon\SoapKernel;
use BeSimple\SoapCommon\Converter\SoapKernelAwareInterface;
use BeSimple\SoapCommon\Converter\TypeConverterInterface;
/** /**
* MTOM type converter. * MTOM type converter.
* *
* @author Andreas Schamberger <mail@andreass.net> * @author Andreas Schamberger <mail@andreass.net>
*/ */
class MtomTypeConverter implements TypeConverterInterface class MtomTypeConverter implements TypeConverterInterface, SoapKernelAwareInterface
{ {
/**
* @var \BeSimple\SoapCommon\SoapKernel $soapKernel SoapKernel instance
*/
protected $soapKernel = null;
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@ -46,6 +54,23 @@ class MtomTypeConverter implements TypeConverterInterface
$doc = new \DOMDocument(); $doc = new \DOMDocument();
$doc->loadXML($data); $doc->loadXML($data);
$includes = $doc->getElementsByTagNameNS(Helper::NS_XOP, 'Include');
$include = $includes->item(0);
// convert href -> myhref for external references as PHP throws exception in this case
// http://svn.php.net/viewvc/php/php-src/branches/PHP_5_4/ext/soap/php_encoding.c?view=markup#l3436
$ref = $include->getAttribute('myhref');
if ('cid:' === substr($ref, 0, 4)) {
$contentId = urldecode(substr($ref, 4));
if (null !== ($part = $this->soapKernel->getAttachment($contentId))) {
return $part->getContent();
} else {
return null;
}
}
return $data; return $data;
} }
@ -57,6 +82,8 @@ class MtomTypeConverter implements TypeConverterInterface
$part = new MimePart($data); $part = new MimePart($data);
$contentId = trim($part->getHeader('Content-ID'), '<>'); $contentId = trim($part->getHeader('Content-ID'), '<>');
$this->soapKernel->addAttachment($part);
$doc = new \DOMDocument(); $doc = new \DOMDocument();
$node = $doc->createElement($this->getTypeName()); $node = $doc->createElement($this->getTypeName());
$doc->appendChild($node); $doc->appendChild($node);
@ -68,4 +95,12 @@ class MtomTypeConverter implements TypeConverterInterface
return $doc->saveXML(); return $doc->saveXML();
} }
/**
* {@inheritDoc}
*/
public function setKernel(SoapKernel $soapKernel)
{
$this->soapKernel = $soapKernel;
}
} }

View File

@ -0,0 +1,32 @@
<?php
/*
* This file is part of the BeSimpleSoapCommon.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace BeSimple\SoapCommon\Converter;
use BeSimple\SoapCommon\SoapKernel;
/**
* Internal type converter interface.
*
* @author Andreas Schamberger <mail@andreass.net>
*/
interface SoapKernelAwareInterface
{
/**
* Set SoapKernel instance.
*
* @param \BeSimple\SoapCommon\SoapKernel $soapKernel SoapKernel instance
*
* @return void
*/
public function setKernel(SoapKernel $soapKernel);
}

View File

@ -1,16 +1,34 @@
<?php <?php
/*
* This file is part of the BeSimpleSoapClient.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace BeSimple\SoapCommon\Converter; namespace BeSimple\SoapCommon\Converter;
use BeSimple\SoapCommon\Mime\Part as MimePart; use BeSimple\SoapCommon\Mime\Part as MimePart;
use BeSimple\SoapCommon\SoapKernel;
use BeSimple\SoapCommon\Converter\SoapKernelAwareInterface;
use BeSimple\SoapCommon\Converter\TypeConverterInterface;
/** /**
* SwA type converter. * SwA type converter.
* *
* @author Andreas Schamberger <mail@andreass.net> * @author Andreas Schamberger <mail@andreass.net>
*/ */
class SwaTypeConverter implements TypeConverterInterface class SwaTypeConverter implements TypeConverterInterface, SoapKernelAwareInterface
{ {
/**
* @var \BeSimple\SoapCommon\SoapKernel $soapKernel SoapKernel instance
*/
protected $soapKernel = null;
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@ -35,6 +53,20 @@ class SwaTypeConverter implements TypeConverterInterface
$doc = new \DOMDocument(); $doc = new \DOMDocument();
$doc->loadXML($data); $doc->loadXML($data);
// convert href -> myhref for external references as PHP throws exception in this case
// http://svn.php.net/viewvc/php/php-src/branches/PHP_5_4/ext/soap/php_encoding.c?view=markup#l3436
$ref = $doc->documentElement->getAttribute('myhref');
if ('cid:' === substr($ref, 0, 4)) {
$contentId = urldecode(substr($ref, 4));
if (null !== ($part = $this->soapKernel->getAttachment($contentId))) {
return $part->getContent();
} else {
return null;
}
}
return $data; return $data;
} }
@ -46,6 +78,16 @@ class SwaTypeConverter implements TypeConverterInterface
$part = new MimePart($data); $part = new MimePart($data);
$contentId = trim($part->getHeader('Content-ID'), '<>'); $contentId = trim($part->getHeader('Content-ID'), '<>');
$this->soapKernel->addAttachment($part);
return sprintf('<%s href="%s"/>', $this->getTypeName(), 'cid:' . $contentId); return sprintf('<%s href="%s"/>', $this->getTypeName(), 'cid:' . $contentId);
} }
/**
* {@inheritDoc}
*/
public function setKernel(SoapKernel $soapKernel)
{
$this->soapKernel = $soapKernel;
}
} }

View File

@ -19,7 +19,7 @@ class TypeConverterCollection
{ {
private $converters = array(); private $converters = array();
public function getAll() public function all()
{ {
return array_values($this->converters); return array_values($this->converters);
} }
@ -58,7 +58,7 @@ class TypeConverterCollection
public function addCollection(TypeConverterCollection $converterCollection) public function addCollection(TypeConverterCollection $converterCollection)
{ {
foreach ($converterCollection->getAll() as $converter) { foreach ($converterCollection->all() as $converter) {
$this->add($converter); $this->add($converter);
} }
} }
@ -74,10 +74,10 @@ class TypeConverterCollection
$typemap[] = array( $typemap[] = array(
'type_name' => $converter->getTypeName(), 'type_name' => $converter->getTypeName(),
'type_ns' => $converter->getTypeNamespace(), 'type_ns' => $converter->getTypeNamespace(),
'from_xml' => function($input) use ($converter) { 'from_xml' => function ($input) use ($converter) {
return $converter->convertXmlToPhp($input); return $converter->convertXmlToPhp($input);
}, },
'to_xml' => function($input) use ($converter) { 'to_xml' => function ($input) use ($converter) {
return $converter->convertPhpToXml($input); return $converter->convertPhpToXml($input);
}, },
); );

View File

@ -24,14 +24,14 @@ interface TypeConverterInterface
* *
* @return string * @return string
*/ */
function getTypeNamespace(); public function getTypeNamespace();
/** /**
* Get type name. * Get type name.
* *
* @return string * @return string
*/ */
function getTypeName(); public function getTypeName();
/** /**
* Convert given XML string to PHP type. * Convert given XML string to PHP type.
@ -40,7 +40,7 @@ interface TypeConverterInterface
* *
* @return mixed * @return mixed
*/ */
function convertXmlToPhp($data); public function convertXmlToPhp($data);
/** /**
* Convert PHP type to XML string. * Convert PHP type to XML string.
@ -49,5 +49,5 @@ interface TypeConverterInterface
* *
* @return string * @return string
*/ */
function convertPhpToXml($data); public function convertPhpToXml($data);
} }

View File

@ -25,7 +25,7 @@ class Message
public function __construct($name) public function __construct($name)
{ {
$this->name = $name; $this->name = $name;
$this->parts = array(); $this->parts = [];
} }
public function getName() public function getName()
@ -48,13 +48,13 @@ class Message
return 0 === count($this->parts) ? true : false; return 0 === count($this->parts) ? true : false;
} }
public function add($name, $phpType, $nillable = false) public function add($name, $phpType, $nillable = false, $minOccurs = 1)
{ {
if ($phpType instanceof TypeInterface) { if ($phpType instanceof TypeInterface) {
$phpType = $phpType->getPhpType(); $phpType = $phpType->getPhpType();
} }
$this->parts[$name] = new Part($name, $phpType, $nillable); $this->parts[$name] = new Part($name, $phpType, $nillable, $minOccurs);
return $this; return $this;
} }

View File

@ -12,8 +12,6 @@
namespace BeSimple\SoapCommon\Definition; namespace BeSimple\SoapCommon\Definition;
use BeSimple\SoapCommon\Definition\Type\TypeRepository;
/** /**
* @author Francis Besset <francis.besset@gmail.com> * @author Francis Besset <francis.besset@gmail.com>
*/ */
@ -66,7 +64,7 @@ class Method
$this->input->add($name, $type); $this->input->add($name, $type);
} }
public function setOutput($type) public function setOutput($type, $name = 'return')
{ {
$this->output->add('return', $type); $this->output->add('return', $type);
} }

Some files were not shown because too many files have changed in this diff Show More