Skip to content
This repository has been archived by the owner on Jan 31, 2020. It is now read-only.

Commit

Permalink
Merge branch 'master' of git://github.com/zendframework/zf2
Browse files Browse the repository at this point in the history
  • Loading branch information
Show file tree
Hide file tree
Showing 5 changed files with 343 additions and 0 deletions.
9 changes: 9 additions & 0 deletions src/Exception/BadMethodCallException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace Zend\Soap\Exception;

class BadMethodCallException
extends \BadMethodCallException
implements \Zend\Soap\Exception
{
}
184 changes: 184 additions & 0 deletions src/Server/DocumentLiteralWrapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Soap
* @subpackage Server
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/

/**
* @namespace
*/
namespace Zend\Soap\Server;

use ReflectionClass;
use Zend\Soap\Exception\UnexpectedValueException;
use Zend\Soap\Exception\BadMethodCallException;

/**
* Wraps WSDL Document/Literal Style service objects to hide SOAP request
* message abstraction from the actual service object.
*
* When using the document/literal SOAP message pattern you end up with one
* object passed to your service methods that contains all the parameters of
* the method. This obviously leads to a problem since Zend\Soap\Wsdl tightly
* couples method parameters to request message parameters.
*
* Example:
*
* class MyCalculatorService
* {
* /**
* * @param int $x
* * @param int $y
* * @return int
* *
* public function add($x, $y) {}
* }
*
* The document/literal wrapper pattern would lead php ext/soap to generate a
* single "request" object that contains $x and $y properties. To solve this a
* wrapper service is needed that extracts the properties and delegates a
* proper call to the underlying service.
*
* The input variable from a document/literal SOAP-call to the client
* MyCalculatorServiceClient#add(10, 20) would lead PHP ext/soap to create
* the following request object:
*
* $addRequest = new \stdClass;
* $addRequest->x = 10;
* $addRequest->y = 20;
*
* This object does not match the signature of the server-side
* MyCalculatorService and lead to failure.
*
* Also the response object in this case is supposed to be an array
* or object with a property "addResult":
*
* $addResponse = new \stdClass;
* $addResponse->addResult = 30;
*
* To keep your service object code free from this implementation detail
* of SOAP this wrapper service handles the parsing between the formats.
*
* @example
*
* $service = new MyCalculatorService();
* $soap = new \Zend\Soap\Server($wsdlFile);
* $soap->setObject(new \Zend\Soap\Server\DocumentLiteralWrapper($service));
* $soap->handle();
*
* @uses ReflectionClass
* @category Zend
* @package Zend_Soap
* @subpackage Server
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class DocumentLiteralWrapper
{
/**
* @var object
*/
protected $_object;

/**
* @var ReflectionObject
*/
protected $_reflection;

/**
* Pass Service object to the constructor
*
* @param object $object
*/
public function __construct($object)
{
$this->_object = $object;
$this->_reflection = new \ReflectionObject($this->_object);
}

/**
* Proxy method that does the heavy document/literal decomposing.
*
* @param string $method
* @param array $args
* @return mixed
*/
public function __call($method, $args)
{
$this->_assertOnlyOneArgument($args);
$this->_assertServiceDelegateHasMethod($method);

$delegateArgs = $this->_parseArguments($method, $args[0]);
$ret = call_user_func_array(array($this->_object, $method), $delegateArgs);
return $this->_getResultMessage($method, $ret);
}

/**
* Parse the document/literal wrapper into arguments to call the real
* service.
*
* @param string $method
* @param object $document
* @return array
*/
protected function _parseArguments($method, $document)
{
$reflMethod = $this->_reflection->getMethod($method);
$params = array();
foreach ($reflMethod->getParameters() as $param) {
$params[$param->getName()] = $param;
}

$delegateArgs = array();
foreach (get_object_vars($document) as $argName => $argValue) {
if (!isset($params[$argName])) {
throw new UnexpectedValueException(sprintf(
"Recieved unknown argument %s which is not an argument to %s::%s",
get_class($this->_object), $method
));
}
$delegateArgs[$params[$argName]->getPosition()] = $argValue;
}
return $delegateArgs;
}

protected function _getResultMessage($method, $ret)
{
return array($method.'Result' => $ret);
}

protected function _assertServiceDelegateHasMethod($method)
{
if ( !$this->_reflection->hasMethod($method) ) {
throw new BadMethodCallException(sprintf(
"Method %s does not exist on delegate object %s",
$method, get_class($this->_object)
));
}
}

protected function _assertOnlyOneArgument($args)
{
if (count($args) != 1) {
throw new UnexpectedValueException(sprintf(
"Expecting exactly one argument that is the document/literal wrapper, got %d",
count($args)));
}
}
}

57 changes: 57 additions & 0 deletions test/Server/DocumentLiteralWrapperTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Soap
* @subpackage UnitTests
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/

namespace ZendTest\Soap\Server;

use Zend\Soap\Client\Local as SoapClient,
Zend\Soap\Server,
Zend\Soap\ServerException,
Zend\Soap\Server\DocumentLiteralWrapper,
ZendTest\Soap\TestAsset\MyCalculatorService;

class DocumentLiteralWrapperTest extends \PHPUnit_Framework_TestCase
{
const WSDL = '/_files/calculator.wsdl';

private $client;

public function setUp()
{
ini_set("soap.wsdl_cache_enabled", 0);
}

/**
* @runInSeparateProcess
*/
public function testDelegate()
{
$server = new Server(__DIR__ . self::WSDL);
$server->setObject(new DocumentLiteralWrapper(new MyCalculatorService));

// The local client needs an abstraction for this pattern as well.
// This is just a test so we use the messy way.
$client = new SoapClient($server, __DIR__ . self::WSDL);
$ret = $client->add(array('x' => 10, 'y' => 20));

$this->assertInstanceOf('stdClass', $ret);
$this->assertEquals(30, $ret->addResult);
}
}
52 changes: 52 additions & 0 deletions test/Server/_files/calculator.wsdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?xml version="1.0"?>
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://localhost" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 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="MyCalculatorService" targetNamespace="http://localhost">
<types>
<xsd:schema targetNamespace="http://localhost">
<xsd:element name="add">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="x" type="xsd:int"/>
<xsd:element name="y" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="addResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="addResult" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</types>
<portType name="MyCalculatorServicePort">
<operation name="add">
<documentation>@param int $x</documentation>
<input message="tns:addIn"/>
<output message="tns:addOut"/>
</operation>
</portType>
<binding name="MyCalculatorServiceBinding" type="tns:MyCalculatorServicePort">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="add">
<soap:operation soapAction="http://localhost#add"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="MyCalculatorServiceService">
<port name="MyCalculatorServicePort" binding="tns:MyCalculatorServiceBinding">
<soap:address location="http://localhost"/>
</port>
</service>
<message name="addIn">
<part name="parameters" element="tns:add"/>
</message>
<message name="addOut">
<part name="parameters" element="tns:addResponse"/>
</message>
</definitions>
41 changes: 41 additions & 0 deletions test/TestAsset/MyCalculatorService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Soap
* @subpackage UnitTests
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/

namespace ZendTest\Soap\TestAsset;

/**
* MyCalculatorService
*
* Class used in DocumentLiteralWrapperTest
*/
class MyCalculatorService
{
/**
* @param int $x
* @param int $y
* @return int
*/
public function add($x, $y)
{
return $x+$y;
}
}

0 comments on commit e8f73d2

Please sign in to comment.