160 Commits

Author SHA1 Message Date
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
311f9e6d08 Readme update: better examples added 2017-03-15 11:23:21 +01:00
e67d5aa84b Readme updated 2017-03-15 10:48:23 +01:00
d3023b1a5a UnitTests are now located in tests directory & tiny improvements 2017-03-15 10:25:48 +01:00
21d705bbfa SoapClient custom endpoint location & connection keep alive configuration added & tests updated 2017-03-03 11:11:44 +01:00
0e2c33faf8 Support of older PHP versions removed: MimeFilter does not sanitize PHP 5.4.x error 2017-02-22 12:23:24 +01:00
cf6e147c26 Merge remote-tracking branch 'remotes/origin/develop' 2017-02-18 00:14:21 +01:00
f276a30a47 Curl/WsdlGenerator - better error handling 2017-02-18 00:13:02 +01:00
4edc46e67f Parser fix - MimeMessages with CRLF caused iconv_mime_decode throwing Exceptions 2017-02-17 15:06:06 +01:00
a76526a5b6 DEFAULT_CONNECTION_TIMEOUT default value increased to 120 2017-02-17 11:20:09 +01:00
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
5c0bf914e3 Unused SoapClientNativeDataTransferObject removed 2017-02-17 03:36:16 +01:00
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
e1b50ce914 SoapClient::__soapCall() must be compatible with \SoapClient::__soapCall() fix 2017-02-17 00:26:01 +01:00
68b41acc46 SoapClient - WSDL download fixes 2017-02-17 00:14:05 +01:00
30a9707c59 Merge remote-tracking branch 'remotes/origin/develop' 2017-02-14 16:48:58 +01:00
aee034791e SoapClient large refactoring & tests update 2017-02-14 16:01:39 +01:00
00ddf149b0 Passing SOAP fault with detail 2016-11-29 18:55:55 +01:00
476813e9bb MIME parts now contain only LF (was CRLF) 2016-11-29 18:55:55 +01:00
f57239ad0d MultiPart Boundary generator changed 2016-11-24 15:18:00 +01:00
10caf27da3 MultiPart ContentId is now in different format 2016-11-24 15:00:46 +01:00
51d1abab48 Connection: Keep-alive is now configurable - BUT NOW WORKING
PHP is unable to change Connection type, this configuration is quite missleading for SoapServer, but still working for SoapClient
2016-11-24 12:47:01 +01:00
1224f5f40f Content-Location added for attachment parts 2016-11-24 12:45:17 +01:00
f4a4619fe6 Handling SoapRequests/SoapResponse with attachments fix 2016-11-24 11:04:57 +01:00
052ab20d67 tiny bugfixes 2016-11-11 16:04:44 +01:00
dd7b6904b6 SoapOptions moved 2016-11-09 17:05:43 +01:00
c4d993585f SoapServer now handles get WSDL requests 2016-11-09 13:43:18 +01:00
bd1fbf9cfc SoapServer::handle() has to be compatible with \SoapServer 2016-11-09 12:08:32 +01:00
5fbcfb3e22 AttachmentsHandlerInterface refactored 2016-11-08 18:31:28 +01:00
84c37b1d24 Soap server with attachments refactoring 2016-11-08 15:42:52 +01:00
8d033f9afc SoapResponse is a product of SoapResponseFactory, small refactorings 2016-11-02 16:08:21 +01:00
bf494a42b5 MimeFilters are now stateless 2016-11-02 09:55:12 +01:00
969709cae5 Large refactoring of SoapKernel 2016-11-01 18:13:23 +01:00
155aa029ce SoapRequest is now SoapRequestFactory product 2016-11-01 16:23:21 +01:00
3c0f731086 SoapOptions cache dir introduced + SoapOptionsBuilder - new methods added 2016-11-01 09:24:41 +01:00
374c64538a remove useless SoapClientBuilder 2016-10-31 14:12:35 +01:00
4d7894b66e Composer info updated 2016-10-27 16:38:53 +02:00
0a157748a8 Large refactoring removing states, abstract magic, vague fluent interfaces 2016-10-27 16:24:44 +02:00
c4a9b58b08 Use request_stack service instead of deprecated request service 2016-01-11 16:28:20 +11:00
fc15bf36ab Call getPath() instead of string casting 2016-01-11 16:28:05 +11:00
8462233a08 Update FlattenException use statements 2016-01-11 16:20:13 +11:00
03227295f6 Use ContainerAwareTrait and ContainerAwareInterface 2016-01-11 16:09:42 +11:00
f285adfa14 Use path attribute rather than pattern 2016-01-11 16:06:22 +11:00
2ecdbe9714 Change package name and description 2016-01-08 11:47:15 +11:00
e5c54164c1 Support Symfony 3.* 2016-01-08 11:42:56 +11:00
27ebf0fbce Merge remote-tracking branch 'origin/0.2' 2015-06-01 16:04:32 +02:00
855e382590 [SoapBundle] Fixed service definition with factory 2015-06-01 16:04:29 +02:00
2974a4f838 Stop support of Symfony <2.6 2015-06-01 16:04:24 +02:00
fb56d51bd8 fixup! [SoapBundle] Set _format route to xml 2015-03-27 16:07:42 +01:00
f2a8a7ebb3 Merge branch '0.2' 2014-08-18 14:20:19 +02:00
7a9119cef1 [SoapBundle] Added configuration to configure client proxy 2014-08-18 13:54:19 +02:00
1a7f60b679 [SoapClient] Added proxy authentication option in SoapClientBuilder
Fixed #47
2014-08-18 11:45:53 +02:00
70db0c42fd [SoapClient] Renamed proxy_user to proxy_login option to keep compatibility with SoapClient of PHP 2014-08-18 10:58:40 +02:00
960c9f557a [SoapClient] Fixed typo for proxy options
Fixed #46
2014-08-18 10:31:20 +02:00
33d641de4e [SoapClient] Fixed tests if proxy exists in environment variables 2014-08-18 10:29:49 +02:00
bbd4c26134 Merge branch '0.2' 2014-08-16 15:48:45 +02:00
29170576c2 [Doc] Added documentation for SoapClient 2014-08-15 21:18:24 +02:00
50ab5a93ad [SoapBundle] Update the cache dir 2014-08-15 19:46:23 +02:00
1290573285 [SoapBundle] Add a hack to load BeSimpleSoap cache with a client 2014-08-15 19:45:21 +02:00
f5675f6ece [SoapBundle] Set cache informations even though it is disabled 2014-08-15 19:43:31 +02:00
15b208d861 Replaced cli_webserver_workaround client option by a check of CONTENT_TYPE AND HTTP_CONTENT_TYPE entry in SERVER superglobal 2014-08-14 21:40:13 +02:00
294a9fe90e Stop support of Symfony <2.3 2014-08-14 15:02:52 +02:00
313840d5a4 Revert "[SoapClient] [Tests] Down required version of symfony/filesystem vendor"
This reverts commit 726ee89936.

Conflicts:
	composer.json
	src/BeSimple/SoapClient/composer.json
2014-08-14 14:57:00 +02:00
8e4d8b0300 Updated BeSimpleSoap vendor requierement to 0.3 2014-08-14 14:56:39 +02:00
621b2080e0 Updated version to 0.3 2014-08-14 14:21:49 +02:00
fe67cff5ff Merge branch 'fixed_tests' 2014-08-14 13:39:12 +02:00
e676eb0432 [composer] Used a stable version of vfsStream 2014-08-14 13:33:32 +02:00
fd402731af Fixed travis configuration 2014-08-14 13:20:09 +02:00
f5d6f5e759 Updated travis 2014-08-14 13:06:18 +02:00
726ee89936 [SoapClient] [Tests] Down required version of symfony/filesystem vendor 2014-08-14 13:06:18 +02:00
36a368e695 [composer] Removed dev minimum-stability 2014-08-14 13:06:18 +02:00
e2de214ea5 [SoapClient] [Tests] Removed uploaded file 2014-08-14 13:06:18 +02:00
3cfeea8371 [SoapClient] [Tests] Fixed typo 2014-08-14 13:06:18 +02:00
c24e8775bf [SoapClient] Add possiblity to disable proxy if present in environment variable 2014-08-14 13:05:50 +02:00
b3c6353af8 [composer] Removed dev minimum-stability 2014-08-14 13:05:50 +02:00
10bba6a3bd [Test] Force replace unziped file for axis server 2014-08-13 22:08:17 +02:00
a122f2a0f6 [SoapBundle] Skipped test for SoapRequest 2014-08-13 22:02:46 +02:00
8d13d2dd5c [Doc] Add missing methods 2014-08-13 06:57:03 +02:00
1c1cd377f1 Merge branch 'ch3ric-fix-doc' 2014-08-13 06:55:07 +02:00
1efa348ae5 Merge branch 'fix-doc' of https://github.com/ch3ric/BeSimpleSoap into ch3ric-fix-doc 2014-08-13 06:55:01 +02:00
ccc4d57501 Merge pull request #42 from mremi/handle-request-options
Handled additional request options
2014-07-10 16:16:27 +02:00
740f146bad Handled additional request options 2014-07-01 15:47:46 +02:00
5e8e669299 Fix Doc 2014-05-25 16:48:26 +02:00
e4cb612aed Created a client classmap even when it is empty 2014-04-30 10:54:07 +02:00
59ea6b1ce0 Merge pull request #33 from borissamardzija/master
Update Curl class to support CURLOPT_CAINFO and CURLOPT_CAPATH options
2014-04-25 13:36:04 +02:00
7bb849e394 Update Curl class to support CURLOPT_CAINFO and CURLOPT_CAPATH options 2014-04-25 11:16:34 +02:00
02722eae8f Merge pull request #32 from mremi/filter-request-headers
Added method to tweak HTTP headers of request
2014-04-24 17:22:00 +02:00
b7581f29b0 Removed reference to return an array of HTTP headers 2014-04-24 09:29:58 +02:00
dc6e1e0889 Merge pull request #31 from mremi/http-auth
Added extra option to configure HTTP authentication
2014-04-24 08:38:03 +02:00
f986400dc2 Merge pull request #30 from mremi/method-visibility
Updated visibility from private to protected
2014-04-24 08:36:23 +02:00
67410805ba Added method to tweak HTTP headers of request 2014-04-22 22:29:11 +02:00
2ae7515294 Added extra option to configure HTTP authentication 2014-04-22 22:05:04 +02:00
cdfc3cd5bd Updated visibility from private to protected 2014-04-22 21:53:14 +02:00
9ac755d86e [SoapBundle] Set _format route to xml 2013-12-13 15:25:20 +01:00
321dcf3058 [SoapBundle] Set wsdl request type only if the "wsdl" parameter in present in URL 2013-12-13 11:24:25 +01:00
3a2b8e32ee [SoapBundle] Enhanced SoapFault management 2013-12-13 08:26:18 +01:00
fd5154a469 Fixed typo 2013-12-10 15:25:09 +01:00
188f282a87 [SoapWsdl] Specify an empty message if the input is empty 2013-12-10 15:25:09 +01:00
f9e230400d [SoapBundle] Fixed RpcLiteralRequestMessageBinderTest 2013-12-08 00:27:33 +01:00
1b4e262c60 [SoapBundle] Simplified conditional statement 2013-12-08 00:25:20 +01:00
60e3714602 [SoapBundle][SoapCommon] Removed unused TypeRepository in Definition\Method classes 2013-12-08 00:23:30 +01:00
1e82d7fdd7 Fix WSDL schema stylesheet including 2013-12-07 19:55:33 +01:00
8788d7595d Cleaned unused method, property, variable or parameter 2013-12-02 16:02:29 +01:00
b45224587a Added use TypeConverterInterface 2013-12-02 15:39:59 +01:00
c8baf14c75 Fixed typo 2013-12-02 15:39:39 +01:00
53849c68e0 Removed unused use statement 2013-12-02 15:35:36 +01:00
ecdf7e1872 Fixed an undefined variable
Fixed commit c830097430
Fixed issue #22
2013-11-20 08:45:12 +01:00
dcfca04db4 Merge remote-tracking branch 'origin/exception'
Conflicts:
	composer.json
	src/BeSimple/SoapBundle/composer.json
2013-11-15 10:37:55 +01:00
73efa627ce Removed old Zend dependencies in composer.json 2013-11-13 16:43:47 +01:00
d6752a41e9 [SoapWsdl] Fixed bad usage name of type included in an other ComplexType
Fixed issue #21
2013-11-13 15:46:50 +01:00
6a6661012e [SoapBundle] Enhanced exception management with Symfony2 2013-11-13 15:02:30 +01:00
10705aa9e2 Merge branch '0.1'
Conflicts:
	src/BeSimple/SoapServer/SoapResponse.php
2013-11-06 16:50:31 +01:00
bd2508f854 Merge branch '0.1' 2013-11-06 09:31:58 +01:00
259c23ee4d Merge pull request #20 from hason/patch-1
Fixed typo
2013-11-01 07:42:46 -07:00
98842b24f8 Fixed typo 2013-11-01 13:40:16 +01:00
48d305e7db Merge branch 'wsse' of https://github.com/aschamberger/BeSimpleSoap into aschamberger-wsse
Conflicts:
	.travis.yml
	src/BeSimple/SoapServer/SoapRequest.php
2013-10-30 17:00:44 +01:00
4a97c2537e Merge branch 'patch-1' of https://github.com/rekky/BeSimpleSoap into rekky-patch-1 2013-10-30 16:51:54 +01:00
b8f37d213e Fixed version besimple/soap-* version in README's 2013-10-30 16:49:47 +01:00
6e967fe811 Merge branch 'readmes' of https://github.com/aschamberger/BeSimpleSoap into aschamberger-readmes 2013-10-30 16:47:25 +01:00
00c8726bb2 Updated composer.json 2013-10-30 16:35:17 +01:00
dc4c9d2191 remove travis status in readme 2013-10-30 15:54:35 +01:00
9ddac35f18 Fix doc comment 2013-10-30 12:31:00 +01:00
ed0846da6f Fix byte length counting if strlen overloading is used 2013-10-30 11:18:22 +04:00
9827e58c56 Merge pull request #19 from rolebi/patch-1
Adding besimple/soap-wsdl to dependencies
2013-10-28 03:40:34 -07:00
e7d86b3e99 Adding besimple/soap-wsdl to dependencies
Fix missing `BeSimple\SoapWsdl\Dumper\Dumper` class in `BeSimple\SoapBundle\WebServiceContext`
2013-10-28 11:09:23 +01:00
54894b2fd9 Fixed ComplexType without alias name
Fix issue #17
2013-10-17 13:51:31 +02:00
95efa3e366 Fixed CS 2013-10-17 13:48:02 +02:00
c830097430 Rewrited Definition of WebService and WSDL dumper 2013-10-15 11:46:12 +02:00
391a3f10b8 Merge branch '0.1' 2013-10-15 11:15:10 +02:00
ebd565cd79 Fixed besimple/soap-* version 2013-09-27 21:35:39 +02:00
81ce2d7571 Merge branch '0.1' 2013-09-27 21:33:11 +02:00
461675042a fix soap header handling 2013-08-30 22:07:44 +02:00
f5a8573a4e Add readme files 2013-08-24 17:38:18 +02:00
1f1d513ea3 remove obsolete file 2013-08-24 11:01:59 +02:00
8e305da9c0 change url for check if axis is ready 2013-08-24 10:53:24 +02:00
dc3fcaf81f remove ini and try axis build 2013-08-24 09:47:34 +02:00
d8d6ca5795 fix problem with cache path 2013-08-24 09:39:56 +02:00
cbd49c3342 add php ini for travis and update travis config 2013-08-24 09:21:13 +02:00
e9388023c1 add php ini for travis and update travis config 2013-08-24 09:05:58 +02:00
76360c193e add php ini for travis and update travis config 2013-08-24 09:03:23 +02:00
155956ca04 change file permissions 2013-08-24 08:44:10 +02:00
3f41d4b7bc change file permissions 2013-08-24 08:41:59 +02:00
4fa7fd759a add phpwebserver to travis 2013-08-24 08:24:31 +02:00
2b12264304 Axis and SoapServer interop tests 2013-08-23 23:25:16 +02:00
f8a80c0361 fix wrong method call 2013-08-23 21:45:09 +02:00
19def707d3 use WsSecurityFilterClientServer from common 2013-08-23 20:59:35 +02:00
b21d758e77 remove now obsolete code 2013-08-23 20:57:37 +02:00
9bc9410172 add BinarySecurityToken resolving to key resolver 2013-08-23 20:57:07 +02:00
1cde22d8bb fix securitykey factory method call 2013-08-23 20:56:37 +02:00
8d62141a3d add workaround for cli webserver option 2013-08-23 20:55:26 +02:00
96f8415b92 added encryption to WS Security 2013-08-23 20:48:13 +02:00
5229091033 further steps with WS-Security (signing) 2013-08-23 20:47:55 +02:00
580e6f4da7 added WsSecurityFilter that supports UsernamePassword for now 2013-08-23 20:47:41 +02:00
6a5109c526 fix SoapFault handling to throw proper soap fault to client 2013-08-23 20:47:20 +02:00
5e6fd5de25 extract common code used in client/server 2013-08-23 20:43:48 +02:00
ee321fca42 fix missing 'cid:' in SwaTypeConverter 2013-08-23 20:43:22 +02:00
b5af83f9d2 add workaround for cli webserver, option implemented in client 2013-08-23 20:30:50 +02:00
9f9bab242d Fixed composer.json 2013-08-16 17:36:03 +02:00
f792f53aa2 Added composer.json 2013-08-16 17:18:40 +02:00
4d9b112bb5 Updated version to 0.2 2013-08-16 17:18:31 +02:00
235 changed files with 10433 additions and 6543 deletions

2
.gitignore vendored
View File

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

View File

@ -4,20 +4,22 @@ php:
- 5.3
- 5.4
- 5.5
- 5.6
env:
- SYMFONY_VERSION=2.0.*
- SYMFONY_VERSION=2.1.*
- SYMFONY_VERSION=2.2.*
- SYMFONY_VERSION=2.3.*
- SYMFONY_VERSION=dev-master
- SYMFONY_VERSION=2.6.*
- SYMFONY_VERSION="dev-master symfony/debug:~2.7@dev symfony/http-kernel:~2.7@dev"
before_script:
- composer require symfony/http-foundation:${SYMFONY_VERSION} --no-interaction --prefer-source
- composer self-update
- composer require symfony/framework-bundle:${SYMFONY_VERSION} --no-update
- composer update --no-interaction --prefer-source
- ./src/BeSimple/SoapClient/Tests/bin/phpwebserver.sh
- ./src/BeSimple/SoapClient/Tests/bin/axis.sh
script:
- phpunit --coverage-text
matrix:
allow_failures:
- env: SYMFONY_VERSION=dev-master
- env: SYMFONY_VERSION="dev-master symfony/debug:~2.7@dev symfony/http-kernel:~2.7@dev"

147
README.md Normal file
View File

@ -0,0 +1,147 @@
# BeSimpleSoap
Build SOAP and WSDL based web services.
This fork is a refactored version that fixes a lot of errors and provides
better API, robust, stable and modern codebase.
See [How to use](#how-to-use) that will help you to understand the magic.
# Components
BeSimpleSoap consists of five components ...
## BeSimpleSoapClient
**Refactored** BeSimpleSoapClient is a component that extends the native PHP SoapClient with further features like SwA and WS-Security.
## BeSimpleSoapServer
**Refactored** BeSimpleSoapServer is a component that extends the native PHP SoapServer with further features like SwA and WS-Security.
## BeSimpleSoapCommon
**Refactored** BeSimpleSoapCommon component contains functionality shared by both the server and client implementations.
## BeSimpleSoapWsdl
**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
**Unsupported!**
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).
*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
You can investigate the unit tests dir ``tests`` in order to get a clue.
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
```php
$soapClientBuilder = new SoapClientBuilder();
$soapClient = $soapClientBuilder->build(
SoapClientOptionsBuilder::createWithDefaults(),
SoapOptionsBuilder::createWithDefaults('http://path/to/wsdlfile.wsdl')
);
$myRequest = new MyRequest();
$myRequest->attribute = 'string value';
$soapResponse = $soapClient->soapCall('myMethod', [$myRequest]);
var_dump($soapResponse); // Contains Response, Attachments
```
### Something wrong?!
Turn on the tracking and catch `SoapFaultWithTracingData` exception to get some sweets :)
```php
try {
$soapResponse = $soapClient->soapCall('myMethod', [$myRequest]);
} catch (SoapFaultWithTracingData $fault) {
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.
## Example of soap server handling
Starting a SOAP server is a bit more complex.
I recommend you to inspect SoapServer unit tests for inspiration.
```php
$dummyService = new DummyService();
$classMap = new ClassMap();
foreach ($dummyService->getClassMap() as $type => $className) {
$classMap->add($type, $className);
}
$soapServerBuilder = new SoapServerBuilder();
$soapServerOptions = SoapServerOptionsBuilder::createWithDefaults($dummyService);
$soapOptions = SoapOptionsBuilder::createWithClassMap($dummyService->getWsdlPath(), $classMap);
$soapServer = $soapServerBuilder->build($soapServerOptions, $soapOptions);
$request = $soapServer->createRequest(
$dummyService->getEndpoint(),
'DummyService.dummyServiceMethod',
'text/xml;charset=UTF-8',
'<received><soap><request><here /></request></soap></received>'
);
$response = $soapServer->handleRequest($request);
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:
```
/**
* @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 Normal file
View File

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

View File

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

1349
composer.lock generated Normal file
View File

@ -0,0 +1,1349 @@
{
"_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,26 +9,15 @@
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="vendor/autoload.php"
>
stderr="true"
bootstrap="vendor/autoload.php">
<php>
<const name="WEBSERVER_PORT" value="8000" />
</php>
<testsuites>
<testsuite name="BeSimpleSoap Test Suite">
<directory>./src/BeSimple/*/Tests/</directory>
<testsuite name="BeSimpleSoapTestSuite">
<directory>tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./src/BeSimple/</directory>
<exclude>
<directory>./src/BeSimple/*/Tests</directory>
<directory>./src/BeSimple/*/Resources</directory>
</exclude>
</whitelist>
</filter>
</phpunit>

View File

@ -13,28 +13,44 @@
namespace BeSimple\SoapBundle;
use BeSimple\SoapCommon\Cache as BaseCache;
use BeSimple\SoapCommon\SoapOptions\SoapOptions;
use Exception;
/**
* @author Francis Besset <francis.besset@gmail.com>
*/
class Cache
{
public function __construct($cacheDisabled, $type, $directory, $lifetime = null, $limit = null)
public function __construct(SoapOptions $soapOptions)
{
$isEnabled = (Boolean) $cacheDisabled ? BaseCache::DISABLED : BaseCache::ENABLED;
if ($soapOptions->isWsdlCached()) {
$isEnabled = (bool)$soapOptions->isWsdlCached() ? BaseCache::ENABLED : BaseCache::DISABLED;
BaseCache::setEnabled($isEnabled);
BaseCache::setEnabled($isEnabled);
BaseCache::setType($soapOptions->getWsdlCacheType());
BaseCache::setDirectory($soapOptions->getWsdlCacheDir());
} else {
BaseCache::setEnabled(BaseCache::DISABLED);
BaseCache::setType(SoapOptions::SOAP_CACHE_TYPE_NONE);
BaseCache::setDirectory(null);
}
}
if (BaseCache::ENABLED == BaseCache::isEnabled()) {
BaseCache::setType($type);
BaseCache::setDirectory($directory);
if (null !== $lifetime) {
BaseCache::setLifetime($lifetime);
public function validateSettings(SoapOptions $soapOptions)
{
if ($soapOptions->isWsdlCached()) {
if (BaseCache::isEnabled() !== true) {
throw new Exception('WSDL cache could not be set');
}
if (null !== $limit) {
BaseCache::setLimit($limit);
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

@ -12,21 +12,27 @@
namespace BeSimple\SoapBundle\Controller;
use BeSimple\SoapBundle\Handler\ExceptionHandler;
use BeSimple\SoapBundle\Soap\SoapRequest;
use BeSimple\SoapBundle\Soap\SoapResponse;
use BeSimple\SoapServer\Exception as SoapException;
use Symfony\Component\DependencyInjection\ContainerAware;
use BeSimple\SoapServer\SoapServerBuilder;
use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
/**
* @author Christian Kerl <christian-kerl@web.de>
* @author Francis Besset <francis.besset@gmail.com>
*/
class SoapWebServiceController extends ContainerAware
class SoapWebServiceController implements ContainerAwareInterface
{
use ContainerAwareTrait;
/**
* @var \SoapServer
*/
@ -61,9 +67,10 @@ class SoapWebServiceController extends ContainerAware
$this->serviceBinder = $webServiceContext->getServiceBinder();
$this->soapRequest = SoapRequest::createFromHttpRequest($this->container->get('request'));
$this->soapRequest = SoapRequest::createFromHttpRequest($this->container->get('request_stack')->getCurrentRequest());
$this->soapServer = $webServiceContext
->getServerBuilder()
->withSoapVersion11()
->withHandler($this)
->build()
;
@ -91,14 +98,69 @@ class SoapWebServiceController extends ContainerAware
)
));
$query = $this->container->get('request')->query;
if (!$query->has('wsdl') && !$query->has('WSDL')) {
$this->container->get('request')->setRequestFormat('xml');
$request = $this->container->get('request');
$query = $request->query;
if ($query->has('wsdl') || $query->has('WSDL')) {
$request->setRequestFormat('wsdl');
}
return $response;
}
/**
* Converts an Exception to a SoapFault Response.
*
* @param Request $request The request
* @param FlattenException $exception A FlattenException instance
* @param DebugLoggerInterface $logger A DebugLoggerInterface instance
*
* @return Response
*
* @throws \LogicException When the request query parameter "_besimple_soap_webservice" does not exist
*/
public function exceptionAction(Request $request, FlattenException $exception, DebugLoggerInterface $logger = null)
{
if (!$webservice = $request->query->get('_besimple_soap_webservice')) {
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';
$code = $exception->getStatusCode();
$details = $this->container->get('templating')->render($view, array(
'status_code' => $code,
'status_text' => isset(Response::$statusTexts[$code]) ? Response::$statusTexts[$code] : '',
'exception' => $exception,
'logger' => $logger,
));
$handler = new ExceptionHandler($exception, $details);
if ($soapFault = $request->query->get('_besimple_soap_fault')) {
$handler->setSoapFault($soapFault);
// Remove parameter from query because cannot be Serialized in Logger
$request->query->remove('_besimple_soap_fault');
}
$server = SoapServerBuilder::createWithDefaults(__DIR__.'/../Handler/wsdl/exception.wsdl')
->withWsdl()
->withWsdlCacheNone()
->withHandler($handler)
->build()
;
ob_start();
$server->handle(
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://besim.pl/soap/exception/1.0/">'.
'<soapenv:Header/>'.
'<soapenv:Body>'.
'<ns:exception />'.
'</soapenv:Body>'.
'</soapenv:Envelope>'
);
return new Response(ob_get_clean());
}
/**
* This method gets called once for every SOAP header the \SoapServer received
* and afterwards once for the called SOAP operation.
@ -124,13 +186,7 @@ class SoapWebServiceController extends ContainerAware
);
// forward to controller
try {
$response = $this->container->get('http_kernel')->handle($this->soapRequest, HttpKernelInterface::SUB_REQUEST, false);
} catch (\Exception $e) {
$this->soapResponse = new Response(null, 500);
throw $e instanceof \SoapFault || $this->container->getParameter('kernel.debug') ? $e : new SoapException\ReceiverSoapFault($e->getMessage());
}
$response = $this->container->get('http_kernel')->handle($this->soapRequest, HttpKernelInterface::SUB_REQUEST, false);
$this->setResponse($response);

View File

@ -12,8 +12,6 @@ namespace BeSimple\SoapBundle\Converter;
use BeSimple\SoapBundle\ServiceDefinition\ServiceDefinition;
use BeSimple\SoapBundle\Util\Assert;
use BeSimple\SoapBundle\Util\QName;
use BeSimple\SoapBundle\Util\String;
/**
* @author Christian Kerl <christian-kerl@web.de>
@ -50,8 +48,6 @@ class TypeRepository
public function fixTypeInformation(ServiceDefinition $definition)
{
$typeMap = $this->defaultTypeMap;
foreach($definition->getAllTypes() as $type) {
$phpType = $type->getPhpType();
$xmlType = $type->getXmlType();

View File

@ -13,6 +13,7 @@ namespace BeSimple\SoapBundle\Converter;
use BeSimple\SoapBundle\Soap\SoapRequest;
use BeSimple\SoapBundle\Soap\SoapResponse;
use BeSimple\SoapBundle\Util\String;
use BeSimple\SoapCommon\Converter\TypeConverterInterface;
/**
* @author Christian Kerl <christian-kerl@web.de>

View File

@ -63,6 +63,8 @@ class BeSimpleSoapExtension extends Extension
$serviceConfig['name'] = $name;
$this->createWebServiceContext($serviceConfig, $container);
}
$container->setParameter('besimple.soap.exception_listener.controller', $config['exception_controller']);
}
private function registerCacheConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
@ -82,7 +84,7 @@ class BeSimpleSoapExtension extends Extension
foreach ($config as $client => $options) {
$definition = new DefinitionDecorator('besimple.soap.client.builder');
$context = $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']);
@ -96,18 +98,31 @@ class BeSimpleSoapExtension extends Extension
}
}
$proxy = $options['proxy'];
if (false !== $proxy['host']) {
if (null !== $proxy['auth']) {
if ('basic' === $proxy['auth']) {
$proxy['auth'] = \CURLAUTH_BASIC;
} elseif ('ntlm' === $proxy['auth']) {
$proxy['auth'] = \CURLAUTH_NTLM;
}
}
$definition->addMethodCall('withProxy', array(
$proxy['host'], $proxy['port'],
$proxy['login'], $proxy['password'],
$proxy['auth']
));
}
if (isset($defOptions['cache_type'])) {
$defOptions['cache_type'] = $this->getCacheType($defOptions['cache_type']);
}
$definition->replaceArgument(1, $defOptions);
if (!empty($options['classmap'])) {
$classmap = $this->createClientClassmap($client, $options['classmap'], $container);
$definition->replaceArgument(2, new Reference($classmap));
} else {
$definition->replaceArgument(2, null);
}
$classmap = $this->createClientClassmap($client, $options['classmap'], $container);
$definition->replaceArgument(2, new Reference($classmap));
$this->createClient($client, $container);
}
@ -116,11 +131,13 @@ class BeSimpleSoapExtension extends Extension
private function createClientClassmap($client, array $classmap, ContainerBuilder $container)
{
$definition = new DefinitionDecorator('besimple.soap.classmap');
$context = $container->setDefinition(sprintf('besimple.soap.classmap.%s', $client), $definition);
$container->setDefinition(sprintf('besimple.soap.classmap.%s', $client), $definition);
$definition->setMethodCalls(array(
array('set', array($classmap)),
));
if (!empty($classmap)) {
$definition->setMethodCalls(array(
array('set', array($classmap)),
));
}
return sprintf('besimple.soap.classmap.%s', $client);
}
@ -128,9 +145,12 @@ class BeSimpleSoapExtension extends Extension
private function createClient($client, ContainerBuilder $container)
{
$definition = new DefinitionDecorator('besimple.soap.client');
$context = $container->setDefinition(sprintf('besimple.soap.client.%s', $client), $definition);
$container->setDefinition(sprintf('besimple.soap.client.%s', $client), $definition);
$definition->setFactoryService(sprintf('besimple.soap.client.builder.%s', $client));
$definition->setFactory(array(
new Reference(sprintf('besimple.soap.client.builder.%s', $client)),
'build'
));
}
private function createWebServiceContext(array $config, ContainerBuilder $container)
@ -140,7 +160,7 @@ class BeSimpleSoapExtension extends Extension
$contextId = 'besimple.soap.context.'.$config['name'];
$definition = new DefinitionDecorator('besimple.soap.context.'.$bindingSuffix);
$context = $container->setDefinition($contextId, $definition);
$container->setDefinition($contextId, $definition);
if (isset($config['cache_type'])) {
$config['cache_type'] = $this->getCacheType($config['cache_type']);
@ -148,9 +168,9 @@ class BeSimpleSoapExtension extends Extension
$options = $container
->getDefinition('besimple.soap.context.'.$bindingSuffix)
->getArgument(5);
->getArgument(2);
$definition->replaceArgument(5, array_merge($options, $config));
$definition->replaceArgument(2, array_merge($options, $config));
}
private function getCacheType($type)

View File

@ -24,6 +24,7 @@ use Symfony\Component\Config\Definition\Builder\TreeBuilder;
class Configuration
{
private $cacheTypes = array('none', 'disk', 'memory', 'disk_memory');
private $proxyAuth = array('basic', 'ntlm');
/**
* Generates the configuration tree.
@ -40,6 +41,12 @@ class Configuration
$this->addServicesSection($rootNode);
$this->addWsdlDumperSection($rootNode);
$rootNode
->children()
->scalarNode('exception_controller')->defaultValue('BeSimpleSoapBundle:SoapWebService:exception')->end()
->end()
;
return $treeBuilder->buildTree();
}
@ -79,12 +86,33 @@ class Configuration
->scalarNode('cache_type')
->validate()
->ifNotInArray($this->cacheTypes)
->thenInvalid(sprintf('The cache type has to be either %s', implode(', ', $this->cacheTypes)))
->thenInvalid(sprintf('The cache type has to be either: %s', implode(', ', $this->cacheTypes)))
->end()
->end()
->arrayNode('classmap')
->useAttributeAsKey('name')->prototype('scalar')->end()
->end()
->arrayNode('proxy')
->info('proxy configuration')
->addDefaultsIfNotSet()
->beforeNormalization()
->ifTrue(function ($v) { return !is_array($v); })
->then(function ($v) { return array('host' => null === $v ? false : $v); })
->end()
->children()
->scalarNode('host')->defaultFalse()->end()
->scalarNode('port')->defaultValue(3128)->end()
->scalarNode('login')->defaultNull()->end()
->scalarNode('password')->defaultNull()->end()
->scalarNode('auth')
->defaultNull()
->validate()
->ifNotInArray($this->proxyAuth)
->thenInvalid(sprintf('The proxy auth has to be either: %s', implode(', ', $this->proxyAuth)))
->end()
->end()
->end()
->end()
->end()
->end()
->end()

View File

@ -2,7 +2,6 @@
namespace BeSimple\SoapBundle\EventListener;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
class RequestFormatListener

View File

@ -0,0 +1,87 @@
<?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\SoapBundle\EventListener;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\EventListener\ExceptionListener;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* @author Francis Besset <francis.besset@gmail.com>
*/
class SoapExceptionListener extends ExceptionListener
{
/**
* @var ContainerInterface
*/
protected $container;
/**
* To avoid conflict between , the logger param is not typed:
* The parent class needs and instance of `Psr\Log\LoggerInterface` from Symfony 2.2,
* before logger is an instance of `Symfony\Component\HttpKernel\Log\LoggerInterface`.
*
* @param ContainerInterface $container A ContainerInterface instance
* @param string $controller The controller name to call
* @param LoggerInterface $logger A logger instance
*/
public function __construct(ContainerInterface $container, $controller, $logger)
{
parent::__construct($controller, $logger);
$this->container = $container;
}
public function onKernelException(GetResponseForExceptionEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
}
$request = $event->getRequest();
if (!in_array($request->getRequestFormat(), array('soap', 'xml'))) {
return;
} elseif ('xml' === $request->getRequestFormat() && '_webservice_call' !== $request->attributes->get('_route')) {
return;
}
$attributes = $request->attributes;
if (!$webservice = $attributes->get('webservice')) {
return;
}
if (!$this->container->has(sprintf('besimple.soap.context.%s', $webservice))) {
return;
}
// hack to retrieve the current WebService name in the controller
$request->query->set('_besimple_soap_webservice', $webservice);
$exception = $event->getException();
if ($exception instanceof \SoapFault) {
$request->query->set('_besimple_soap_fault', $exception);
}
parent::onKernelException($event);
}
public static function getSubscribedEvents()
{
return array(
// Must be called before ExceptionListener of HttpKernel component
KernelEvents::EXCEPTION => array('onKernelException', -64),
);
}
}

View File

@ -0,0 +1,53 @@
<?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\SoapBundle\Handler;
use BeSimple\SoapServer\Exception\ReceiverSoapFault;
use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\HttpFoundation\Response;
/**
* @author Francis Besset <francis.besset@gmail.com>
*/
class ExceptionHandler
{
protected $exception;
protected $details;
protected $soapFault;
public function __construct(FlattenException $exception, $details = null)
{
$this->exception = $exception;
$this->details = $details;
}
public function setSoapFault(\SoapFault $soapFault)
{
$this->soapFault = $soapFault;
}
public function __call($method, $arguments)
{
if (isset($this->soapFault)) {
throw $this->soapFault;
}
$code = $this->exception->getStatusCode();
throw new ReceiverSoapFault(
isset(Response::$statusTexts[$code]) ? Response::$statusTexts[$code] : '',
null,
$this->details
);
}
}

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://besim.pl/soap/exception/1.0/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" name="Exception" targetNamespace="http://besim.pl/soap/exception/1.0/">
<portType name="ExceptionPortType">
<operation name="exception">
<input message="tns:empty"/>
<output message="tns:empty"/>
</operation>
</portType>
<message name="empty" />
<binding name="ExceptionBinding" type="tns:ExceptionPortType">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/>
<operation name="exception">
<soap:operation soapAction="http://besim.pl/soap/exception/1.0/exception"/>
<input>
<soap:body use="literal" namespace="http://besim.pl/soap/exception/1.0/" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
<output>
<soap:body use="literal" namespace="http://besim.pl/soap/exception/1.0/" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</output>
</operation>
</binding>
<service name="ExceptionService">
<port name="ExceptionPort" binding="tns:ExceptionBinding">
<soap:address location="http://localhost/soap/Exception"/>
</port>
</service>
</definitions>

View File

@ -16,9 +16,12 @@
</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" factory-service="besimple.soap.client.builder" factory-method="build" 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" />
</service>
<service id="besimple.soap.classmap" class="%besimple.soap.classmap.class%" abstract="true" />
</services>

View File

@ -29,10 +29,13 @@
<service id="besimple.soap.definition.loader.annot_class" class="%besimple.soap.definition.loader.annot_class.class%" public="false">
<tag name="besimple.soap.definition.loader" />
<argument type="service" id="annotation_reader" />
<argument type="service" id="besimple.soap.type.repository" />
</service>
<service id="besimple.soap.definition.loader.annot_complextype" class="%besimple.soap.definition.loader.annot_complextype.class%" public="false">
<tag name="besimple.soap.definition.loader" />
<argument type="service" id="annotation_reader" />
<argument type="service" id="besimple.soap.type.repository" />
</service>
</services>

View File

@ -4,15 +4,15 @@
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">
<route id="_webservice_call" pattern="/{webservice}">
<route id="_webservice_call" path="/{webservice}">
<default key="_controller">BeSimpleSoapBundle:SoapWebService:Call</default>
<default key="_format">soap</default>
<default key="_format">xml</default>
<requirement key="_method">POST</requirement>
</route>
<route id="_webservice_definition" pattern="/{webservice}">
<route id="_webservice_definition" path="/{webservice}">
<default key="_controller">BeSimpleSoapBundle:SoapWebService:Definition</default>
<default key="_format">wsdl</default>
<default key="_format">xml</default>
<requirement key="_method">GET</requirement>
</route>
</routes>

View File

@ -12,7 +12,7 @@
<service id="besimple.soap.cache" class="%besimple.soap.cache.class%">
<argument>%kernel.debug%</argument>
<argument>%besimple.soap.cache.type%</argument>
<argument>%besimple.soap.cache.dir%/php</argument>
<argument>%besimple.soap.cache.dir%/cache</argument>
<argument>%besimple.soap.cache.lifetime%</argument>
<argument>%besimple.soap.cache.limit%</argument>
</service>

View File

@ -6,6 +6,7 @@
<parameters>
<parameter key="besimple.soap.response.class">BeSimple\SoapBundle\Soap\SoapResponse</parameter>
<parameter key="besimple.soap.response.listener.class">BeSimple\SoapBundle\EventListener\SoapResponseListener</parameter>
<parameter key="besimple.soap.exception_listener.class">BeSimple\SoapBundle\EventListener\SoapExceptionListener</parameter>
<parameter key="besimple.soap.context.class">BeSimple\SoapBundle\WebServiceContext</parameter>
<parameter key="besimple.soap.binder.request_header.rpcliteral.class">BeSimple\SoapBundle\ServiceBinding\RpcLiteralRequestHeaderMessageBinder</parameter>
<parameter key="besimple.soap.binder.request.rpcliteral.class">BeSimple\SoapBundle\ServiceBinding\RpcLiteralRequestMessageBinder</parameter>
@ -13,8 +14,7 @@
<parameter key="besimple.soap.binder.request.documentwrapped.class">BeSimple\SoapBundle\ServiceBinding\DocumentLiteralWrappedRequestMessageBinder</parameter>
<parameter key="besimple.soap.binder.request_header.documentwrapped.class">BeSimple\SoapBundle\ServiceBinding\DocumentLiteralWrappedRequestHeaderMessageBinder</parameter>
<parameter key="besimple.soap.binder.response.documentwrapped.class">BeSimple\SoapBundle\ServiceBinding\DocumentLiteralWrappedResponseMessageBinder</parameter>
<parameter key="besimple.soap.definition.dumper.wsdl.rpcliteral.class">BeSimple\SoapBundle\ServiceDefinition\Dumper\WsdlDumper</parameter>
<parameter key="besimple.soap.type.repository.class">BeSimple\SoapBundle\Converter\TypeRepository</parameter>
<parameter key="besimple.soap.type.repository.class">BeSimple\SoapCommon\Definition\Type\TypeRepository</parameter>
<parameter key="besimple.soap.server.classmap.class">BeSimple\SoapServer\Classmap</parameter>
</parameters>
@ -26,11 +26,16 @@
<argument type="service" id="besimple.soap.response" />
</service>
<service id="besimple.soap.exception_listener" class="%besimple.soap.exception_listener.class%">
<tag name="kernel.event_subscriber" />
<tag name="monolog.logger" channel="request" />
<argument type="service" id="service_container" />
<argument>%besimple.soap.exception_listener.controller%</argument>
<argument type="service" id="logger" on-invalid="null" />
</service>
<service id="besimple.soap.context.rpcliteral" class="%besimple.soap.context.class%" abstract="true">
<argument type="service" id="besimple.soap.definition.loader" />
<argument type="service" id="besimple.soap.definition.dumper.wsdl.rpcliteral" />
<argument type="service" id="besimple.soap.server.classmap" />
<argument type="service" id="besimple.soap.type.repository" />
<argument type="service" id="besimple.soap.converter.collection" />
<argument type="collection">
<argument key="cache_dir">%besimple.soap.cache.dir%</argument>
@ -39,15 +44,13 @@
<argument key="binder_request_header_class">%besimple.soap.binder.request_header.rpcliteral.class%</argument>
<argument key="binder_request_class">%besimple.soap.binder.request.rpcliteral.class%</argument>
<argument key="binder_response_class">%besimple.soap.binder.response.rpcliteral.class%</argument>
<argument key="wsdl_stylesheet">%besimple.soap.definition.dumper.options.stylesheet%</argument>
</argument>
<argument type="service" id="besimple.soap.cache" />
</service>
<service id="besimple.soap.context.documentwrapped" class="%besimple.soap.context.class%" abstract="true">
<argument type="service" id="besimple.soap.definition.loader" />
<argument type="service" id="besimple.soap.definition.dumper.wsdl.documentwrapped" />
<argument type="service" id="besimple.soap.server.classmap" />
<argument type="service" id="besimple.soap.type.repository" />
<argument type="service" id="besimple.soap.converter.collection" />
<argument type="collection">
<argument key="cache_dir">%besimple.soap.cache.dir%</argument>
@ -56,46 +59,40 @@
<argument key="binder_request_header_class">%besimple.soap.binder.request_header.documentwrapped.class%</argument>
<argument key="binder_request_class">%besimple.soap.binder.request.documentwrapped.class%</argument>
<argument key="binder_response_class">%besimple.soap.binder.response.documentwrapped.class%</argument>
<argument key="wsdl_stylesheet">%besimple.soap.definition.dumper.options.stylesheet%</argument>
</argument>
<argument type="service" id="besimple.soap.cache" />
</service>
<service id="besimple.soap.definition.dumper.wsdl.rpcliteral" class="%besimple.soap.definition.dumper.wsdl.rpcliteral.class%">
<argument type="service" id="besimple.soap.definition.loader.annot_complextype" />
<argument type="service" id="besimple.soap.type.repository" />
<argument type="collection">
<argument key="stylesheet">%besimple.soap.definition.dumper.options.stylesheet%</argument>
</argument>
</service>
<service id="besimple.soap.server.classmap" class="%besimple.soap.server.classmap.class%" public="false" />
<service id="besimple.soap.type.repository" class="%besimple.soap.type.repository.class%">
<argument type="service" id="besimple.soap.server.classmap" />
<call method="addXmlNamespace">
<argument>xsd</argument>
<argument>http://www.w3.org/2001/XMLSchema</argument>
</call>
<call method="addDefaultTypeMapping">
<call method="addType">
<argument>string</argument>
<argument>xsd:string</argument>
</call>
<call method="addDefaultTypeMapping">
<call method="addType">
<argument>boolean</argument>
<argument>xsd:boolean</argument>
</call>
<call method="addDefaultTypeMapping">
<call method="addType">
<argument>int</argument>
<argument>xsd:int</argument>
</call>
<call method="addDefaultTypeMapping">
<call method="addType">
<argument>float</argument>
<argument>xsd:float</argument>
</call>
<call method="addDefaultTypeMapping">
<call method="addType">
<argument>date</argument>
<argument>xsd:date</argument>
</call>
<call method="addDefaultTypeMapping">
<call method="addType">
<argument>dateTime</argument>
<argument>xsd:dateTime</argument>
</call>

View File

@ -33,4 +33,8 @@ SoapServer
SoapClient
----------
Coming soon.
.. toctree::
:maxdepth: 1
:numbered:
soapclient/configuration

View File

@ -0,0 +1,158 @@
Configuration
=============
Client configuration
--------------------
Configure your first client in your config file:
.. code-block:: yaml
# app/config/config.yml
be_simple_soap:
clients:
DemoApi:
# required
wsdl: http://localhost/app_dev.php/ws/DemoApi?wsdl
# classmap (optional)
classmap:
type_name: "Full\Class\Name"
# proxy (optional)
proxy:
host: proxy.domain.name # required to enable proxy configuration
port: 3128
login: ~
password: ~
auth: ~ # can be 'basic' or 'ntlm'
Using client
------------
.. code-block:: php
namespace Acme\DemoBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class DemoController extends Controller
{
public function helloAction($name)
{
// The client service name is `besimple.soap.client.demoapi`:
// `besimple.soap.client.`: is the base name of your client
// `demoapi`: is the name specified in your config file converted to lowercase
$client = $this->container->get('besimple.soap.client.demoapi');
// call `hello` method on WebService with the string parameter `$name`
$helloResult = $client->hello($name);
return $this->render('AcmeDemoBundle:Demo:hello.html.twig', array(
'hello' => $helloResult,
));
}
}
Classmap
--------
Configuration
~~~~~~~~~~~~~
.. code-block:: yaml
# app/config/config.yml
be_simple_soap:
clients:
DemoApi:
# ...
classmap:
User: Acme\DemoBundle\Api\UserApi
# add other type_name: classname
UserApi class
~~~~~~~~~~~~~
.. code-block:: php
namespace Acme\DemoBundle\Api;
class UserApi
{
private $username;
private $firstname;
private $lastname;
public function __construct($username)
{
$this->username = $username;
}
public function getFirstname()
{
return $this->firstname;
}
public function getLastname()
{
return $this->lastname;
}
}
Usage
~~~~~
.. code-block:: php
namespace Acme\DemoBundle\Controller;
use Acme\DemoBundle\Api\UserApi;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class DemoController extends Controller
{
public function userAction($username)
{
// The client service name is `besimple.soap.client.demoapi`:
// `besimple.soap.client.`: is the base name of your client
// `demoapi`: is the name specified in your config file converted to lowercase
$client = $this->container->get('besimple.soap.client.demoapi');
// call `getUser` method on WebService with an instance of UserApi
// if the `getUserByUsername` method return a `User` type then `$userResult` is an instance of UserApi
$userResult = $client->getUserByUsername($username);
return $this->render('AcmeDemoBundle:Demo:user.html.twig', array(
'user' => $userResult,
));
}
}
Without classmap configuration the `$userResult` is an instance of `stdClass`:
.. code-block:: text
object(stdClass)#5561 (3) {
["username"]=>
string(6) "FooBar"
["firstname"]=>
string(3) "Foo"
["lastname"]=>
string(3) "Bar"
}
With classmap configuration the `$userResult` is an instance of `Acme\DemoBundle\Api\UserApi`:
.. code-block:: text
object(Acme\DemoBundle\Api\UserApi)#208 (3) {
["username":"Acme\DemoBundle\Api\UserApi":private]=>
string(6) "FooBar"
["firstname":"Acme\DemoBundle\Api\UserApi":private]=>
string(3) "Foo"
["lastname":"Acme\DemoBundle\Api\UserApi":private]=>
string(3) "Bar"
}

View File

@ -47,9 +47,9 @@ Controller
/**
* @Soap\Method("sendAssocArray")
* @Soap\Param("assocArray", phpType = "BeSimple\SoapCommon\Type\KeyValue\String[]")
* @Soap\Return(phpType = "BeSimple\SoapCommon\Type\KeyValue\String[]")
* @Soap\Result(phpType = "BeSimple\SoapCommon\Type\KeyValue\String[]")
*/
public function assocArrayOfStringAction(array $assocArray)
public function sendAssocArrayOfStringAction(array $assocArray)
{
// The $assocArray it's a real associative array
// var_dump($assocArray);die;
@ -97,3 +97,4 @@ How to create my Associative Array?
'user2' => new User('user2', 'user2@user.com'),
);
}
}

View File

@ -86,6 +86,16 @@ You can expose only the properties (public, protected or private) of a complex t
*/
private $newsletter;
/**
* @Soap\ComplexType("date")
*/
private $createdAt:
/**
* @Soap\ComplexType("datetime")
*/
private $updatedAt;
public function getId()
{
return $this->id;
@ -128,7 +138,27 @@ You can expose only the properties (public, protected or private) of a complex t
public function setNewsletter($newsletter)
{
$this->newletter = (Boolean) $newsletter
$this->newletter = (Boolean) $newsletter;
}
public function getCreatedAt()
{
return $this->createdAt;
}
public function setCreatedAt(\DateTime $createdAt)
{
$this->createdAt = $createdAt;
}
public function getUpdatedAt()
{
return this->updatedAt;
}
public function setUpdatedAt(\DateTime $updatedAt)
{
$this->updatedAt = $updatedAt;
}
}

View File

@ -11,6 +11,7 @@
namespace BeSimple\SoapBundle\ServiceBinding;
use BeSimple\SoapBundle\ServiceDefinition\Method;
use BeSimple\SoapCommon\Definition\Type\TypeRepository;
/**
* @author Christian Kerl <christian-kerl@web.de>
@ -23,5 +24,5 @@ interface MessageBinderInterface
*
* @return mixed
*/
function processMessage(Method $messageDefinition, $message, array $definitionComplexTypes = array());
function processMessage(Method $messageDefinition, $message, TypeRepository $typeRepository);
}

View File

@ -11,6 +11,7 @@
namespace BeSimple\SoapBundle\ServiceBinding;
use BeSimple\SoapBundle\ServiceDefinition\Method;
use BeSimple\SoapCommon\Definition\Type\TypeRepository;
/**
* @author Francis Besset <francis.besset@gmail.com>
@ -24,10 +25,11 @@ class RpcLiteralRequestHeaderMessageBinder extends RpcLiteralRequestMessageBinde
$this->header = $header;
}
public function processMessage(Method $messageDefinition, $message, array $definitionComplexTypes = array())
public function processMessage(Method $messageDefinition, $message, TypeRepository $typeRepository)
{
$this->typeRepository = $typeRepository;
$headerDefinition = $messageDefinition->getHeaders()->get($this->header);
return $this->processType($headerDefinition->getType()->getPhpType(), $message, $definitionComplexTypes);
return $this->processType($headerDefinition->getType(), $message);
}
}

View File

@ -13,8 +13,9 @@
namespace BeSimple\SoapBundle\ServiceBinding;
use BeSimple\SoapBundle\ServiceDefinition\Method;
use BeSimple\SoapBundle\ServiceDefinition\Strategy\MethodComplexType;
use BeSimple\SoapBundle\ServiceDefinition\Strategy\PropertyComplexType;
use BeSimple\SoapCommon\Definition\Type\ArrayOfType;
use BeSimple\SoapCommon\Definition\Type\ComplexType;
use BeSimple\SoapCommon\Definition\Type\TypeRepository;
use BeSimple\SoapCommon\Util\MessageBinder;
/**
@ -23,19 +24,20 @@ use BeSimple\SoapCommon\Util\MessageBinder;
*/
class RpcLiteralRequestMessageBinder implements MessageBinderInterface
{
private $messageRefs = array();
private $definitionComplexTypes;
protected $typeRepository;
public function processMessage(Method $messageDefinition, $message, array $definitionComplexTypes = array())
private $messageRefs = array();
public function processMessage(Method $messageDefinition, $message, TypeRepository $typeRepository)
{
$this->definitionComplexTypes = $definitionComplexTypes;
$this->typeRepository = $typeRepository;
$result = array();
$i = 0;
foreach ($messageDefinition->getArguments() as $argument) {
foreach ($messageDefinition->getInput()->all() as $argument) {
if (isset($message[$i])) {
$result[$argument->getName()] = $this->processType($argument->getType()->getPhpType(), $message[$i]);
$result[$argument->getName()] = $this->processType($argument->getType(), $message[$i]);
}
$i++;
@ -48,14 +50,18 @@ class RpcLiteralRequestMessageBinder implements MessageBinderInterface
{
$isArray = false;
if (preg_match('/^([^\[]+)\[\]$/', $phpType, $match)) {
$type = $this->typeRepository->getType($phpType);
if ($type instanceof ArrayOfType) {
$isArray = true;
$array = array();
$phpType = $match[1];
$array = array();
$type = $this->typeRepository->getType($type->get('item')->getType());
}
// @TODO Fix array reference
if (isset($this->definitionComplexTypes[$phpType])) {
if ($type instanceof ComplexType) {
$phpType = $type->getPhpType();
if ($isArray) {
if (isset($message->item)) {
foreach ($message->item as $complexType) {
@ -98,17 +104,16 @@ class RpcLiteralRequestMessageBinder implements MessageBinderInterface
$this->messageRefs[$hash] = $message;
$messageBinder = new MessageBinder($message);
foreach ($this->definitionComplexTypes[$phpType]['properties'] as $type) {
foreach ($this->typeRepository->getType($phpType)->all() as $type) {
$property = $type->getName();
$value = $messageBinder->readProperty($property);
if (null !== $value) {
$value = $this->processType($type->getValue(), $value);
$value = $this->processType($type->getType(), $value);
$messageBinder->writeProperty($property, $value);
}
if (!$type->isNillable() && null === $value) {
} elseif (!$type->isNillable()) {
// @TODO use xmlType instead of phpType
throw new \SoapFault('SOAP_ERROR_COMPLEX_TYPE', sprintf('"%s:%s" cannot be null.', ucfirst($phpType), $type->getName()));
}
}

View File

@ -13,8 +13,9 @@
namespace BeSimple\SoapBundle\ServiceBinding;
use BeSimple\SoapBundle\ServiceDefinition\Method;
use BeSimple\SoapBundle\ServiceDefinition\Strategy\PropertyComplexType;
use BeSimple\SoapBundle\ServiceDefinition\Strategy\MethodComplexType;
use BeSimple\SoapCommon\Definition\Type\ArrayOfType;
use BeSimple\SoapCommon\Definition\Type\ComplexType;
use BeSimple\SoapCommon\Definition\Type\TypeRepository;
use BeSimple\SoapCommon\Util\MessageBinder;
/**
@ -23,26 +24,31 @@ use BeSimple\SoapCommon\Util\MessageBinder;
*/
class RpcLiteralResponseMessageBinder implements MessageBinderInterface
{
protected $typeRepository;
private $messageRefs = array();
private $definitionComplexTypes;
public function processMessage(Method $messageDefinition, $message, array $definitionComplexTypes = array())
public function processMessage(Method $messageDefinition, $message, TypeRepository $typeRepository)
{
$this->definitionComplexTypes = $definitionComplexTypes;
$this->typeRepository = $typeRepository;
return $this->processType($messageDefinition->getReturn()->getPhpType(), $message);
return $this->processType($messageDefinition->getOutput()->get('return')->getType(), $message);
}
private function processType($phpType, $message)
{
$isArray = false;
if (preg_match('/^([^\[]+)\[\]$/', $phpType, $match)) {
$type = $this->typeRepository->getType($phpType);
if ($type instanceof ArrayOfType) {
$isArray = true;
$phpType = $match[1];
$type = $this->typeRepository->getType($type->get('item')->getType());
}
if (isset($this->definitionComplexTypes[$phpType])) {
if ($type instanceof ComplexType) {
$phpType = $type->getPhpType();
if ($isArray) {
$array = array();
@ -79,16 +85,16 @@ class RpcLiteralResponseMessageBinder implements MessageBinderInterface
$this->messageRefs[$hash] = $message;
if (!$message instanceof $phpType) {
throw new \InvalidArgumentException(sprintf('The instance class must be "%s", "%s" given.', get_class($message), $phpType));
throw new \InvalidArgumentException(sprintf('The instance class must be "%s", "%s" given.', $phpType, get_class($message)));
}
$messageBinder = new MessageBinder($message);
foreach ($this->definitionComplexTypes[$phpType]['properties'] as $type) {
foreach ($this->typeRepository->getType($phpType)->all() as $type) {
$property = $type->getName();
$value = $messageBinder->readProperty($property);
if (null !== $value) {
$value = $this->processType($type->getValue(), $value);
$value = $this->processType($type->getType(), $value);
$messageBinder->writeProperty($property, $value);
}

View File

@ -10,8 +10,7 @@
namespace BeSimple\SoapBundle\ServiceBinding;
use BeSimple\SoapBundle\ServiceDefinition\Header;
use BeSimple\SoapBundle\ServiceDefinition\ServiceDefinition;
use BeSimple\SoapBundle\ServiceDefinition\Definition;
use BeSimple\SoapBundle\Soap\SoapHeader;
/**
@ -40,12 +39,12 @@ class ServiceBinder
private $responseMessageBinder;
/**
* @param ServiceDefinition $definition
* @param Definition $definition
* @param MessageBinderInterface $requestHeaderMessageBinder
* @param MessageBinderInterface $requestMessageBinder
* @param MessageBinderInterface $responseMessageBinder
*/
public function __construct(ServiceDefinition $definition, MessageBinderInterface $requestHeaderMessageBinder, MessageBinderInterface $requestMessageBinder, MessageBinderInterface $responseMessageBinder) {
public function __construct(Definition $definition, MessageBinderInterface $requestHeaderMessageBinder, MessageBinderInterface $requestMessageBinder, MessageBinderInterface $responseMessageBinder) {
$this->definition = $definition;
$this->requestHeaderMessageBinder = $requestHeaderMessageBinder;
@ -62,7 +61,7 @@ class ServiceBinder
*/
public function isServiceHeader($method, $header)
{
return $this->definition->getMethods()->get($method)->getHeaders()->has($header);
return $this->definition->getMethod($method)->getHeader($header);
}
/**
@ -72,7 +71,7 @@ class ServiceBinder
*/
public function isServiceMethod($method)
{
return $this->definition->getMethods()->has($method);
return null !== $this->definition->getMethod($method);
}
/**
@ -84,11 +83,11 @@ class ServiceBinder
*/
public function processServiceHeader($method, $header, $data)
{
$methodDefinition = $this->definition->getMethods()->get($method);
$headerDefinition = $methodDefinition->getHeaders()->get($header);
$methodDefinition = $this->definition->getMethod($method);
$headerDefinition = $methodDefinition->getHeader($header);
$this->requestHeaderMessageBinder->setHeader($header);
$data = $this->requestHeaderMessageBinder->processMessage($methodDefinition, $data, $this->definition->getDefinitionComplexTypes());
$data = $this->requestHeaderMessageBinder->processMessage($methodDefinition, $data, $this->definition->getTypeRepository());
return new SoapHeader($this->definition->getNamespace(), $headerDefinition->getName(), $data);
}
@ -101,11 +100,11 @@ class ServiceBinder
*/
public function processServiceMethodArguments($method, $arguments)
{
$methodDefinition = $this->definition->getMethods()->get($method);
$methodDefinition = $this->definition->getMethod($method);
return array_merge(
array('_controller' => $methodDefinition->getController()),
$this->requestMessageBinder->processMessage($methodDefinition, $arguments, $this->definition->getDefinitionComplexTypes())
$this->requestMessageBinder->processMessage($methodDefinition, $arguments, $this->definition->getTypeRepository())
);
}
@ -117,8 +116,8 @@ class ServiceBinder
*/
public function processServiceMethodReturnValue($name, $return)
{
$methodDefinition = $this->definition->getMethods()->get($name);
$methodDefinition = $this->definition->getMethod($name);
return $this->responseMessageBinder->processMessage($methodDefinition, $return, $this->definition->getDefinitionComplexTypes());
return $this->responseMessageBinder->processMessage($methodDefinition, $return, $this->definition->getTypeRepository());
}
}

View File

@ -1,43 +0,0 @@
<?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\ServiceDefinition;
class Argument
{
private $name;
private $type;
public function __construct($name = null, Type $type = null)
{
$this->setName($name);
$this->setType($type);
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
public function getType()
{
return $this->type;
}
public function setType(Type $type)
{
$this->type = $type;
}
}

View File

@ -1,8 +1,10 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
* This file is part of the BeSimpleSoap.
*
* (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.

View File

@ -0,0 +1,44 @@
<?php
/*
* This file is part of the BeSimpleSoap.
*
* (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\SoapBundle\ServiceDefinition;
use BeSimple\SoapCommon\Definition\Definition as BaseDefinition;
use BeSimple\SoapCommon\Definition\Type\TypeRepository;
/**
* @author Christian Kerl <christian-kerl@web.de>
* @author Francis Besset <francis.besset@gmail.com>
*/
class Definition extends BaseDefinition
{
public function __construct(TypeRepository $typeRepository)
{
$this->typeRepository = $typeRepository;
$this->setOptions(array());
}
public function setName($name)
{
$this->name = $name;
return $this;
}
public function setNamespace($namespace)
{
$this->namespace = $namespace;
return $this;
}
}

View File

@ -1,18 +0,0 @@
<?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\ServiceDefinition\Dumper;
use BeSimple\SoapBundle\ServiceDefinition\ServiceDefinition;
interface DumperInterface
{
function dumpServiceDefinition(ServiceDefinition $definition, $endpoint);
}

View File

@ -1,80 +0,0 @@
<?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\ServiceDefinition\Dumper;
use BeSimple\SoapBundle\Converter\TypeRepository;
use BeSimple\SoapBundle\ServiceDefinition\Type;
use Zend\Soap\Wsdl as BaseWsdl;
/**
* @author Francis Besset <francis.besset@gmail.com>
*/
class Wsdl extends BaseWsdl
{
private $typeRepository;
public function __construct(TypeRepository $typeRepository, $name, $uri, $strategy = true)
{
$this->typeRepository = $typeRepository;
parent::__construct($name, $uri, $strategy);
}
public function getType($type)
{
if ($type instanceof Type) {
return $type->getXmlType();
}
if ('\\' === $type[0]) {
$type = substr($type, 1);
}
if (!$xmlType = $this->typeRepository->getXmlTypeMapping($type)) {
$xmlType = $this->addComplexType($type);
}
return $xmlType;
}
/**
* Translate PHP type into WSDL QName
*
* @param string $type
* @return string QName
*/
public function translateType($type)
{
if (isset($this->classMap[$type])) {
return $this->classMap[$type];
}
return str_replace('\\', '.', $type);
}
public function addBindingOperationHeader(\DOMElement $bindingOperation, array $headers, array $baseBinding)
{
foreach ($headers as $header) {
$inputNode = $bindingOperation->getElementsByTagName('input')->item(0);
$headerNode = $this->toDomDocument()->createElement('soap:header');
$headerNode->setAttribute('part', $header);
foreach ($baseBinding as $name => $value) {
$headerNode->setAttribute($name, $value);
}
$inputNode->appendChild($headerNode);
}
return $bindingOperation;
}
}

View File

@ -1,177 +0,0 @@
<?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\ServiceDefinition\Dumper;
use BeSimple\SoapBundle\Converter\TypeRepository;
use BeSimple\SoapBundle\ServiceDefinition\Method;
use BeSimple\SoapBundle\ServiceDefinition\Type;
use BeSimple\SoapBundle\ServiceDefinition\ServiceDefinition;
use BeSimple\SoapBundle\ServiceDefinition\Loader\AnnotationComplexTypeLoader;
use BeSimple\SoapBundle\Util\Assert;
use BeSimple\SoapBundle\Util\QName;
/**
* @author Christian Kerl <christian-kerl@web.de>
*/
class WsdlDumper implements DumperInterface
{
private $loader;
private $typeRepository;
private $options;
private $wsdl;
private $definition;
public function __construct(AnnotationComplexTypeLoader $loader, TypeRepository $typeRepository, array $options)
{
$this->loader = $loader;
$this->typeRepository = $typeRepository;
$this->options = $options;
}
public function dumpServiceDefinition(ServiceDefinition $definition, $endpoint)
{
Assert::thatArgumentNotNull('definition', $definition);
$this->definition = $definition;
$this->wsdl = new Wsdl($this->typeRepository, $definition->getName(), $definition->getNamespace(), new WsdlTypeStrategy($this->loader, $definition));
$port = $this->wsdl->addPortType($this->getPortTypeName());
$binding = $this->wsdl->addBinding($this->getBindingName(), $this->qualify($this->getPortTypeName()));
$this->wsdl->addSoapBinding($binding, 'rpc');
$this->wsdl->addService($this->getServiceName(), $this->getPortName(), $this->qualify($this->getBindingName()), $endpoint);
foreach ($definition->getMethods() as $method) {
$requestHeaderParts =
$requestParts =
$responseParts = array();
foreach ($method->getHeaders() as $header) {
$requestHeaderParts[$header->getName()] = $this->wsdl->getType($header->getType()->getPhpType());
}
foreach ($method->getArguments() as $argument) {
$requestParts[$argument->getName()] = $this->wsdl->getType($argument->getType()->getPhpType());
}
if ($method->getReturn() !== null) {
$responseParts['return'] = $this->wsdl->getType($method->getReturn()->getPhpType());
}
if (!empty($requestHeaderParts)) {
$this->wsdl->addMessage($this->getRequestHeaderMessageName($method), $requestHeaderParts);
}
$this->wsdl->addMessage($this->getRequestMessageName($method), $requestParts);
$this->wsdl->addMessage($this->getResponseMessageName($method), $responseParts);
$portOperation = $this->wsdl->addPortOperation(
$port,
$method->getName(),
$this->qualify($this->getRequestMessageName($method)),
$this->qualify($this->getResponseMessageName($method))
);
$baseBinding =
$inputBinding =
$outputBinding = array(
'use' => 'literal',
'namespace' => $definition->getNamespace(),
'encodingStyle' => 'http://schemas.xmlsoap.org/soap/encoding/',
);
if (!empty($requestParts)) {
$portOperation->setAttribute('parameterOrder', implode(' ', array_keys($requestParts)));
$inputBinding['parts'] = implode(' ', array_keys($requestParts));
}
if (!empty($responseParts)) {
$outputBinding['parts'] = implode(' ', array_keys($responseParts));
}
$bindingOperation = $this->wsdl->addBindingOperation(
$binding,
$method->getName(),
$inputBinding,
$outputBinding
);
$bindingOperation = $this->wsdl->addBindingOperationHeader(
$bindingOperation,
array_keys($requestHeaderParts),
array_merge(array('message' => $this->qualify($this->getRequestHeaderMessageName($method))), $baseBinding)
);
$this->wsdl->addSoapOperation($bindingOperation, $this->getSoapOperationName($method));
}
$this->definition = null;
$dom = $this->wsdl->toDomDocument();
$dom->formatOutput = true;
if ($this->options['stylesheet']) {
$stylesheet = $dom->createProcessingInstruction('xml-stylesheet', sprintf('type="text/xsl" href="%s"', $this->options['stylesheet']));
$dom->insertBefore($stylesheet, $dom->documentElement);
}
return $this->wsdl->toXml();
}
protected function qualify($name, $namespace = null)
{
if($namespace === null) {
$namespace = $this->definition->getNamespace();
}
return $this->wsdl->toDomDocument()->lookupPrefix($namespace).':'.$name;
}
protected function getPortName()
{
return $this->definition->getName().'Port';
}
protected function getPortTypeName()
{
return $this->definition->getName().'PortType';
}
protected function getBindingName()
{
return $this->definition->getName().'Binding';
}
protected function getServiceName()
{
return $this->definition->getName().'Service';
}
protected function getRequestHeaderMessageName(Method $method)
{
return $method->getName().'Header';
}
protected function getRequestMessageName(Method $method)
{
return $method->getName().'Request';
}
protected function getResponseMessageName(Method $method)
{
return $method->getName().'Response';
}
protected function getSoapOperationName(Method $method)
{
return $this->definition->getNamespace().$method->getName();
}
}

View File

@ -1,95 +0,0 @@
<?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\ServiceDefinition\Dumper;
use BeSimple\SoapBundle\ServiceDefinition\ServiceDefinition;
use BeSimple\SoapBundle\ServiceDefinition\Loader\AnnotationComplexTypeLoader;
use BeSimple\SoapBundle\ServiceDefinition\Strategy\ComplexType;
use BeSimple\SoapBundle\Util\String;
use Zend\Soap\Exception;
use Zend\Soap\Wsdl as BaseWsdl;
use Zend\Soap\Wsdl\ComplexTypeStrategy\ComplexTypeStrategyInterface;
use Zend\Soap\Wsdl\ComplexTypeStrategy\ArrayOfTypeSequence;
class WsdlTypeStrategy implements ComplexTypeStrategyInterface
{
/**
* Context WSDL file
*
* @var \Zend\Soap\Wsdl|null
*/
private $context;
private $loader;
private $definition;
private $typeStrategy;
private $arrayStrategy;
public function __construct(AnnotationComplexTypeLoader $loader, ServiceDefinition $definition)
{
$this->loader = $loader;
$this->definition = $definition;
}
/**
* Method accepts the current WSDL context file.
*
* @param \Zend\Soap\Wsdl $context
*/
public function setContext(BaseWsdl $context)
{
$this->context = $context;
return $this;
}
/**
* Create a complex type based on a strategy
*
* @param string $type
*
* @return string XSD type
*
* @throws \Zend\Soap\WsdlException
*/
public function addComplexType($type)
{
if (!$this->context) {
throw new \LogicException(sprintf('Cannot add complex type "%s", no context is set for this composite strategy.', $type));
}
$strategy = String::endsWith($type, '[]') ? $this->getArrayStrategy() : $this->getTypeStrategy();
return $strategy->addComplexType($type);
}
private function getArrayStrategy()
{
if (!$this->arrayStrategy) {
$this->arrayStrategy = new ArrayOfTypeSequence();
$this->arrayStrategy->setContext($this->context);
}
return $this->arrayStrategy;
}
private function getTypeStrategy()
{
if (!$this->typeStrategy) {
$this->typeStrategy = new ComplexType($this->loader, $this->definition);
$this->typeStrategy->setContext($this->context);
}
return $this->typeStrategy;
}
}

View File

@ -1,43 +0,0 @@
<?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\ServiceDefinition;
class Header
{
private $name;
private $type;
public function __construct($name = null, Type $type = null)
{
$this->setName($name);
$this->setType($type);
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
public function getType()
{
return $this->type;
}
public function setType($type)
{
$this->type = $type;
}
}

View File

@ -1,7 +1,7 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
* This file is part of the BeSimpleSoap.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
@ -14,11 +14,10 @@ namespace BeSimple\SoapBundle\ServiceDefinition\Loader;
use BeSimple\SoapBundle\ServiceDefinition as Definition;
use BeSimple\SoapBundle\ServiceDefinition\Annotation;
use BeSimple\SoapCommon\Definition\Type\ComplexType;
use BeSimple\SoapCommon\Definition\Type\TypeRepository;
use Doctrine\Common\Annotations\Reader;
use Symfony\Component\Config\Loader\Loader;
use Symfony\Component\Config\Loader\LoaderResolverInterface;
/**
* AnnotationClassLoader loads ServiceDefinition from a PHP class and its methods.
@ -26,19 +25,23 @@ use Symfony\Component\Config\Loader\LoaderResolverInterface;
* Based on \Symfony\Component\Routing\Loader\AnnotationClassLoader
*
* @author Christian Kerl <christian-kerl@web.de>
* @author Francis Besset <francis.besset@gmail.com>
*/
class AnnotationClassLoader extends Loader
{
protected $reader;
protected $typeRepository;
/**
* Constructor.
*
* @param \Doctrine\Common\Annotations\Reader $reader
*/
public function __construct(Reader $reader)
public function __construct(Reader $reader, TypeRepository $typeRepository)
{
$this->reader = $reader;
$this->typeRepository = $typeRepository;
}
/**
@ -58,39 +61,26 @@ class AnnotationClassLoader extends Loader
}
$class = new \ReflectionClass($class);
$definition = new Definition\ServiceDefinition();
$definition = new Definition\Definition($this->typeRepository);
$serviceMethodHeaders = array();
$sharedHeaders = array();
foreach ($this->reader->getClassAnnotations($class) as $annotation) {
if ($annotation instanceof Annotation\Header) {
$serviceMethodHeaders[$annotation->getValue()] = $annotation;
$sharedHeaders[$annotation->getValue()] = $this->loadType($annotation->getPhpType());
}
}
foreach ($class->getMethods() as $method) {
$serviceArguments =
$serviceHeaders = array();
$serviceHeaders = $sharedHeaders;
$serviceArguments = array();
$serviceMethod =
$serviceReturn = null;
foreach ($serviceMethodHeaders as $annotation) {
$serviceHeaders[$annotation->getValue()] = new Definition\Header(
$annotation->getValue(),
$this->getArgumentType($method, $annotation)
);
}
foreach ($this->reader->getMethodAnnotations($method) as $annotation) {
if ($annotation instanceof Annotation\Header) {
$serviceHeaders[$annotation->getValue()] = new Definition\Header(
$annotation->getValue(),
$this->getArgumentType($method, $annotation)
);
$serviceHeaders[$annotation->getValue()] = $this->loadType($annotation->getPhpType());
} elseif ($annotation instanceof Annotation\Param) {
$serviceArguments[] = new Definition\Argument(
$annotation->getValue(),
$this->getArgumentType($method, $annotation)
);
$serviceArguments[$annotation->getValue()] = $this->loadType($annotation->getPhpType());
} elseif ($annotation instanceof Annotation\Method) {
if ($serviceMethod) {
throw new \LogicException(sprintf('@Soap\Method defined twice for "%s".', $method->getName()));
@ -105,7 +95,7 @@ class AnnotationClassLoader extends Loader
throw new \LogicException(sprintf('@Soap\Result defined twice for "%s".', $method->getName()));
}
$serviceReturn = new Definition\Type($annotation->getPhpType(), $annotation->getXmlType());
$serviceReturn = $annotation->getPhpType();
}
}
@ -114,16 +104,21 @@ class AnnotationClassLoader extends Loader
}
if ($serviceMethod) {
$serviceMethod->setArguments($serviceArguments);
$serviceMethod->setHeaders($serviceHeaders);
foreach ($serviceHeaders as $name => $type) {
$serviceMethod->addHeader($name, $type);
}
foreach ($serviceArguments as $name => $type) {
$serviceMethod->addInput($name, $type);
}
if (!$serviceReturn) {
throw new \LogicException(sprintf('@Soap\Result non-existent for "%s".', $method->getName()));
}
$serviceMethod->setReturn($serviceReturn);
$serviceMethod->setOutput($this->loadType($serviceReturn));
$definition->getMethods()->add($serviceMethod);
$definition->addMethod($serviceMethod);
}
}
@ -145,28 +140,28 @@ class AnnotationClassLoader extends Loader
}
}
/**
* @param \ReflectionMethod $method
* @param \BeSimple\SoapBundle\ServiceDefinition\Annotation\Param $annotation
*
* @return \BeSimple\SoapBundle\ServiceDefinition\Type
*/
private function getArgumentType(\ReflectionMethod $method, Annotation\Param $annotation)
private function loadType($phpType)
{
$phpType = $annotation->getPhpType();
$xmlType = $annotation->getXmlType();
if (null === $phpType) {
foreach ($method->getParameters() as $param) {
if ($param->name === $annotation->getName()) {
$phpType = $param->getClass()->name;
break;
}
}
if (false !== $arrayOf = $this->typeRepository->getArrayOf($phpType)) {
$this->loadType($arrayOf);
}
return new Definition\Type($phpType, $xmlType);
if (!$this->typeRepository->hasType($phpType)) {
$complexTypeResolver = $this->resolve($phpType, 'annotation_complextype');
if (!$complexTypeResolver) {
throw new \Exception();
}
$loaded = $complexTypeResolver->load($phpType);
$complexType = new ComplexType($phpType, isset($loaded['alias']) ? $loaded['alias'] : $phpType);
foreach ($loaded['properties'] as $name => $property) {
$complexType->add($name, $this->loadType($property->getValue()), $property->isNillable());
}
$this->typeRepository->addComplexType($complexType);
}
return $phpType;
}
/**

View File

@ -1,7 +1,7 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
* This file is part of the BeSimpleSoap.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
@ -65,4 +65,17 @@ class AnnotationComplexTypeLoader extends AnnotationClassLoader
return $annotations;
}
/**
* Returns true if this class supports the given resource.
*
* @param mixed $resource A resource
* @param string $type The resource type
*
* @return Boolean True if this class supports the given resource, false otherwise
*/
public function supports($resource, $type = null)
{
return is_string($resource) && class_exists($resource) && 'annotation_complextype' === $type;
}
}

View File

@ -1,7 +1,7 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
* This file is part of the BeSimpleSoap.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
@ -16,7 +16,6 @@ use BeSimple\SoapBundle\ServiceDefinition\ServiceDefinition;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Config\Loader\FileLoader;
use Symfony\Component\Config\Resource\FileResource;
/**
* AnnotationFileLoader loads ServiceDefinition from annotations set
@ -62,7 +61,7 @@ class AnnotationFileLoader extends FileLoader
$path = $this->locator->locate($file);
if ($class = $this->findClass($path)) {
return $definition = $this->loader->load($class, $type);
return $this->loader->load($class, $type);
}
return null;

View File

@ -1,145 +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\SoapBundle\ServiceDefinition\Loader;
use BeSimple\SoapBundle\ServiceDefinition\Argument;
use BeSimple\SoapBundle\ServiceDefinition\Header;
use BeSimple\SoapBundle\ServiceDefinition\Method;
use BeSimple\SoapBundle\ServiceDefinition\Type;
use BeSimple\SoapBundle\ServiceDefinition\ServiceDefinition;
use Symfony\Component\Config\Loader\FileLoader;
class XmlFileLoader extends FileLoader
{
public function supports($resource, $type = null)
{
return is_string($resource) && 'xml' === pathinfo($resource, PATHINFO_EXTENSION);
}
public function load($file, $type = null)
{
$path = $this->locator->locate($file);
$xml = $this->parseFile($path);
$definition = new ServiceDefinition();
$definition->setName((string) $xml['name']);
$definition->setNamespace((string) $xml['namespace']);
foreach($xml->header as $header) {
$definition->getHeaders()->add($this->parseHeader($header));
}
foreach($xml->method as $method) {
$definition->getMethods()->add($this->parseMethod($method));
}
return $definition;
}
/**
* @param \SimpleXMLElement $node
*
* @return \BeSimple\SoapBundle\ServiceDefinition\Header
*/
protected function parseHeader(\SimpleXMLElement $node)
{
return new Header((string)$node['name'], $this->parseType($node->type));
}
/**
* @param \SimpleXMLElement $node
*
* @return \BeSimple\SoapBundle\ServiceDefinition\Method
*/
protected function parseMethod(\SimpleXMLElement $node)
{
$method = new Method((string)$node['name'], (string)$node['controller']);
foreach($node->argument as $argument) {
$method->getArguments()->add($this->parseArgument($argument));
}
$method->setReturn($this->parseType($node->return->type));
return $method;
}
/**
* @param \SimpleXMLElement $node
*
* @return \BeSimple\SoapBundle\ServiceDefinition\Argument
*/
protected function parseArgument(\SimpleXMLElement $node)
{
$argument = new Argument((string)$node['name'], $this->parseType($node->type));
return $argument;
}
/**
* @param \SimpleXMLElement $node
*
* @return \BeSimple\SoapBundle\ServiceDefinition\Type
*/
protected function parseType(\SimpleXMLElement $node)
{
$namespaces = $node->getDocNamespaces(true);
$qname = explode(':', $node['xml-type'], 2);
$xmlType = sprintf('{%s}%s', $namespaces[$qname[0]], $qname[1]);
return new Type((string)$node['php-type'], $xmlType, (string)$node['converter']);
}
/**
* @param string $file
*
* @return \SimpleXMLElement
*/
protected function parseFile($file)
{
$dom = new \DOMDocument();
libxml_use_internal_errors(true);
if (!$dom->load($file, LIBXML_COMPACT)) {
throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors()));
}
if (!$dom->schemaValidate(__DIR__.'/schema/servicedefinition-1.0.xsd')) {
throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors()));
}
$dom->validateOnParse = true;
$dom->normalizeDocument();
libxml_use_internal_errors(false);
return simplexml_import_dom($dom);
}
protected function getXmlErrors()
{
$errors = array();
foreach (libxml_get_errors() as $error) {
$errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)',
LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
$error->code,
trim($error->message),
$error->file ? $error->file : 'n/a',
$error->line,
$error->column
);
}
libxml_clear_errors();
libxml_use_internal_errors(false);
return $errors;
}
}

View File

@ -1,8 +1,10 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
* This file is part of the BeSimpleSoap.
*
* (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.
@ -10,36 +12,22 @@
namespace BeSimple\SoapBundle\ServiceDefinition;
use BeSimple\SoapBundle\Util\Collection;
use BeSimple\SoapCommon\Definition\Method as BaseMethod;
use BeSimple\SoapCommon\Definition\Type\TypeRepository;
class Method
/**
* @author Christian Kerl <christian-kerl@web.de>
* @author Francis Besset <francis.besset@gmail.com>
*/
class Method extends BaseMethod
{
private $name;
private $controller;
private $arguments;
private $headers;
private $return;
public function __construct($name = null, $controller = null, array $headers = array(), array $arguments = array(), Type $return = null)
public function __construct($name, $controller)
{
$this->setName($name);
$this->setController($controller);
$this->setHeaders($headers);
$this->setArguments($arguments);
parent::__construct($name);
if ($return) {
$this->setReturn($return);
}
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
$this->controller = $controller;
}
public function getController()
@ -47,40 +35,8 @@ class Method
return $this->controller;
}
public function setController($controller)
public function getVersions()
{
$this->controller = $controller;
}
public function getHeaders()
{
return $this->headers;
}
public function setHeaders(array $headers)
{
$this->headers = new Collection('getName', 'BeSimple\SoapBundle\ServiceDefinition\Header');
$this->headers->addAll($headers);
}
public function getArguments()
{
return $this->arguments;
}
public function setArguments(array $arguments)
{
$this->arguments = new Collection('getName', 'BeSimple\SoapBundle\ServiceDefinition\Argument');
$this->arguments->addAll($arguments);
}
public function getReturn()
{
return $this->return;
}
public function setReturn(Type $return)
{
$this->return = $return;
return array(\SOAP_1_1);
}
}

View File

@ -1,151 +0,0 @@
<?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\ServiceDefinition;
use BeSimple\SoapBundle\Util\Collection;
use BeSimple\SoapCommon\Classmap;
class ServiceDefinition
{
/**
* @var string
*/
private $name;
/**
* @var string
*/
private $namespace;
/**
* @var \BeSimple\SoapBundle\Util\Collection
*/
private $methods;
/**
* @var \BeSimple\SoapCommon\Classmap
*/
private $classmap;
private $complexTypes = array();
public function __construct($name = null, $namespace = null, array $methods = array(), Classmap $classmap = null)
{
$this->setName($name);
$this->setNamespace($namespace);
$this->methods = new Collection('getName', 'BeSimple\SoapBundle\ServiceDefinition\Method');
$this->setMethods($methods);
$this->classmap = $classmap;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* @return string
*/
public function getNamespace()
{
return $this->namespace;
}
/**
* @param string $namespace
*/
public function setNamespace($namespace)
{
$this->namespace = $namespace;
}
/**
* @return \BeSimple\SoapBundle\Util\Collection
*/
public function getMethods()
{
return $this->methods;
}
/**
* @param array $methods
*/
public function setMethods(array $methods)
{
$this->methods->addAll($methods);
}
/**
* @return array
*/
public function getAllTypes()
{
$types = array();
foreach ($this->methods as $method) {
foreach ($method->getArguments() as $argument) {
$types[] = $argument->getType();
}
foreach ($method->getHeaders() as $header) {
$types[] = $header->getType();
}
$types[] = $method->getReturn();
}
return $types;
}
public function getClassmap()
{
return $this->classmap ?: array();
}
public function setClassmap(Classmap $classmap)
{
$this->classmap = $classmap;
}
public function hasDefinitionComplexType($type)
{
return isset($this->complexTypes[$type]);
}
public function addDefinitionComplexType($type, array $definition)
{
if ($this->hasDefinitionComplexType($type)) {
return false;
}
$this->complexTypes[$type] = $definition;
return true;
}
public function getDefinitionComplexTypes()
{
return $this->complexTypes;
}
}

View File

@ -1,89 +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\SoapBundle\ServiceDefinition\Strategy;
use BeSimple\SoapBundle\ServiceDefinition\Loader\AnnotationComplexTypeLoader;
use Zend\Soap\Wsdl;
use Zend\Soap\Wsdl\ComplexTypeStrategy\AbstractComplexTypeStrategy;
/**
* @author Francis Besset <francis.besset@gmail.com>
*/
class ComplexType extends AbstractComplexTypeStrategy
{
private $loader;
private $definition;
public function __construct(AnnotationComplexTypeLoader $loader, $definition)
{
$this->loader = $loader;
$this->definition = $definition;
}
/**
* Add a complex type by recursivly using all the class properties fetched via Reflection.
*
* @param string $type Name of the class to be specified
* @return string XSD Type for the given PHP type
*/
public function addComplexType($classname)
{
$classmap = $this->definition->getClassmap();
if ($classmap->hasByClassname($classname)) {
return 'tns:'.$classmap->getByClassname($classname);
}
if (!$this->loader->supports($classname)) {
throw new \InvalidArgumentException(sprintf('Cannot add ComplexType "%s" because it is not an object or the class could not be found.', $classname));
}
$definitionComplexType = $this->loader->load($classname);
$classnameAlias = isset($definitionComplexType['alias']) ? $definitionComplexType['alias'] : $classname;
$type = $this->getContext()->translateType($classnameAlias);
$xmlType = 'tns:'.$type;
// Register type here to avoid recursion
$classmap->add($type, $classname);
$this->addXmlDefinition($definitionComplexType, $classname, $type);
return $xmlType;
}
private function addXmlDefinition(array $definitionComplexType, $classname, $type)
{
$dom = $this->getContext()->toDomDocument();
$complexType = $dom->createElement('xsd:complexType');
$complexType->setAttribute('name', $type);
$all = $dom->createElement('xsd:all');
$elements = array();
foreach ($definitionComplexType['properties'] as $property) {
$element = $dom->createElement('xsd:element');
$element->setAttribute('name', $property->getName());
$element->setAttribute('type', $this->getContext()->getType($property->getValue()));
if ($property->isNillable()) {
$element->setAttribute('nillable', 'true');
}
$all->appendChild($element);
}
$complexType->appendChild($all);
$this->getContext()->getSchema()->appendChild($complexType);
$this->definition->addDefinitionComplexType($classname, $definitionComplexType);
}
}

View File

@ -1,60 +0,0 @@
<?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\ServiceDefinition;
class Type
{
private $phpType;
private $xmlType;
private $converter;
public function __construct($phpType = null, $xmlType = null, $converter = null)
{
$this->setPhpType($phpType);
$this->setXmlType($xmlType);
$this->setConverter($converter);
}
public function getPhpType()
{
return $this->phpType;
}
public function setPhpType($phpType)
{
$phpType = $phpType;
if ($phpType[0] == '\\') {
$phpType = substr($phpType, 1);
}
$this->phpType = $phpType;
}
public function getXmlType()
{
return $this->xmlType;
}
public function setXmlType($xmlType)
{
$this->xmlType = $xmlType;
}
public function getConverter()
{
return $this->converter;
}
public function setConverter($converter)
{
$this->converter = $converter;
}
}

View File

@ -0,0 +1,36 @@
<?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

@ -1,77 +0,0 @@
<?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

@ -11,10 +11,7 @@
namespace BeSimple\SoapBundle\Soap;
use BeSimple\SoapBundle\Util\Collection;
use Symfony\Component\HttpFoundation\Request;
use Zend\Mime\Mime;
use Zend\Mime\Message;
/**

View File

@ -16,66 +16,70 @@ use BeSimple\SoapBundle\ServiceBinding\RpcLiteralRequestMessageBinder;
use BeSimple\SoapBundle\ServiceDefinition as Definition;
use BeSimple\SoapBundle\Tests\fixtures\ServiceBinding as Fixtures;
use BeSimple\SoapBundle\Util\Collection;
use BeSimple\SoapCommon\Definition\Type\ComplexType;
use BeSimple\SoapCommon\Definition\Type\TypeRepository;
class RpcLiteralRequestMessageBinderTest extends \PHPUnit_Framework_TestCase
{
/**
* @dataProvider messageProvider
*/
public function testProcessMessage(Definition\Method $method, $message, $assert)
public function testProcessMessage(Definition\Method $method, array $message, array $assert)
{
$messageBinder = new RpcLiteralRequestMessageBinder();
$result = $messageBinder->processMessage($method, $message);
$result = $messageBinder->processMessage($method, $message, $this->getTypeRepository());
$this->assertSame($assert, $result);
}
public function testProcessMessageWithComplexType()
{
$typeRepository = $this->addComplexTypes($this->getTypeRepository());
$messageBinder = new RpcLiteralRequestMessageBinder();
$method = new Definition\Method('complextype_argument', null);
$method->addInput('foo', 'BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\Foo');
$foo = new Fixtures\Foo('foobar', 19395);
$result = $messageBinder->processMessage(
new Definition\Method('complextype_argument', null, array(), array(
new Definition\Argument('foo', new Definition\Type('BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\Foo')),
)),
$method,
array($foo),
$this->getDefinitionComplexTypes()
$typeRepository
);
$this->assertEquals(array('foo' => $foo), $result);
$foo1 = new Fixtures\Foo('foobar', 29291);
$foo2 = new Fixtures\Foo('barfoo', 39392);
$foos = new \stdClass();
$foos->item = array($foo1, $foo2);
$method = new Definition\Method('complextype_argument', null);
$method->addInput('foos', 'BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\Foo[]');
$result = $messageBinder->processMessage(
new Definition\Method('complextype_argument', null, array(), array(
new Definition\Argument('foos', new Definition\Type('BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\Foo[]')),
)),
$method,
array($foos),
$this->getDefinitionComplexTypes()
$typeRepository
);
$this->assertEquals(array('foos' => array($foo1, $foo2)), $result);
}
/**
* @expectedException SoapFault
*/
public function testProcessMessageSoapFault()
{
$messageBinder = new RpcLiteralRequestMessageBinder();
$method = new Definition\Method('complextype_argument', null);
$method->addInput('foo', 'BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\Foo');
$foo = new Fixtures\Foo('foo', null);
$result = $messageBinder->processMessage(
new Definition\Method('complextype_argument', null, array(), array(
new Definition\Argument('foo', new Definition\Type('BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\Foo')),
)),
$this->setExpectedException('SoapFault');
$messageBinder->processMessage(
$method,
array($foo),
$this->getDefinitionComplexTypes()
$this->addComplexTypes($this->getTypeRepository())
);
}
@ -83,16 +87,17 @@ class RpcLiteralRequestMessageBinderTest extends \PHPUnit_Framework_TestCase
{
$messageBinder = new RpcLiteralRequestMessageBinder();
$method = new Definition\Method('complextype_argument', null);
$method->addInput('foos', 'BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\Foo[]');
$foo = new Fixtures\Foo('foo', 2499104);
$foos = new \stdClass();
$foos->item = array($foo, $foo);
$result = $messageBinder->processMessage(
new Definition\Method('complextype_argument', null, array(), array(
new Definition\Argument('foos', new Definition\Type('BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\Foo[]')),
)),
$method,
array($foos),
$this->getDefinitionComplexTypes()
$this->addComplexTypes($this->getTypeRepository())
);
$this->assertEquals(array('foos' => array($foo, $foo)), $result);
@ -102,16 +107,17 @@ class RpcLiteralRequestMessageBinderTest extends \PHPUnit_Framework_TestCase
{
$messageBinder = new RpcLiteralRequestMessageBinder();
$method = new Definition\Method('complextype_argument', null);
$method->addInput('fooBar', 'BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\FooBar');
$foo = new Fixtures\Foo('foo', 38845);
$bar = new Fixtures\Bar('bar', null);
$fooBar = new Fixtures\FooBar($foo, $bar);
$result = $messageBinder->processMessage(
new Definition\Method('complextype_argument', null, array(), array(
new Definition\Argument('fooBar', new Definition\Type('BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\FooBar')),
)),
$method,
array($fooBar),
$this->getDefinitionComplexTypes()
$this->addComplexTypes($this->getTypeRepository())
);
$this->assertEquals(array('fooBar' => $fooBar), $result);
@ -121,17 +127,18 @@ class RpcLiteralRequestMessageBinderTest extends \PHPUnit_Framework_TestCase
{
$messageBinder = new RpcLiteralRequestMessageBinder();
$method = new Definition\Method('complextype_with_array', null);
$method->addInput('simple_arrays', 'BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\SimpleArrays');
$array = array(1, 2, 3, 4);
$stdClass = new \stdClass();
$stdClass->item = $array;
$simpleArrays = new Fixtures\SimpleArrays(null, new \stdClass(), $stdClass);
$result = $messageBinder->processMessage(
new Definition\Method('complextype_with_array', null, array(), array(
new Definition\Argument('simple_arrays', new Definition\Type('BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\SimpleArrays')),
)),
$method,
array($simpleArrays),
$this->getDefinitionComplexTypes()
$this->addComplexTypes($this->getTypeRepository())
);
$result = $result['simple_arrays'];
@ -144,12 +151,13 @@ class RpcLiteralRequestMessageBinderTest extends \PHPUnit_Framework_TestCase
{
$messageBinder = new RpcLiteralRequestMessageBinder();
$method = new Definition\Method('empty_array_complex_type', null);
$method->addInput('foo', 'BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\Foo[]');
$result = $messageBinder->processMessage(
new Definition\Method('empty_array_complex_type', null, array(), array(
new Definition\Argument('foo', new Definition\Type('BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\Foo[]')),
)),
$method,
array(new \stdClass()),
$this->getDefinitionComplexTypes()
$this->addComplexTypes($this->getTypeRepository())
);
$this->assertEquals(array('foo' => array()), $result);
@ -159,16 +167,17 @@ class RpcLiteralRequestMessageBinderTest extends \PHPUnit_Framework_TestCase
{
$messageBinder = new RpcLiteralRequestMessageBinder();
$method = new Definition\Method('prevent_infinite_recursion', null);
$method->addInput('foo_recursive', 'BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\FooRecursive');
$foo = new Fixtures\FooRecursive('foo', '');
$bar = new Fixtures\BarRecursive($foo, 10394);
$foo->bar = $bar;
$result = $messageBinder->processMessage(
new Definition\Method('prevent_infinite_recursion', null, array(), array(
new Definition\Argument('foo_recursive', new Definition\Type('BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\FooRecursive')),
)),
$method,
array($foo),
$this->getDefinitionComplexTypes()
$this->addComplexTypes($this->getTypeRepository())
);
$this->assertEquals(array('foo_recursive' => $foo), $result);
@ -179,43 +188,43 @@ class RpcLiteralRequestMessageBinderTest extends \PHPUnit_Framework_TestCase
$messages = array();
$messages[] = array(
new Definition\Method('no_argument'),
new Definition\Method('no_argument', null),
array(),
array(),
);
$method = new Definition\Method('string_argument', null);
$method->addInput('foo', 'string');
$messages[] = array(
new Definition\Method('string_argument', null, array(), array(
new Definition\Argument('foo', new Definition\Type('string')),
)),
$method,
array('bar'),
array('foo' => 'bar'),
);
$method = new Definition\Method('string_int_arguments', null);
$method->addInput('foo', 'string');
$method->addInput('bar', 'int');
$messages[] = array(
new Definition\Method('string_int_arguments', null, array(), array(
new Definition\Argument('foo', new Definition\Type('string')),
new Definition\Argument('bar', new Definition\Type('int')),
)),
$method,
array('test', 20),
array('foo' => 'test', 'bar' => 20),
);
$method = new Definition\Method('array_string_arguments', null);
$method->addInput('foo', 'string[]');
$method->addInput('bar', 'int');
$strings = new \stdClass();
$strings->item = array('foo', 'bar', 'barfoo');
$messages[] = array(
new Definition\Method('array_string_arguments', null, array(), array(
new Definition\Argument('foo', new Definition\Type('string[]')),
new Definition\Argument('bar', new Definition\Type('int')),
)),
$method,
array($strings, 4),
array('foo' => array('foo', 'bar', 'barfoo'), 'bar' => 4),
);
$method = new Definition\Method('empty_array', null);
$method->addInput('foo', 'string[]');
$messages[] = array(
new Definition\Method('empty_array', null, array(), array(
new Definition\Argument('foo', new Definition\Type('string[]')),
)),
$method,
array(new \stdClass()),
array('foo' => array()),
);
@ -223,40 +232,38 @@ class RpcLiteralRequestMessageBinderTest extends \PHPUnit_Framework_TestCase
return $messages;
}
private function getDefinitionComplexTypes()
private function addComplexTypes(TypeRepository $typeRepository)
{
$definitionComplexTypes = array();
$foo = new ComplexType('BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\Foo', 'Foo');
$foo->add('foo', 'string');
$foo->add('bar', 'int');
$typeRepository->addComplexType($foo);
$definitionComplexTypes['BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\Foo'] = $this->createComplexTypeCollection(array(
array('foo', 'string'),
array('bar', 'int'),
));
$bar = new ComplexType('BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\Bar', 'Bar');
$bar->add('foo', 'string');
$bar->add('bar', 'int', true);
$typeRepository->addComplexType($bar);
$definitionComplexTypes['BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\Bar'] = $this->createComplexTypeCollection(array(
array('foo', 'string'),
array('bar', 'int', true),
));
$fooBar = new ComplexType('BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\FooBar', 'FooBar');
$fooBar->add('foo', 'BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\Foo');
$fooBar->add('bar', 'BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\Bar');
$typeRepository->addComplexType($fooBar);
$definitionComplexTypes['BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\FooBar'] = $this->createComplexTypeCollection(array(
array('foo', 'BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\Foo'),
array('bar', 'BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\Bar'),
));
$simpleArrays = new ComplexType('BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\SimpleArrays', 'SimpleArrays');
$simpleArrays->add('array1', 'string[]', true);
$simpleArrays->add('array2', 'string[]');
$simpleArrays->add('array3', 'string[]');
$typeRepository->addComplexType($simpleArrays);
$definitionComplexTypes['BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\SimpleArrays'] = $this->createComplexTypeCollection(array(
array('array1', 'string[]', true),
array('array2', 'string[]'),
array('array3', 'string[]'),
));
$fooRecursive = new ComplexType('BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\FooRecursive', 'FooRecursive');
$fooRecursive->add('bar', 'BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\BarRecursive');
$typeRepository->addComplexType($fooRecursive);
$definitionComplexTypes['BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\FooRecursive'] = $this->createComplexTypeCollection(array(
array('bar', 'BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\BarRecursive'),
));
$barRecursive = new ComplexType('BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\BarRecursive', 'BarRecursive');
$barRecursive->add('foo', 'BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\FooRecursive');
$typeRepository->addComplexType($barRecursive);
$definitionComplexTypes['BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\BarRecursive'] = $this->createComplexTypeCollection(array(
array('foo', 'BeSimple\SoapBundle\Tests\fixtures\ServiceBinding\FooRecursive'),
));
return $definitionComplexTypes;
return $typeRepository;
}
private function createComplexTypeCollection(array $properties)
@ -277,4 +284,18 @@ class RpcLiteralRequestMessageBinderTest extends \PHPUnit_Framework_TestCase
return array('properties' => $collection);
}
private function getTypeRepository()
{
$typeRepository = new TypeRepository();
$typeRepository->addXmlNamespace('xsd', 'http://www.w3.org/2001/XMLSchema');
$typeRepository->addType('string', 'xsd:string');
$typeRepository->addType('boolean', 'xsd:boolean');
$typeRepository->addType('int', 'xsd:int');
$typeRepository->addType('float', 'xsd:float');
$typeRepository->addType('date', 'xsd:date');
$typeRepository->addType('dateTime', 'xsd:dateTime');
return $typeRepository;
}
}

View File

@ -23,6 +23,8 @@ class SoapRequestTest extends \PHPUnit_Framework_TestCase
{
public function testMtomMessage()
{
$this->markTestSkipped('Skip because I\'m not sure that SoapRequest is used in a HTTP Request process.');
$content = $this->loadRequestContentFixture('mtom/simple.txt');
$request = new SoapRequest(array(), array(), array(), array(), array(), array(), $content);

View File

@ -3,6 +3,7 @@
* 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.
@ -10,15 +11,12 @@
namespace BeSimple\SoapBundle;
use BeSimple\SoapBundle\Converter\TypeRepository;
use BeSimple\SoapBundle\ServiceBinding\MessageBinderInterface;
use BeSimple\SoapBundle\ServiceBinding\ServiceBinder;
use BeSimple\SoapBundle\ServiceDefinition\Dumper\DumperInterface;
use BeSimple\SoapCommon\Classmap;
use BeSimple\SoapCommon\Converter\TypeConverterCollection;
use BeSimple\SoapCommon\SoapOptionsBuilder;
use BeSimple\SoapServer\SoapServerOptionsBuilder;
use BeSimple\SoapWsdl\Dumper\Dumper;
use BeSimple\SoapServer\SoapServerBuilder;
use Symfony\Component\Config\ConfigCache;
use Symfony\Component\Config\Loader\LoaderInterface;
@ -26,43 +24,29 @@ use Symfony\Component\Config\Loader\LoaderInterface;
* WebServiceContext.
*
* @author Christian Kerl <christian-kerl@web.de>
* @author Francis Besset <francis.besset@gmail.com>
*/
class WebServiceContext
{
private $classmap;
private $typeRepository;
private $converterRepository;
private $wsdlFileDumper;
private $options;
private $serviceDefinition;
private $serviceBinder;
private $serverBuilder;
public function __construct(LoaderInterface $loader, DumperInterface $dumper, Classmap $classmap, TypeRepository $typeRepository, TypeConverterCollection $converters, array $options)
public function __construct(LoaderInterface $loader, TypeConverterCollection $converters, array $options)
{
$this->loader = $loader;
$this->wsdlFileDumper = $dumper;
$this->classmap = $classmap;
$this->typeRepository = $typeRepository;
$this->converters = $converters;
// Issue #6: keep the debug because the cache is invalid
$options['debug'] = true;
$this->options = $options;
$this->loader = $loader;
$this->converters = $converters;
$this->options = $options;
}
public function getServiceDefinition()
{
if (null === $this->serviceDefinition) {
$cacheDefinition = new ConfigCache(sprintf('%s/%s.definition.php', $this->options['cache_dir'], $this->options['name']), $this->options['debug']);
if ($cacheDefinition->isFresh()) {
$this->serviceDefinition = include (string) $cacheDefinition;
$cache = new ConfigCache(sprintf('%s/%s.definition.php', $this->options['cache_dir'], $this->options['name']), $this->options['debug']);
if ($cache->isFresh()) {
$this->serviceDefinition = include $cache->getPath();
} else {
if (!$this->loader->supports($this->options['resource'], $this->options['resource_type'])) {
throw new \LogicException(sprintf('Cannot load "%s" (%s)', $this->options['resource'], $this->options['resource_type']));
@ -72,10 +56,7 @@ class WebServiceContext
$this->serviceDefinition->setName($this->options['name']);
$this->serviceDefinition->setNamespace($this->options['namespace']);
$this->serviceDefinition->setClassmap($this->classmap);
$this->classmap = null;
$this->typeRepository->fixTypeInformation($this->serviceDefinition);
$cache->write('<?php return unserialize('.var_export(serialize($this->serviceDefinition), true).');');
}
}
@ -89,19 +70,21 @@ class WebServiceContext
public function getWsdlFile($endpoint = null)
{
$file = sprintf('%s/%s.%s.wsdl', $this->options['cache_dir'], $this->options['name'], md5($endpoint));
$cacheWsdl = new ConfigCache($file, $this->options['debug']);
$file = sprintf ('%s/%s.%s.wsdl', $this->options['cache_dir'], $this->options['name'], md5($endpoint));
$cache = new ConfigCache($file, $this->options['debug']);
if(!$cacheWsdl->isFresh()) {
$serviceDefinition = $this->getServiceDefinition();
if(!$cache->isFresh()) {
$definition = $this->getServiceDefinition();
$cacheWsdl->write($this->wsdlFileDumper->dumpServiceDefinition($serviceDefinition, $endpoint));
if ($endpoint) {
$definition->setOption('location', $endpoint);
}
$cacheDefinition = new ConfigCache(sprintf('%s/%s.definition.php', $this->options['cache_dir'], $this->options['name']), $this->options['debug']);
$cacheDefinition->write('<?php return unserialize('.var_export(serialize($serviceDefinition), true).');');
$dumper = new Dumper($definition, array('stylesheet' => $this->options['wsdl_stylesheet']));
$cache->write($dumper->dump());
}
return (string) $cacheWsdl;
return $cache->getPath();
}
public function getServiceBinder()
@ -121,15 +104,14 @@ class WebServiceContext
public function getServerBuilder()
{
if (null === $this->serverBuilder) {
$this->serverBuilder = SoapServerBuilder::createWithDefaults()
->withWsdl($this->getWsdlFile())
->withClassmap($this->getServiceDefinition()->getClassmap())
->withTypeConverters($this->converters)
;
if (null !== $this->options['cache_type']) {
$this->serverBuilder->withWsdlCache($this->options['cache_type']);
}
$soapServerBuilder = new SoapServerBuilder();
$this->serverBuilder = $soapServerBuilder->build(
SoapServerOptionsBuilder::createWithDefaults(),
SoapOptionsBuilder::createWithClassMap(
$this->getWsdlFile(),
$this->getServiceDefinition()->getTypeRepository()->getClassmap()
)
);
}
return $this->serverBuilder;

View File

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

View File

@ -1,313 +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;
/**
* 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');
}
if (isset($options['connection_timeout'])) {
curl_setopt($this->ch, CURLOPT_CONNECTTIMEOUT, $options['connection_timeout']);
}
if (isset($options['proxy_host'])) {
$port = isset($options['proxy_port']) ? $options['proxy_port'] : 8080;
curl_setopt($this->ch, CURLOPT_PROXY, $options['proxy_host'] . ':' . $port);
}
if (isset($options['proxy_user'])) {
curl_setopt($this->ch, CURLOPT_PROXYUSERPWD, $options['proxy_user'] . ':' . $options['proxy_password']);
}
if (isset($options['login'])) {
curl_setopt($this->ch, CURLOPT_HTTPAUTH, 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']);
}
}
/**
* 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
*
* @return bool
*/
public function exec($location, $request = null, $requestHeaders = 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);
}
$this->response = $this->execManualRedirect($this->followLocationMaxRedirects);
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

@ -0,0 +1,237 @@
<?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 => false,
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);;
$responseBody = substr($executeSoapCallResponse, $headerSize);
$responseHeaders = substr($executeSoapCallResponse, 0, $headerSize);
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 (!is_integer($httpResponseCode) || $httpResponseCode >= 400 || $httpResponseCode === 0) {
return new CurlResponse(
$httpRequestHeadersAsString,
$httpResponseCode,
$httpResponseMessage,
$httpResponseContentType,
self::CURL_FAILED,
$responseHeaders,
$responseBody,
$curlErrorMessage
);
}
return new CurlResponse(
$httpRequestHeadersAsString,
$httpResponseCode,
$httpResponseMessage,
$httpResponseContentType,
self::CURL_SUCCESS,
$responseHeaders,
$responseBody
);
}
/**
* 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

@ -0,0 +1,126 @@
<?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 = 'PhpBeSimpleSoap';
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

@ -0,0 +1,79 @@
<?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 = 120;
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

@ -0,0 +1,90 @@
<?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,
$responseHeader,
$responseBody,
$curlErrorMessage = 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 getResponseHeader()
{
return $this->responseHeader;
}
public function getResponseBody()
{
return $this->responseBody;
}
}

View File

@ -0,0 +1,34 @@
<?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

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

View File

@ -0,0 +1,15 @@
<?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

@ -0,0 +1,64 @@
<?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,9 +16,10 @@ use BeSimple\SoapCommon\Helper;
use BeSimple\SoapCommon\Mime\MultiPart as MimeMultiPart;
use BeSimple\SoapCommon\Mime\Parser as MimeParser;
use BeSimple\SoapCommon\Mime\Part as MimePart;
use BeSimple\SoapCommon\Mime\Part;
use BeSimple\SoapCommon\SoapRequest;
use BeSimple\SoapCommon\SoapRequestFilter;
use BeSimple\SoapCommon\SoapResponse;
use BeSimple\SoapCommon\SoapResponse as CommonSoapResponse;
use BeSimple\SoapCommon\SoapResponseFilter;
/**
@ -28,111 +29,61 @@ use BeSimple\SoapCommon\SoapResponseFilter;
*/
class MimeFilter implements SoapRequestFilter, SoapResponseFilter
{
/**
* 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)
public function filterRequest(SoapRequest $request, $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();
// build mime message if we have attachments
if (count($attachmentsToSend) > 0) {
$multipart = new MimeMultiPart();
$multipart = new MimeMultiPart('Part_' . rand(10, 15) . '_' . uniqid() . '.' . uniqid());
$soapPart = new MimePart($request->getContent(), 'text/xml', 'utf-8', MimePart::ENCODING_EIGHT_BIT);
$soapVersion = $request->getVersion();
// change content type headers for MTOM with SOAP 1.1
if ($soapVersion == SOAP_1_1 && $this->attachmentType & Helper::ATTACHMENTS_TYPE_MTOM) {
if ($soapVersion === SOAP_1_1 && $attachmentType & Helper::ATTACHMENTS_TYPE_MTOM) {
$multipart->setHeader('Content-Type', 'type', 'application/xop+xml');
$multipart->setHeader('Content-Type', 'start-info', 'text/xml');
$soapPart->setHeader('Content-Type', 'application/xop+xml');
$soapPart->setHeader('Content-Type', 'type', 'text/xml');
}
// change content type headers for SOAP 1.2
elseif ($soapVersion == SOAP_1_2) {
} elseif ($soapVersion === SOAP_1_2) {
$multipart->setHeader('Content-Type', 'type', 'application/soap+xml');
$soapPart->setHeader('Content-Type', 'application/soap+xml');
}
$multipart->addPart($soapPart, true);
foreach ($attachmentsToSend as $cid => $attachment) {
$multipart->addPart($attachment, false);
}
$request->setContent($multipart->getMimeMessage());
// TODO
$headers = $multipart->getHeadersForHttp();
list($name, $contentType) = explode(': ', $headers[0]);
list(, $contentType) = explode(': ', $headers[0]);
$request->setContentType($contentType);
}
return $request;
}
/**
* Modify the given response XML.
*
* @param \BeSimple\SoapCommon\SoapResponse $response SOAP response
*
* @return void
*/
public function filterResponse(SoapResponse $response)
public function filterResponse(CommonSoapResponse $response, $attachmentType)
{
// array to store attachments
$attachmentsRecieved = array();
$multiPartMessage = MimeParser::parseMimeMessage(
$response->getContent(),
['Content-Type' => trim($response->getContentType())]
);
$soapPart = $multiPartMessage->getMainPart();
$attachments = $multiPartMessage->getAttachments();
// 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),
);
$multipart = MimeParser::parseMimeMessage($response->getContent(), $headers);
// get soap payload and update SoapResponse object
$soapPart = $multipart->getPart();
// 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
$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;
}
$response->setContent($soapPart->getContent());
$response->setContentType($soapPart->getHeader('Content-Type'));
if (count($attachments) > 0) {
$response->setAttachments($attachments);
}
// add attachments to response object
if (count($attachmentsRecieved) > 0) {
$response->setAttachments($attachmentsRecieved);
}
return $response;
}
private function sanitizePhpExceptionOnHrefs(Part $soapPart)
{
// 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
return preg_replace('/href=(?!#)/', 'myhref=', $soapPart->getContent());
}
}

View File

@ -0,0 +1,34 @@
# BeSimpleSoapClient
The BeSimpleSoapClient is a component that extends the native PHP SoapClient with further features like SwA, MTOM and WS-Security.
# Features (only subsets of the linked specs implemented)
* SwA: SOAP Messages with Attachments [Spec](http://www.w3.org/TR/SOAP-attachments)
* MTOM: SOAP Message Transmission Optimization Mechanism [Spec](http://www.w3.org/TR/soap12-mtom/)
* WS-Security [Spec1](http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0.pdf), [Spec2](http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0.pdf)
* WS-Adressing [Spec](http://www.w3.org/2002/ws/addr/)
# 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-client": "0.2.*@dev"
}
}
```
Now you are ready to install the library:
```sh
php /usr/local/bin/composer.phar install
```

View File

@ -12,9 +12,22 @@
namespace BeSimple\SoapClient;
use BeSimple\SoapCommon\Helper;
use BeSimple\SoapCommon\Converter\MtomTypeConverter;
use BeSimple\SoapCommon\Converter\SwaTypeConverter;
use BeSimple\SoapBundle\Soap\SoapAttachment;
use BeSimple\SoapBundle\Soap\SoapAttachmentList;
use BeSimple\SoapClient\Curl\Curl;
use BeSimple\SoapClient\Curl\CurlOptionsBuilder;
use BeSimple\SoapClient\Curl\CurlResponse;
use BeSimple\SoapClient\SoapOptions\SoapClientOptions;
use BeSimple\SoapCommon\Fault\SoapFaultEnum;
use BeSimple\SoapCommon\Fault\SoapFaultPrefixEnum;
use BeSimple\SoapCommon\Fault\SoapFaultSourceGetter;
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
@ -23,148 +36,121 @@ use BeSimple\SoapCommon\Converter\SwaTypeConverter;
* allows caching of all remote referenced items.
*
* @author Andreas Schamberger <mail@andreass.net>
* @author Petr Bechyně <mail@petrbechyne.com>
*/
class SoapClient extends \SoapClient
{
/**
* Soap version.
*
* @var int
*/
protected $soapVersion = SOAP_1_1;
/** @var SoapClientOptions */
protected $soapClientOptions;
/** @var SoapOptions */
protected $soapOptions;
/** @var Curl */
private $curl;
/** @var SoapAttachment[] */
private $soapAttachmentsOnRequestStorage;
/** @var SoapResponse */
private $soapResponseStorage;
/**
* Tracing enabled?
*
* @var boolean
*/
protected $tracingEnabled = false;
/**
* cURL instance.
*
* @var \BeSimple\SoapClient\Curl
*/
protected $curl = null;
/**
* 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())
public function __construct(SoapClientOptions $soapClientOptions, SoapOptions $soapOptions)
{
// tracing enabled: store last request/response header and body
if (isset($options['trace']) && $options['trace'] === true) {
$this->tracingEnabled = true;
$this->soapClientOptions = $soapClientOptions;
$this->soapOptions = $soapOptions;
$this->curl = new Curl(
CurlOptionsBuilder::buildForSoapClient($soapClientOptions)
);
try {
$wsdlPath = $this->loadWsdl(
$this->curl,
$soapOptions->getWsdlFile(),
$soapOptions->getWsdlCacheType(),
false
);
} catch (Exception $e) {
throw new SoapFault(
SoapFaultEnum::SOAP_FAULT_SOAP_CLIENT_ERROR,
'Unable to load WsdlPath ('.$soapOptions->getWsdlFile().') with message: '.$e->getMessage().' in file: '.$e->getFile().' (line: '.$e->getLine().')'
);
}
// store SOAP version
if (isset($options['soap_version'])) {
$this->soapVersion = $options['soap_version'];
}
$this->curl = new Curl($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);
@parent::__construct($wsdlPath, $soapClientOptions->toArray() + $soapOptions->toArray());
}
/**
* Avoid using __call directly, it's deprecated even in \SoapClient.
*
* @deprecated
*/
public function __call($function_name, $arguments)
{
throw new Exception(
'The __call method is deprecated. Use __soapCall/soapCall instead.'
);
}
/**
* Perform HTTP request with cURL.
*
* @param SoapRequest $soapRequest SoapRequest object
* Using __soapCall returns only response string, use soapCall instead.
*
* @param string $function_name
* @param array $arguments
* @param array|null $options
* @param null $input_headers
* @param array|null $output_headers
* @return string
*/
public function __soapCall($function_name, $arguments, $options = null, $input_headers = null, &$output_headers = null)
{
return $this->soapCall($function_name, $arguments, $options, $input_headers, $output_headers)->getResponseContent();
}
/**
* @param string $functionName
* @param array $arguments
* @param array|null $options
* @param SoapAttachment[] $soapAttachments
* @param null $inputHeaders
* @param array|null $outputHeaders
* @return SoapResponse
*/
private function __doHttpRequest(SoapRequest $soapRequest)
public function soapCall($functionName, array $arguments, array $soapAttachments = [], array $options = null, $inputHeaders = null, array &$outputHeaders = null)
{
// HTTP headers
$headers = array(
'Content-Type:' . $soapRequest->getContentType(),
'SOAPAction: "' . $soapRequest->getAction() . '"',
);
// execute HTTP request with cURL
$responseSuccessfull = $this->curl->exec(
$soapRequest->getLocation(),
$soapRequest->getContent(),
$headers
);
// 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()
);
$this->setSoapAttachmentsOnRequestToStorage($soapAttachments);
try {
return $soapResponse;
$soapResponseAsObject = parent::__soapCall($functionName, $arguments, $options, $inputHeaders, $outputHeaders);
$soapResponse = $this->getSoapResponseFromStorage();
$soapResponse->setResponseObject($soapResponseAsObject);
return $soapResponse;
} catch (SoapFault $soapFault) {
if (SoapFaultSourceGetter::isNativeSoapFault($soapFault)) {
$soapResponse = $this->getSoapResponseFromStorage();
if ($soapResponse instanceof SoapResponse) {
$soapFault = $this->throwSoapFaultByTracing(
SoapFaultPrefixEnum::PREFIX_PHP . '-' . $soapFault->getCode(),
$soapFault->getMessage(),
new SoapResponseTracingData(
'Content-Type: ' . $soapResponse->getRequest()->getContentType(),
$soapResponse->getRequest()->getContent(),
'Content-Type: ' . $soapResponse->getContentType(),
$soapResponse->getResponseContent()
)
);
} else {
$soapFault = new SoapFault(
SoapFaultPrefixEnum::PREFIX_PHP . '-unresolved',
'Got SoapFault message with no response: '.$soapFault->getMessage()
);
}
}
throw $soapFault;
}
}
/**
* Custom request method to be able to modify the SOAP messages.
* $oneWay parameter is not used at the moment.
* This is not performing any HTTP requests, but it is getting data from SoapClient that are needed for this Client
*
* @param string $request Request string
* @param string $location Location
@ -176,158 +162,299 @@ class SoapClient extends \SoapClient
*/
public function __doRequest($request, $location, $action, $version, $oneWay = 0)
{
// wrap request data in SoapRequest object
$soapRequest = SoapRequest::create($request, $location, $action, $version);
$soapResponse = $this->performSoapRequest(
$request,
$location,
$action,
$version,
$this->getSoapAttachmentsOnRequestFromStorage()
);
$this->setSoapResponseToStorage($soapResponse);
// do actual SOAP request
$soapResponse = $this->__doRequest2($soapRequest);
return $soapResponse->getResponseContent();
}
// return SOAP response to ext/soap
return $soapResponse->getContent();
/** @deprecated */
public function __getLastRequestHeaders()
{
$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.'
);
}
/**
* Runs the currently registered request filters on the request, performs
* the HTTP request and runs the response filters.
* Custom request method to be able to modify the SOAP messages.
* $oneWay parameter is not used at the moment.
*
* @param SoapRequest $soapRequest SOAP request object
* @param mixed $request Request object
* @param string $location Location
* @param string $action SOAP action
* @param int $version SOAP version
* @param SoapAttachment[] $soapAttachments SOAP attachments array
*
* @return SoapResponse
*/
protected function __doRequest2(SoapRequest $soapRequest)
private function performSoapRequest($request, $location, $action, $version, array $soapAttachments = [])
{
// run SoapKernel on SoapRequest
$this->soapKernel->filterRequest($soapRequest);
$soapRequest = $this->createSoapRequest($location, $action, $version, $request, $soapAttachments);
// perform HTTP request with cURL
$soapResponse = $this->__doHttpRequest($soapRequest);
// run SoapKernel on SoapResponse
$this->soapKernel->filterResponse($soapResponse);
return $soapResponse;
return $this->performHttpSoapRequest($soapRequest);
}
/**
* Get last request HTTP headers.
* @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 string
* @return SoapRequest
*/
public function __getLastRequestHeaders()
private function createSoapRequest($location, $action, $version, $request, array $soapAttachments = [])
{
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);
$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())
);
}
// configure typemap
if (!isset($options['typemap'])) {
$options['typemap'] = array();
}
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() . '"',
'Connection: ' . ($this->soapOptions->isConnectionKeepAlive() ? 'Keep-Alive' : 'close'),
];
} else {
$headers = [
'Content-Type: ' . $soapRequest->getContentType() . '; action="' . $soapRequest->getAction() . '"',
'Connection: ' . ($this->soapOptions->isConnectionKeepAlive() ? 'Keep-Alive' : 'close'),
];
}
$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(
$soapRequest,
$curlResponse,
$soapResponseTracingData
);
if ($this->soapOptions->hasAttachments()) {
return SoapKernel::filterResponse(
$soapResponse,
$this->getAttachmentFilters(),
$this->soapOptions->getAttachmentType()
);
} else {
return $soapResponse;
}
$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);
},
} else if ($curlResponse->curlStatusFailed()) {
return $this->throwSoapFaultByTracing(
SoapFaultPrefixEnum::PREFIX_DEFAULT.'-'.SoapFaultEnum::SOAP_FAULT_HTTP.'-'.$curlResponse->getHttpResponseStatusCode(),
$curlResponse->getCurlErrorMessage(),
$soapResponseTracingData
);
} else {
return $this->throwSoapFaultByTracing(
SoapFaultPrefixEnum::PREFIX_DEFAULT.'-'.SoapFaultEnum::SOAP_FAULT_SOAP_CLIENT_ERROR,
'Cannot process curl response with unresolved status: ' . $curlResponse->getCurlStatus(),
$soapResponseTracingData
);
}
}
/**
* Downloads WSDL files with cURL. Uses all SoapClient options for
* authentication. Uses the WSDL_CACHE_* constants and the 'soap.wsdl_*'
* ini settings. Does only file caching as SoapClient only supports a file
* name parameter.
*
* @param string $wsdl WSDL file
* @param array(string=>mixed) $options Options array
* @param Curl $curl
* @param string $wsdlPath
* @param int $wsdlCacheType
* @param bool $resolveRemoteIncludes
*
* @return string
*/
private function loadWsdl($wsdl, array $options)
private function loadWsdl(Curl $curl, $wsdlPath, $wsdlCacheType, $resolveRemoteIncludes = true)
{
// option to resolve wsdl/xsd includes
$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);
$wsdlDownloader = new WsdlDownloader();
try {
$cacheFileName = $wsdlDownloader->download($wsdl);
} catch (\RuntimeException $e) {
throw new \SoapFault('WSDL', "SOAP-ERROR: Parsing WSDL: Couldn't load from '" . $wsdl . "' : failed to load external entity \"" . $wsdl . "\"");
$loadedWsdlFilePath = $wsdlDownloader->getWsdlPath($curl, $wsdlPath, $wsdlCacheType, $resolveRemoteIncludes);
} catch (Exception $e) {
throw new SoapFault(
SoapFaultEnum::SOAP_FAULT_WSDL,
'Unable to load WsdlPath ('.$wsdlPath.') with message: '.$e->getMessage().' in file: '.$e->getFile().' (line: '.$e->getLine().')'
);
}
return $cacheFileName;
return $loadedWsdlFilePath;
}
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 returnSoapResponseByTracing(
SoapRequest $soapRequest,
CurlResponse $curlResponse,
SoapResponseTracingData $soapResponseTracingData,
array $soapAttachments = []
) {
if ($this->soapClientOptions->getTrace() === true) {
return SoapResponseFactory::createWithTracingData(
$soapRequest,
$curlResponse->getResponseBody(),
$curlResponse->getHttpResponseContentType(),
$soapResponseTracingData,
$soapAttachments
);
} else {
return SoapResponseFactory::create(
$curlResponse->getResponseBody(),
$soapRequest->getLocation(),
$soapRequest->getAction(),
$soapRequest->getVersion(),
$curlResponse->getHttpResponseContentType(),
$soapAttachments
);
}
}
/**
* @param string $soapFaultCode
* @param string $soapFaultMessage
* @param SoapResponseTracingData $soapResponseTracingData
* @throws SoapFault
*/
private function throwSoapFaultByTracing($soapFaultCode, $soapFaultMessage, SoapResponseTracingData $soapResponseTracingData)
{
if ($this->soapClientOptions->getTrace() === 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');
}
}
private function setSoapResponseToStorage(SoapResponse $soapResponseStorage)
{
$this->soapResponseStorage = $soapResponseStorage;
}
/**
* @param SoapAttachment[] $soapAttachments
*/
private function setSoapAttachmentsOnRequestToStorage(array $soapAttachments)
{
$this->soapAttachmentsOnRequestStorage = $soapAttachments;
}
private function getSoapAttachmentsOnRequestFromStorage()
{
$soapAttachmentsOnRequest = $this->soapAttachmentsOnRequestStorage;
$this->soapAttachmentsOnRequestStorage = null;
return $soapAttachmentsOnRequest;
}
private function getSoapResponseFromStorage()
{
$soapResponse = $this->soapResponseStorage;
$this->soapResponseStorage = null;
return $soapResponse;
}
}

View File

@ -12,228 +12,44 @@
namespace BeSimple\SoapClient;
use BeSimple\SoapCommon\AbstractSoapBuilder;
use BeSimple\SoapCommon\Helper;
use BeSimple\SoapBundle\Cache;
use BeSimple\SoapClient\SoapOptions\SoapClientOptions;
use BeSimple\SoapCommon\SoapOptions\SoapOptions;
use Exception;
use SoapHeader;
/**
* Fluent interface builder for SoapClient instance.
* 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 SoapClientBuilder extends AbstractSoapBuilder
class SoapClientBuilder
{
/**
* Authentication options.
*
* @var array(string=>mixed)
*/
protected $soapOptionAuthentication = array();
/**
* Create new instance with default options.
*
* @return \BeSimple\SoapClient\SoapClientBuilder
*/
public static function createWithDefaults()
public function build(SoapClientOptions $soapClientOptions, SoapOptions $soapOptions)
{
return parent::createWithDefaults()
->withUserAgent('BeSimpleSoap');
}
$cache = new Cache($soapOptions);
$cache->validateSettings($soapOptions);
/**
* Finally returns a SoapClient instance.
*
* @return \BeSimple\SoapClient\SoapClient
*/
public function build()
{
$this->validateOptions();
return new SoapClient($this->wsdl, $this->getSoapOptions());
}
/**
* 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 new SoapClient(
$soapClientOptions,
$soapOptions
);
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;
public function buildWithSoapHeader(
SoapClientOptions $soapClientOptions,
SoapOptions $soapOptions,
SoapHeader $soapHeader
) {
$soapClient = $this->build($soapClientOptions, $soapOptions);
if ($soapClient->__setSoapHeaders($soapHeader) === false) {
throw new Exception(
'Could not set SoapHeader: '.var_export($soapHeader, true)
);
}
return $this;
}
/**
* Configure proxy.
*
* @param string $host Host
* @param int $port Port
* @param string $username Username
* @param string $password Password
*
* @return \BeSimple\SoapClient\SoapClientBuilder
*/
public function withProxy($host, $port, $username = null, $password = null)
{
$this->soapOptions['proxy_host'] = $host;
$this->soapOptions['proxy_port'] = $port;
if ($username) {
$this->soapOptions['proxy_login'] = $username;
$this->soapOptions['proxy_password'] = $password;
}
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();
return $soapClient;
}
}

View File

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

View File

@ -0,0 +1,84 @@
<?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 createWithEndpointLocation($endpointLocation)
{
return new SoapClientOptions(
SoapClientOptions::SOAP_CLIENT_TRACE_ON,
SoapClientOptions::SOAP_CLIENT_EXCEPTIONS_ON,
CurlOptions::DEFAULT_USER_AGENT,
SoapClientOptions::SOAP_CLIENT_COMPRESSION_NONE,
SoapClientOptions::SOAP_CLIENT_AUTHENTICATION_NONE,
SoapClientOptions::SOAP_CLIENT_PROXY_NONE,
$endpointLocation
);
}
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
);
}
public static function createWithAuthenticationAndEndpointLocation($endpointLocation, 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,
SoapClientOptions::SOAP_CLIENT_PROXY_NONE,
$endpointLocation
);
}
}

View File

@ -0,0 +1,21 @@
<?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

@ -1,47 +0,0 @@
<?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

@ -0,0 +1,145 @@
<?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;
const SOAP_CLIENT_AUTHENTICATION_NONE = null;
const SOAP_CLIENT_PROXY_NONE = null;
private $trace;
private $exceptions;
private $userAgent;
private $compression;
private $authentication;
private $proxy;
private $location;
/**
* @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|null $compression = SoapClientOptions::SOAP_CLIENT_COMPRESSION_NONE|SoapClientOptions::SOAP_CLIENT_COMPRESSION_GZIP|SoapClientOptions::SOAP_CLIENT_COMPRESSION_DEFLATE
* @param SoapServerAuthenticationInterface|null $authentication
* @param SoapServerProxy|null $proxy
* @param string|null $location
*/
public function __construct(
$trace,
$exceptions,
$userAgent,
$compression = null,
SoapServerAuthenticationInterface $authentication = null,
SoapServerProxy $proxy = null,
$location = null
) {
$this->trace = $trace;
$this->exceptions = $exceptions;
$this->userAgent = $userAgent;
$this->compression = $compression;
$this->authentication = $authentication;
$this->proxy = $proxy;
$this->location = $location;
}
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 hasLocation()
{
return $this->location !== null;
}
public function getAuthentication()
{
return $this->authentication;
}
public function getProxy()
{
return $this->proxy;
}
public function getLocation()
{
return $this->location;
}
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();
}
if ($this->hasLocation()) {
$optionsAsArray['location'] = $this->getLocation();
}
return $optionsAsArray;
}
}

View File

@ -1,48 +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\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,47 +1,56 @@
<?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;
use BeSimple\SoapCommon\SoapResponse as CommonSoapResponse;
use BeSimple\SoapCommon\SoapMessage;
/**
* SoapResponse class for SoapClient. Provides factory function for response object.
*
* @author Andreas Schamberger <mail@andreass.net>
*/
class SoapResponse extends CommonSoapResponse
{
/**
* 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)
{
$response = new SoapResponse();
$response->setContent($content);
$response->setLocation($location);
$response->setAction($action);
$response->setVersion($version);
$response->setContentType($contentType);
/** @var mixed */
protected $responseObject;
/** @var SoapResponseTracingData */
protected $tracingData;
/** @var SoapRequest */
protected $request;
return $response;
public function getResponseContent()
{
return $this->getContent();
}
public function getResponseObject()
{
return $this->responseObject;
}
public function setResponseObject($responseObject)
{
$this->responseObject = $responseObject;
}
public function hasTracingData()
{
return $this->tracingData !== null;
}
public function getTracingData()
{
return $this->tracingData;
}
public function setTracingData(SoapResponseTracingData $tracingData)
{
$this->tracingData = $tracingData;
}
public function setRequest(SoapRequest $request)
{
$this->request = $request;
}
public function getRequest()
{
return $this->request;
}
}

View File

@ -0,0 +1,96 @@
<?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;
use BeSimple\SoapCommon\SoapRequest;
/**
* 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(
PartFactory::createAttachmentParts($attachments)
);
}
return $response;
}
/**
* Factory method for SoapClient\SoapResponse with SoapResponseTracingData.
*
* @param SoapRequest $soapRequest related request object
* @param string $content Content
* @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(
SoapRequest $soapRequest,
$content,
$contentType,
SoapResponseTracingData $tracingData,
array $attachments = []
) {
$response = new SoapResponse();
$response->setRequest($soapRequest);
$response->setContent($content);
$response->setLocation($soapRequest->getLocation());
$response->setAction($soapRequest->getAction());
$response->setVersion($soapRequest->getVersion());
$response->setContentType($contentType);
if ($tracingData !== null) {
$response->setTracingData($tracingData);
}
if (count($attachments) > 0) {
$response->setAttachments(
PartFactory::createAttachmentParts($attachments)
);
}
return $response;
}
}

View File

@ -0,0 +1,39 @@
<?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

@ -0,0 +1,39 @@
<?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

@ -0,0 +1,52 @@
<?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

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

View File

@ -0,0 +1,84 @@
<?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

@ -1,56 +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\Tests;
use Symfony\Component\Process\PhpExecutableFinder;
use Symfony\Component\Process\ProcessBuilder;
/**
* @author francis.besset@gmail.com <francis.besset@gmail.com>
*/
abstract class AbstractWebServerTest extends \PHPUnit_Framework_TestCase
{
/**
* @var ProcessBuilder
*/
static protected $webserver;
static protected $websererPortLength;
public static function setUpBeforeClass()
{
if (version_compare(PHP_VERSION, '5.4.0', '<')) {
self::markTestSkipped('PHP Webserver is available from PHP 5.4');
}
$phpFinder = new PhpExecutableFinder();
self::$webserver = ProcessBuilder::create(array(
'exec', // used exec binary (https://github.com/symfony/symfony/issues/5759)
$phpFinder->find(),
'-S',
sprintf('localhost:%d', WEBSERVER_PORT),
'-t',
__DIR__.DIRECTORY_SEPARATOR.'Fixtures',
))->getProcess();
self::$webserver->start();
usleep(100000);
self::$websererPortLength = strlen(WEBSERVER_PORT);
}
public static function tearDownAfterClass()
{
self::$webserver->stop(0);
usleep(100000);
}
}

View File

@ -1,100 +0,0 @@
<?php
use BeSimple\SoapCommon\Helper as BeSimpleSoapHelper;
use BeSimple\SoapClient\SoapClient as BeSimpleSoapClient;
require '../bootstrap.php';
class base64Binary
{
public $_;
public $contentType;
}
class AttachmentType
{
public $fileName;
public $binaryData;
}
class AttachmentRequest extends AttachmentType
{
}
class base64Binary
{
public $_;
public $contentType;
}
class AttachmentType
{
public $fileName;
public $binaryData;
}
class AttachmentRequest extends AttachmentType
{
}
class base64Binary
{
public $_;
public $contentType;
}
class AttachmentType
{
public $fileName;
public $binaryData;
}
class AttachmentRequest extends AttachmentType
{
}
$options = array(
'soap_version' => SOAP_1_1,
'features' => SOAP_SINGLE_ELEMENT_ARRAYS, // make sure that result is array for size=1
'trace' => true, // enables use of the methods SoapClient->__getLastRequest, SoapClient->__getLastRequestHeaders, SoapClient->__getLastResponse and SoapClient->__getLastResponseHeaders
'attachment_type' => BeSimpleSoapHelper::ATTACHMENTS_TYPE_MTOM,
'cache_wsdl' => WSDL_CACHE_NONE,
'classmap' => array(
'base64Binary' => 'base64Binary',
'AttachmentRequest' => 'AttachmentRequest',
),
);
/*
* Deploy "axis_services/sample-mtom.aar" to Apache Axis2 to get this
* example to work.
*
* Apache Axis2 MTOM example.
*
*/
$sc = new BeSimpleSoapClient('MTOM.wsdl', $options);
//var_dump($sc->__getFunctions());
//var_dump($sc->__getTypes());
try {
$b64 = new base64Binary();
$b64->_ = 'This is a test. :)';
$b64->contentType = 'text/plain';
$attachment = new AttachmentRequest();
$attachment->fileName = 'test123.txt';
$attachment->binaryData = $b64;
var_dump($sc->attachment($attachment));
} catch (Exception $e) {
var_dump($e);
}
// var_dump(
// $sc->__getLastRequestHeaders(),
// $sc->__getLastRequest(),
// $sc->__getLastResponseHeaders(),
// $sc->__getLastResponse()
// );

View File

@ -1,89 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions targetNamespace="http://ws.apache.org/axis2/mtomsample/" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://ws.apache.org/axis2/mtomsample/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/">
<types>
<xsd:schema attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://ws.apache.org/axis2/mtomsample/" xmlns="http://schemas.xmlsoap.org/wsdl/">
<xsd:import namespace="http://www.w3.org/2005/05/xmlmime"/>
<xsd:complexType name="AttachmentType">
<xsd:sequence>
<xsd:element minOccurs="0" name="fileName" type="xsd:string"/>
<xsd:element minOccurs="0" name="binaryData" type="xmime:base64Binary"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="AttachmentRequest" type="tns:AttachmentType"/>
<xsd:element name="AttachmentResponse" type="xsd:string"/>
</xsd:schema>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xmime="http://www.w3.org/2005/05/xmlmime" attributeFormDefault="unqualified" elementFormDefault="unqualified" targetNamespace="http://www.w3.org/2005/05/xmlmime">
<xs:attribute name="contentType">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="3"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="expectedContentTypes" type="xs:string"/>
<xs:complexType name="base64Binary">
<xs:simpleContent>
<xs:extension base="xs:base64Binary">
<xs:attribute ref="xmime:contentType"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="hexBinary">
<xs:simpleContent>
<xs:extension base="xs:hexBinary">
<xs:attribute ref="xmime:contentType"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>
</types>
<message name="AttachmentResponse">
<part name="part1" element="tns:AttachmentResponse">
</part>
</message>
<message name="AttachmentRequest">
<part name="part1" element="tns:AttachmentRequest">
</part>
</message>
<portType name="MTOMServicePortType">
<operation name="attachment">
<input message="tns:AttachmentRequest" wsaw:Action="attachment">
</input>
<output message="tns:AttachmentResponse" wsaw:Action="http://schemas.xmlsoap.org/wsdl/MTOMServicePortType/AttachmentResponse">
</output>
</operation>
</portType>
<binding name="MTOMServiceSOAP11Binding" type="tns:MTOMServicePortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="attachment">
<soap:operation soapAction="attachment" style="document"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<binding name="MTOMServiceSOAP12Binding" type="tns:MTOMServicePortType">
<soap12:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="attachment">
<soap12:operation soapAction="attachment" style="document"/>
<input>
<soap12:body use="literal"/>
</input>
<output>
<soap12:body use="literal"/>
</output>
</operation>
</binding>
<service name="MTOMSample">
<port name="MTOMSampleSOAP12port_http" binding="tns:MTOMServiceSOAP12Binding">
<soap12:address location="http://localhost:8080/axis2/services/MTOMSample.MTOMSampleSOAP12port_http/"/>
</port>
<port name="MTOMSampleSOAP11port_http" binding="tns:MTOMServiceSOAP11Binding">
<soap:address location="http://localhost:8080/axis2/services/MTOMSample.MTOMSampleSOAP11port_http/"/>
</port>
</service>
</definitions>

View File

@ -1,84 +0,0 @@
<?php
use BeSimple\SoapCommon\Helper as BeSimpleSoapHelper;
use BeSimple\SoapClient\SoapClient as BeSimpleSoapClient;
require '../bootstrap.php';
$options = array(
'soap_version' => SOAP_1_1,
'features' => SOAP_SINGLE_ELEMENT_ARRAYS, // make sure that result is array for size=1
'trace' => true, // enables use of the methods SoapClient->__getLastRequest, SoapClient->__getLastRequestHeaders, SoapClient->__getLastResponse and SoapClient->__getLastResponseHeaders
'attachment_type' => BeSimpleSoapHelper::ATTACHMENTS_TYPE_SWA,
'cache_wsdl' => WSDL_CACHE_NONE,
);
/*
* Deploy "axis_services/besimple-swa.aar" to Apache Axis2 to get this
* example to work.
*
* Run ant to rebuild aar.
*
* Example based on:
* http://axis.apache.org/axis2/java/core/docs/mtom-guide.html#a3
* http://wso2.org/library/1675
*
* Doesn't work directly with ?wsdl served by Apache Axis!
*
*/
$sc = new BeSimpleSoapClient('SwA.wsdl', $options);
//var_dump($sc->__getFunctions());
//var_dump($sc->__getTypes());
try {
$file = new stdClass();
$file->name = 'upload.txt';
$file->data = 'This is a test text!';
$result = $sc->uploadFile($file);
var_dump(
$result->return
);
$file = new stdClass();
$file->name = 'upload.txt';
$result = $sc->downloadFile($file);
var_dump(
$result->data
);
$file = new stdClass();
$file->name = 'image.jpg'; // source: http://www.freeimageslive.com/galleries/light/pics/swirl3768.jpg
$file->data = file_get_contents('image.jpg');
$result = $sc->uploadFile($file);
var_dump(
$result->return
);
$crc32 = crc32($file->data);
$file = new stdClass();
$file->name = 'image.jpg';
$result = $sc->downloadFile($file);
file_put_contents('image2.jpg', $result->data);
var_dump(
crc32($result->data) === $crc32
);
} catch (Exception $e) {
var_dump($e);
}
// var_dump(
// $sc->__getLastRequestHeaders(),
// $sc->__getLastRequest(),
// $sc->__getLastResponseHeaders(),
// $sc->__getLastResponse()
// );

View File

@ -1,162 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:ns1="http://org.apache.axis2/xsd" xmlns:ns="http://service.besimple" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" targetNamespace="http://service.besimple">
<wsdl:documentation>BeSimpleSwaService</wsdl:documentation>
<wsdl:types>
<xs:schema attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://service.besimple">
<xs:complexType name="Exception">
<xs:sequence>
<xs:element minOccurs="0" name="Exception" nillable="true" type="xs:anyType"/>
</xs:sequence>
</xs:complexType>
<xs:element name="Exception">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="Exception" nillable="true" type="ns:Exception"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="uploadFile">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="data" nillable="true" type="xs:base64Binary"/>
<xs:element minOccurs="0" name="name" nillable="true" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="uploadFileResponse">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="return" nillable="true" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="downloadFile">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="name" nillable="true" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="downloadFileResponse">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="data" nillable="true" type="xs:base64Binary"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
</wsdl:types>
<wsdl:message name="downloadFileRequest">
<wsdl:part name="parameters" element="ns:downloadFile"/>
</wsdl:message>
<wsdl:message name="downloadFileResponse">
<wsdl:part name="parameters" element="ns:downloadFileResponse"/>
</wsdl:message>
<wsdl:message name="Exception">
<wsdl:part name="parameters" element="ns:Exception"/>
</wsdl:message>
<wsdl:message name="uploadFileRequest">
<wsdl:part name="parameters" element="ns:uploadFile"/>
</wsdl:message>
<wsdl:message name="uploadFileResponse">
<wsdl:part name="parameters" element="ns:uploadFileResponse"/>
</wsdl:message>
<wsdl:portType name="BeSimpleSwaServicePortType">
<wsdl:operation name="downloadFile">
<wsdl:input message="ns:downloadFileRequest" wsaw:Action="urn:downloadFile"/>
<wsdl:output message="ns:downloadFileResponse" wsaw:Action="urn:downloadFileResponse"/>
<wsdl:fault message="ns:Exception" name="Exception" wsaw:Action="urn:downloadFileException"/>
</wsdl:operation>
<wsdl:operation name="uploadFile">
<wsdl:input message="ns:uploadFileRequest" wsaw:Action="urn:uploadFile"/>
<wsdl:output message="ns:uploadFileResponse" wsaw:Action="urn:uploadFileResponse"/>
<wsdl:fault message="ns:Exception" name="Exception" wsaw:Action="urn:uploadFileException"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="BeSimpleSwaServiceSoap11Binding" type="ns:BeSimpleSwaServicePortType">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<wsdl:operation name="downloadFile">
<soap:operation soapAction="urn:downloadFile" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
<wsdl:fault name="Exception">
<soap:fault use="literal" name="Exception"/>
</wsdl:fault>
</wsdl:operation>
<wsdl:operation name="uploadFile">
<soap:operation soapAction="urn:uploadFile" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
<wsdl:fault name="Exception">
<soap:fault use="literal" name="Exception"/>
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>
<wsdl:binding name="BeSimpleSwaServiceSoap12Binding" type="ns:BeSimpleSwaServicePortType">
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<wsdl:operation name="downloadFile">
<soap12:operation soapAction="urn:downloadFile" style="document"/>
<wsdl:input>
<soap12:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap12:body use="literal"/>
</wsdl:output>
<wsdl:fault name="Exception">
<soap12:fault use="literal" name="Exception"/>
</wsdl:fault>
</wsdl:operation>
<wsdl:operation name="uploadFile">
<soap12:operation soapAction="urn:uploadFile" style="document"/>
<wsdl:input>
<soap12:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap12:body use="literal"/>
</wsdl:output>
<wsdl:fault name="Exception">
<soap12:fault use="literal" name="Exception"/>
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>
<wsdl:binding name="BeSimpleSwaServiceHttpBinding" type="ns:BeSimpleSwaServicePortType">
<http:binding verb="POST"/>
<wsdl:operation name="downloadFile">
<http:operation location="BeSimpleSwaService/downloadFile"/>
<wsdl:input>
<mime:content type="text/xml" part="downloadFile"/>
</wsdl:input>
<wsdl:output>
<mime:content type="text/xml" part="downloadFile"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="uploadFile">
<http:operation location="BeSimpleSwaService/uploadFile"/>
<wsdl:input>
<mime:content type="text/xml" part="uploadFile"/>
</wsdl:input>
<wsdl:output>
<mime:content type="text/xml" part="uploadFile"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="BeSimpleSwaService">
<wsdl:port name="BeSimpleSwaServiceHttpSoap11Endpoint" binding="ns:BeSimpleSwaServiceSoap11Binding">
<soap:address location="http://localhost:8080/axis2/services/BeSimpleSwaService.BeSimpleSwaServiceHttpSoap11Endpoint/"/>
</wsdl:port>
<wsdl:port name="BeSimpleSwaServiceHttpSoap12Endpoint" binding="ns:BeSimpleSwaServiceSoap12Binding">
<soap12:address location="http://localhost:8080/axis2/services/BeSimpleSwaService.BeSimpleSwaServiceHttpSoap12Endpoint/"/>
</wsdl:port>
<wsdl:port name="BeSimpleSwaServiceHttpEndpoint" binding="ns:BeSimpleSwaServiceHttpBinding">
<http:address location="http://localhost:8080/axis2/services/BeSimpleSwaService.BeSimpleSwaServiceHttpEndpoint/"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

View File

@ -1,38 +0,0 @@
<project name="BeSimpleSwaService" default="generate.service">
<property environment="env" />
<property name="axis2.home" value="C:/axis2" />
<property name="axis2.repo" value="${axis2.home}/repository" />
<property name="build.dir" value="build" />
<property name="filename" value="besimple-swa.aar" />
<path id="axis.classpath">
<fileset dir="${axis2.home}/lib">
<include name="*.jar" />
</fileset>
</path>
<target name="generate.service" depends="compile">
<jar destfile="${build.dir}/${filename}">
<fileset dir="resources/">
<include name="META-INF/services.xml" />
</fileset>
<fileset dir="${build.dir}/classes">
<include name="besimple/service/**/*.class" />
</fileset>
</jar>
<copy file="${build.dir}/${filename}" tofile="../axis_services/${filename}" overwrite="true" />
<copy file="${build.dir}/${filename}" tofile="${axis2.repo}/services/${filename}" overwrite="true" />
<antcall target="clean" />
</target>
<target name="compile">
<mkdir dir="${build.dir}/classes" />
<javac debug="on" srcdir="src" destdir="${build.dir}/classes">
<classpath refid="axis.classpath" />
</javac>
</target>
<target name="clean">
<delete dir="${build.dir}" />
</target>
</project>

View File

@ -1,15 +0,0 @@
<serviceGroup>
<service name="BeSimpleSwaService">
<description>BeSimple test service for SwA.</description>
<parameter name="enableSwA">true</parameter>
<parameter name="ServiceClass" locked="false">besimple.service.BeSimpleSwaService</parameter>
<operation name="uploadFile">
<actionMapping>urn:uploadFile</actionMapping>
<messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
</operation>
<operation name="downloadFile">
<actionMapping>urn:downloadFile</actionMapping>
<messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
</operation>
</service>
</serviceGroup>

View File

@ -1,78 +0,0 @@
package besimple.service;
import java.io.File;
import java.io.FileOutputStream;
import javax.xml.namespace.QName;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import org.apache.axiom.attachments.Attachments;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMAttribute;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.context.OperationContext;
import org.apache.axis2.wsdl.WSDLConstants;
public class BeSimpleSwaService {
String namespace = "http://service.besimple";
public OMElement uploadFile(OMElement element) throws Exception {
OMElement dataElement = (OMElement)element.getFirstChildWithName(new QName(namespace, "data"));
OMAttribute hrefAttribute = dataElement.getAttribute(new QName("href"));
String contentID = hrefAttribute.getAttributeValue();
contentID = contentID.trim();
if (contentID.substring(0, 3).equalsIgnoreCase("cid")) {
contentID = contentID.substring(4);
}
OMElement nameElement = (OMElement)element.getFirstChildWithName(new QName(namespace, "name"));
String name = nameElement.getText();
MessageContext msgCtx = MessageContext.getCurrentMessageContext();
Attachments attachment = msgCtx.getAttachmentMap();
DataHandler dataHandler = attachment.getDataHandler(contentID);
File file = new File(name);
FileOutputStream fileOutputStream = new FileOutputStream(file);
dataHandler.writeTo(fileOutputStream);
fileOutputStream.flush();
fileOutputStream.close();
OMFactory factory = OMAbstractFactory.getOMFactory();
OMNamespace omNs = factory.createOMNamespace(namespace, "swa");
OMElement wrapperElement = factory.createOMElement("uploadFileResponse", omNs);
OMElement returnElement = factory.createOMElement("return", omNs, wrapperElement);
returnElement.setText("File saved succesfully.");
return wrapperElement;
}
public OMElement downloadFile(OMElement element) throws Exception {
OMElement nameElement = (OMElement)element.getFirstChildWithName(new QName(namespace, "name"));
String name = nameElement.getText();
MessageContext msgCtxIn = MessageContext.getCurrentMessageContext();
OperationContext operationContext = msgCtxIn.getOperationContext();
MessageContext msgCtxOut = operationContext.getMessageContext(WSDLConstants.MESSAGE_LABEL_OUT_VALUE);
FileDataSource fileDataSource = new FileDataSource(name);
DataHandler dataHandler = new DataHandler(fileDataSource);
String contentID = "cid:" + msgCtxOut.addAttachment(dataHandler);
OMFactory factory = OMAbstractFactory.getOMFactory();
OMNamespace omNs = factory.createOMNamespace(namespace, "swa");
OMElement wrapperElement = factory.createOMElement("downloadFileResponse", omNs);
OMElement dataElement = factory.createOMElement("data", omNs, wrapperElement);
dataElement.addAttribute("href", contentID, null);
return wrapperElement;
}
}

View File

@ -1,73 +0,0 @@
<?php
use BeSimple\SoapClient\SoapClient as BeSimpleSoapClient;
use BeSimple\SoapClient\WsAddressingFilter as BeSimpleWsAddressingFilter;
require '../bootstrap.php';
$options = array(
'soap_version' => SOAP_1_2,
'features' => SOAP_SINGLE_ELEMENT_ARRAYS, // make sure that result is array for size=1
'trace' => true, // enables use of the methods SoapClient->__getLastRequest, SoapClient->__getLastRequestHeaders, SoapClient->__getLastResponse and SoapClient->__getLastResponseHeaders
);
/*
* Deploy "axis_services/version2.aar" to Apache Axis2 to get this example to
* work.
*
* To rebuild the "axis_services/version2.aar" the following steps need to be
* done to build a working Apache Axis2 version service with SOAP session
* enabled.
*
* 1) Go to $AXIS_HOME/samples/version and edit the following files:
*
* resources/META-INF/services.xml:
* <service name="Version2" scope="soapsession">
* ...
* </service>
*
* build.xml:
* replace version.aar with version2.aar
*
* 2) Run ant build.xml in "$AXIS_HOME/samples/version"
*
*/
$sc = new BeSimpleSoapClient('http://localhost:8080/axis2/services/Version2?wsdl', $options);
$soapKernel = $sc->getSoapKernel();
$wsaFilter = new BeSimpleWsAddressingFilter();
$soapKernel->registerFilter($wsaFilter);
//var_dump($sc->__getFunctions());
//var_dump($sc->__getTypes());
try {
$wsaFilter->setReplyTo(BeSimpleWsAddressingFilter::ENDPOINT_REFERENCE_ANONYMOUS);
$wsaFilter->setMessageId();
var_dump($sc->getVersion());
$soapSessionId1 = $wsaFilter->getReferenceParameter('http://ws.apache.org/namespaces/axis2', 'ServiceGroupId');
echo 'ID1: ' .$soapSessionId1 . PHP_EOL;
$wsaFilter->addReferenceParameter('http://ws.apache.org/namespaces/axis2', 'axis2', 'ServiceGroupId', $soapSessionId1);
var_dump($sc->getVersion());
$soapSessionId2 = $wsaFilter->getReferenceParameter('http://ws.apache.org/namespaces/axis2', 'ServiceGroupId');
echo 'ID2: ' . $soapSessionId2 . PHP_EOL;
if ($soapSessionId1 == $soapSessionId2) {
echo PHP_EOL;
echo 'SOAP session worked :)';
}
} catch (Exception $e) {
var_dump($e);
}
// var_dump(
// $sc->__getLastRequestHeaders(),
// $sc->__getLastRequest(),
// $sc->__getLastResponseHeaders(),
// $sc->__getLastResponse()
// );

View File

@ -1,116 +0,0 @@
<?php
use ass\XmlSecurity\Key as XmlSecurityKey;
use BeSimple\SoapClient\SoapClient as BeSimpleSoapClient;
use BeSimple\SoapClient\WsSecurityFilter as BeSimpleWsSecurityFilter;
use BeSimple\SoapCommon\WsSecurityKey as BeSimpleWsSecurityKey;
require '../bootstrap.php';
echo '<pre>';
$options = array(
'soap_version' => SOAP_1_2,
'features' => SOAP_SINGLE_ELEMENT_ARRAYS, // make sure that result is array for size=1
'trace' => true, // enables use of the methods SoapClient->__getLastRequest, SoapClient->__getLastRequestHeaders, SoapClient->__getLastResponse and SoapClient->__getLastResponseHeaders
);
/*
* Deploy "axis_services/library-signencr.aar" to Apache Axis2 to get this
* example to work.
*
* Links:
* http://www.dcc.uchile.cl/~pcamacho/tutorial/web/xmlsec/xmlsec.html
* http://www.aleksey.com/xmlsec/xmldsig-verifier.html
*
* Using code from axis example:
* http://www.ibm.com/developerworks/java/library/j-jws5/index.html
*
* Download key tool to export private key
* http://couchpotato.net/pkeytool/
*
* keytool -export -alias serverkey -keystore server.keystore -storepass nosecret -file servercert.cer
* openssl x509 -out servercert.pem -outform pem -in servercert.pem -inform der
*
* keytool -export -alias clientkey -keystore client.keystore -storepass nosecret -file clientcert.cer
* openssl x509 -out clientcert.pem -outform pem -in clientcert.pem -inform der
* java -jar pkeytool.jar -exportkey -keystore client.keystore -storepass nosecret -keypass clientpass -rfc -alias clientkey -file clientkey.pem
*
* C:\Program Files\Java\jre6\bin\keytool -export -alias serverkey -keystore server.keystore -storepass nosecret -file servercert.cer
* C:\xampp\apache\bin\openssl x509 -out servercert.pem -outform pem -in servercert.cer -inform der
*
* C:\Program Files\Java\jre6\bin\keytool -export -alias clientkey -keystore client.keystore -storepass nosecret -file clientcert.cer
* C:\xampp\apache\bin\openssl x509 -out clientcert.pem -outform pem -in clientcert.cer -inform der
* java -jar C:\axis2\pkeytool\pkeytool.jar -exportkey -keystore client.keystore -storepass nosecret -keypass clientpass -rfc -alias clientkey -file clientkey.pem
*
* build.properties:
* server-policy=hash-policy-server.xml
*
* allows both text and digest!
*/
class getBook {}
class getBookResponse {}
class getBooksByType {}
class getBooksByTypeResponse {}
class addBook {}
class addBookResponse {}
class BookInformation {}
$options['classmap'] = array(
'getBook' => 'getBook',
'getBookResponse' => 'getBookResponse',
'getBooksByType' => 'getBooksByType',
'getBooksByTypeResponse' => 'getBooksByTypeResponse',
'addBook' => 'addBook',
'addBookResponse' => 'addBookResponse',
'BookInformation' => 'BookInformation',
);
$sc = new BeSimpleSoapClient('WsSecuritySigEnc.wsdl', $options);
$wssFilter = new BeSimpleWsSecurityFilter();
// user key for signature and encryption
$securityKeyUser = new BeSimpleWsSecurityKey();
$securityKeyUser->addPrivateKey(XmlSecurityKey::RSA_SHA1, 'clientkey.pem', true);
$securityKeyUser->addPublicKey(XmlSecurityKey::RSA_SHA1, 'clientcert.pem', true);
$wssFilter->setUserSecurityKeyObject($securityKeyUser);
// service key for encryption
$securityKeyService = new BeSimpleWsSecurityKey();
$securityKeyService->addPrivateKey(XmlSecurityKey::TRIPLEDES_CBC);
$securityKeyService->addPublicKey(XmlSecurityKey::RSA_1_5, 'servercert.pem', true);
$wssFilter->setServiceSecurityKeyObject($securityKeyService);
// TOKEN_REFERENCE_SUBJECT_KEY_IDENTIFIER | TOKEN_REFERENCE_SECURITY_TOKEN | TOKEN_REFERENCE_THUMBPRINT_SHA1
$wssFilter->setSecurityOptionsSignature(BeSimpleWsSecurityFilter::TOKEN_REFERENCE_SECURITY_TOKEN);
$wssFilter->setSecurityOptionsEncryption(BeSimpleWsSecurityFilter::TOKEN_REFERENCE_THUMBPRINT_SHA1);
$soapKernel = $sc->getSoapKernel();
$soapKernel->registerFilter($wssFilter);
//var_dump($sc->__getFunctions());
//var_dump($sc->__getTypes());
try {
$gb = new getBook();
$gb->isbn = '0061020052';
var_dump($sc->getBook($gb));
$ab = new addBook();
$ab->isbn = '0445203498';
$ab->title = 'The Dragon Never Sleeps';
$ab->author = 'Cook, Glen';
$ab->type = 'scifi';
var_dump($sc->addBook($ab));
// getBooksByType("scifi");
} catch (Exception $e) {
var_dump($e);
}
//var_dump(
// $sc->__getLastRequestHeaders(),
// $sc->__getLastRequest(),
// $sc->__getLastResponseHeaders(),
// $sc->__getLastResponse()
//);

View File

@ -1,184 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://ws.sosnoski.com/library/wsdl"
xmlns:wns="http://ws.sosnoski.com/library/wsdl"
xmlns:tns="http://ws.sosnoski.com/library/types"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/">
<wsdl:types>
<schema elementFormDefault="qualified"
targetNamespace="http://ws.sosnoski.com/library/wsdl"
xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://ws.sosnoski.com/library/types"/>
<element name="getBook">
<complexType>
<sequence>
<element name="isbn" type="string"/>
</sequence>
</complexType>
</element>
<element name="getBookResponse">
<complexType>
<sequence>
<element name="getBookReturn" minOccurs="0" type="tns:BookInformation"/>
</sequence>
</complexType>
</element>
<element name="getBooksByType">
<complexType>
<sequence>
<element name="type" type="string"/>
</sequence>
</complexType>
</element>
<element name="getBooksByTypeResponse">
<complexType>
<sequence>
<element name="getBooksByTypeReturn" minOccurs="0" maxOccurs="unbounded" type="tns:BookInformation"/>
</sequence>
</complexType>
</element>
<element name="addBook">
<complexType>
<sequence>
<element name="type" type="string"/>
<element name="isbn" type="string"/>
<element name="author" minOccurs="0" maxOccurs="unbounded" type="string"/>
<element name="title" type="string"/>
</sequence>
</complexType>
</element>
<element name="addBookResponse">
<complexType>
<sequence>
<element name="addBookReturn" type="boolean"/>
</sequence>
</complexType>
</element>
</schema>
<schema elementFormDefault="qualified"
targetNamespace="http://ws.sosnoski.com/library/types"
xmlns="http://www.w3.org/2001/XMLSchema">
<complexType name="BookInformation">
<sequence>
<element name="author" minOccurs="0" maxOccurs="unbounded" type="string"/>
<element name="title" type="string"/>
</sequence>
<attribute name="type" use="required" type="string"/>
<attribute name="isbn" use="required" type="string"/>
</complexType>
</schema>
</wsdl:types>
<wsdl:message name="getBookRequest">
<wsdl:part element="wns:getBook" name="parameters"/>
</wsdl:message>
<wsdl:message name="getBookResponse">
<wsdl:part element="wns:getBookResponse" name="parameters"/>
</wsdl:message>
<wsdl:message name="getBooksByTypeRequest">
<wsdl:part element="wns:getBooksByType" name="parameters"/>
</wsdl:message>
<wsdl:message name="getBooksByTypeResponse">
<wsdl:part element="wns:getBooksByTypeResponse" name="parameters"/>
</wsdl:message>
<wsdl:message name="addBookRequest">
<wsdl:part element="wns:addBook" name="parameters"/>
</wsdl:message>
<wsdl:message name="addBookResponse">
<wsdl:part element="wns:addBookResponse" name="parameters"/>
</wsdl:message>
<wsdl:portType name="Library">
<wsdl:operation name="getBook">
<wsdl:input message="wns:getBookRequest" name="getBookRequest"/>
<wsdl:output message="wns:getBookResponse" name="getBookResponse"/>
</wsdl:operation>
<wsdl:operation name="getBooksByType">
<wsdl:input message="wns:getBooksByTypeRequest" name="getBooksByTypeRequest"/>
<wsdl:output message="wns:getBooksByTypeResponse" name="getBooksByTypeResponse"/>
</wsdl:operation>
<wsdl:operation name="addBook">
<wsdl:input message="wns:addBookRequest" name="addBookRequest"/>
<wsdl:output message="wns:addBookResponse" name="addBookResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="LibrarySoapBinding" type="wns:Library">
<wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getBook">
<wsdlsoap:operation soapAction="urn:getBook"/>
<wsdl:input name="getBookRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getBookResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="getBooksByType">
<wsdlsoap:operation soapAction="urn:getBooksByType"/>
<wsdl:input name="getBooksByTypeRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getBooksByTypeResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="addBook">
<wsdlsoap:operation soapAction="urn:addBook"/>
<wsdl:input name="addBookRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="addBookResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="library-signencr">
<wsdl:port binding="wns:LibrarySoapBinding" name="library">
<wsdlsoap:address location="http://localhost:8080/axis2/services/library-signencr"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

View File

@ -1,79 +0,0 @@
<?php
use BeSimple\SoapClient\SoapClient as BeSimpleSoapClient;
use BeSimple\SoapClient\WsSecurityFilter as BeSimpleWsSecurityFilter;
require '../bootstrap.php';
$options = array(
'soap_version' => SOAP_1_2,
'features' => SOAP_SINGLE_ELEMENT_ARRAYS, // make sure that result is array for size=1
'trace' => true, // enables use of the methods SoapClient->__getLastRequest, SoapClient->__getLastRequestHeaders, SoapClient->__getLastResponse and SoapClient->__getLastResponseHeaders
);
/*
* Deploy "axis_services/library-username-digest.aar" to Apache Axis2 to get
* this example to work.
*
* Using code from axis example:
* http://www.ibm.com/developerworks/java/library/j-jws4/index.html
*
* build.properties:
* server-policy=hash-policy-server.xml
*
* allows both text and digest!
*/
class getBook {}
class getBookResponse {}
class getBooksByType {}
class getBooksByTypeResponse {}
class addBook {}
class addBookResponse {}
class BookInformation {}
$options['classmap'] = array(
'getBook' => 'getBook',
'getBookResponse' => 'getBookResponse',
'getBooksByType' => 'getBooksByType',
'getBooksByTypeResponse' => 'getBooksByTypeResponse',
'addBook' => 'addBook',
'addBookResponse' => 'addBookResponse',
'BookInformation' => 'BookInformation',
);
$sc = new BeSimpleSoapClient('WsSecurityUserPass.wsdl', $options);
$wssFilter = new BeSimpleWsSecurityFilter(true, 600);
$wssFilter->addUserData('libuser', 'books', BeSimpleWsSecurityFilter::PASSWORD_TYPE_TEXT);
//$wssFilter->addUserData( 'libuser', 'books', BeSimpleWsSecurityFilter::PASSWORD_TYPE_DIGEST );
$soapKernel = $sc->getSoapKernel();
$soapKernel->registerFilter($wssFilter);
//var_dump($sc->__getFunctions());
//var_dump($sc->__getTypes());
try {
$gb = new getBook();
$gb->isbn = '0061020052';
var_dump($sc->getBook($gb));
$ab = new addBook();
$ab->isbn = '0445203498';
$ab->title = 'The Dragon Never Sleeps';
$ab->author = 'Cook, Glen';
$ab->type = 'scifi';
var_dump($sc->addBook($ab));
// getBooksByType("scifi");
} catch (Exception $e) {
var_dump($e);
}
//var_dump(
// $sc->__getLastRequestHeaders(),
// $sc->__getLastRequest(),
// $sc->__getLastResponseHeaders(),
// $sc->__getLastResponse()
//);

View File

@ -1,184 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://ws.sosnoski.com/library/wsdl"
xmlns:wns="http://ws.sosnoski.com/library/wsdl"
xmlns:tns="http://ws.sosnoski.com/library/types"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/">
<wsdl:types>
<schema elementFormDefault="qualified"
targetNamespace="http://ws.sosnoski.com/library/wsdl"
xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://ws.sosnoski.com/library/types"/>
<element name="getBook">
<complexType>
<sequence>
<element name="isbn" type="string"/>
</sequence>
</complexType>
</element>
<element name="getBookResponse">
<complexType>
<sequence>
<element name="getBookReturn" minOccurs="0" type="tns:BookInformation"/>
</sequence>
</complexType>
</element>
<element name="getBooksByType">
<complexType>
<sequence>
<element name="type" type="string"/>
</sequence>
</complexType>
</element>
<element name="getBooksByTypeResponse">
<complexType>
<sequence>
<element name="getBooksByTypeReturn" minOccurs="0" maxOccurs="unbounded" type="tns:BookInformation"/>
</sequence>
</complexType>
</element>
<element name="addBook">
<complexType>
<sequence>
<element name="type" type="string"/>
<element name="isbn" type="string"/>
<element name="author" minOccurs="0" maxOccurs="unbounded" type="string"/>
<element name="title" type="string"/>
</sequence>
</complexType>
</element>
<element name="addBookResponse">
<complexType>
<sequence>
<element name="addBookReturn" type="boolean"/>
</sequence>
</complexType>
</element>
</schema>
<schema elementFormDefault="qualified"
targetNamespace="http://ws.sosnoski.com/library/types"
xmlns="http://www.w3.org/2001/XMLSchema">
<complexType name="BookInformation">
<sequence>
<element name="author" minOccurs="0" maxOccurs="unbounded" type="string"/>
<element name="title" type="string"/>
</sequence>
<attribute name="type" use="required" type="string"/>
<attribute name="isbn" use="required" type="string"/>
</complexType>
</schema>
</wsdl:types>
<wsdl:message name="getBookRequest">
<wsdl:part element="wns:getBook" name="parameters"/>
</wsdl:message>
<wsdl:message name="getBookResponse">
<wsdl:part element="wns:getBookResponse" name="parameters"/>
</wsdl:message>
<wsdl:message name="getBooksByTypeRequest">
<wsdl:part element="wns:getBooksByType" name="parameters"/>
</wsdl:message>
<wsdl:message name="getBooksByTypeResponse">
<wsdl:part element="wns:getBooksByTypeResponse" name="parameters"/>
</wsdl:message>
<wsdl:message name="addBookRequest">
<wsdl:part element="wns:addBook" name="parameters"/>
</wsdl:message>
<wsdl:message name="addBookResponse">
<wsdl:part element="wns:addBookResponse" name="parameters"/>
</wsdl:message>
<wsdl:portType name="Library">
<wsdl:operation name="getBook">
<wsdl:input message="wns:getBookRequest" name="getBookRequest"/>
<wsdl:output message="wns:getBookResponse" name="getBookResponse"/>
</wsdl:operation>
<wsdl:operation name="getBooksByType">
<wsdl:input message="wns:getBooksByTypeRequest" name="getBooksByTypeRequest"/>
<wsdl:output message="wns:getBooksByTypeResponse" name="getBooksByTypeResponse"/>
</wsdl:operation>
<wsdl:operation name="addBook">
<wsdl:input message="wns:addBookRequest" name="addBookRequest"/>
<wsdl:output message="wns:addBookResponse" name="addBookResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="LibrarySoapBinding" type="wns:Library">
<wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getBook">
<wsdlsoap:operation soapAction="urn:getBook"/>
<wsdl:input name="getBookRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getBookResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="getBooksByType">
<wsdlsoap:operation soapAction="urn:getBooksByType"/>
<wsdl:input name="getBooksByTypeRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getBooksByTypeResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="addBook">
<wsdlsoap:operation soapAction="urn:addBook"/>
<wsdl:input name="addBookRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="addBookResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="library-username">
<wsdl:port binding="wns:LibrarySoapBinding" name="library">
<wsdlsoap:address location="http://localhost:8080/axis2/services/library-username"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

View File

@ -1,17 +0,0 @@
-----BEGIN CERTIFICATE-----
MIICoDCCAgkCBEnhw2IwDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNVBAYTAk5aMRMw
EQYDVQQIEwpXZWxsaW5ndG9uMRowGAYDVQQHExFQYXJhcGFyYXVtdSBCZWFjaDEq
MCgGA1UEChMhU29zbm9za2kgU29mdHdhcmUgQXNzb2NpYXRlcyBMdGQuMRAwDgYD
VQQLEwdVbmtub3duMRgwFgYDVQQDEw9EZW5uaXMgU29zbm9za2kwHhcNMDkwNDEy
MTAzMzA2WhcNMzYwODI3MTAzMzA2WjCBljELMAkGA1UEBhMCTloxEzARBgNVBAgT
CldlbGxpbmd0b24xGjAYBgNVBAcTEVBhcmFwYXJhdW11IEJlYWNoMSowKAYDVQQK
EyFTb3Nub3NraSBTb2Z0d2FyZSBBc3NvY2lhdGVzIEx0ZC4xEDAOBgNVBAsTB1Vu
a25vd24xGDAWBgNVBAMTD0Rlbm5pcyBTb3Nub3NraTCBnzANBgkqhkiG9w0BAQEF
AAOBjQAwgYkCgYEAhOVyNK8xyxtb4DnKtU6mF9KoiFqCk7eKoLE26+9h410CtTkx
zWAfgnR+8i+LPbdsPY+yXAo6NYpCCKolXfDLe+AG2GwnMZGrIl6+BLF3hqTmIXBF
TLGUmC7A7uBTivaWgdH1w3hb33rASoVU67BVtQ3QQi99juZX4vU9o9pScocCAwEA
ATANBgkqhkiG9w0BAQUFAAOBgQBMNPo1KAGbz8Jl6HGbtAcetieSJ3bEAXmv1tcj
ysBS67AXzdu1Ac+onHh2EpzBM7kuGbw+trU+AhulooPpewIQRApXP1F0KHRDcbqW
jwvknS6HnomN9572giLGKn2601bHiRUj35hiA8aLmMUBppIRPFFAoQ0QUBCPx+m8
/0n33w==
-----END CERTIFICATE-----

View File

@ -1,14 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAITlcjSvMcsbW+A5yrVOphfSqIha
gpO3iqCxNuvvYeNdArU5Mc1gH4J0fvIviz23bD2PslwKOjWKQgiqJV3wy3vgBthsJzGRqyJevgSx
d4ak5iFwRUyxlJguwO7gU4r2loHR9cN4W996wEqFVOuwVbUN0EIvfY7mV+L1PaPaUnKHAgMBAAEC
gYAZ6UqtLwN8YGc3fs0hMKZ9upsViuAuwPiMgED/G3twgzAF+ZLWQkmie+hMfCyf6eV200+pVm0n
Bz/8xH/oowxpX0Kk3szoB4vFghjU84GKUcrbhu/NRIm7l3drnfbzqhQkHDCx6n1CotI4Gs49cDWu
4uEAuxJkEIVY553unZjZgQJBAOJVIallNKmD0iQlvtWRmRzpmYDjt9vhNY6WBTIOx6SDn9SRaoSA
fkipQ2HXo04r78TQ674+zfZ1lRTkFG7px6ECQQCWUPHp3pSZOM1oGzJrNvNaw+MizZAZjq34npHm
9GRquFLG7BlCaI9QNGE7pN2ryYsYCRUMaM2e4GR0tUXxVGknAkAgrxqFU9AfCqI2Bh1gyf3KZxF7
w2axofwR8ygc6nV6FGfoUneHWubhp0/LuVAj4cRmL6Vbe8ZSaPh2Y9lviuMBAkEAicP8Q+1E4j1m
PPEYP51oYprANOiUFmhnWEL00+jPk+QFsd03tV6hYs/vAbwzkjuwqMHCMdJoCiH8z95IEUvc5wJA
MvLOuZdu4dmhOXg/YKsbMSPjFNEVskLQNSXqw6O2wIrpPg1NQvBBAOTbiuZj3vind4VPos1wc4vB
QocvdUC6dA==
-----END PRIVATE KEY-----

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