PageRenderTime 23ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Zend/Soap/Server/DocumentLiteralWrapper.php

http://github.com/zendframework/zf2
PHP | 182 lines | 66 code | 13 blank | 103 comment | 4 complexity | 84b05c5c299fcd5a936dc72dcf8c3b02 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  5. * @link http://github.com/zendframework/zf2 for the canonical source repository
  6. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. */
  9. namespace Zend\Soap\Server;
  10. use ReflectionObject;
  11. use Zend\Soap\Exception;
  12. /**
  13. * Wraps WSDL Document/Literal Style service objects to hide SOAP request
  14. * message abstraction from the actual service object.
  15. *
  16. * When using the document/literal SOAP message pattern you end up with one
  17. * object passed to your service methods that contains all the parameters of
  18. * the method. This obviously leads to a problem since Zend\Soap\Wsdl tightly
  19. * couples method parameters to request message parameters.
  20. *
  21. * Example:
  22. *
  23. * class MyCalculatorService
  24. * {
  25. * /**
  26. * * @param int $x
  27. * * @param int $y
  28. * * @return int
  29. * *
  30. * public function add($x, $y) {}
  31. * }
  32. *
  33. * The document/literal wrapper pattern would lead php ext/soap to generate a
  34. * single "request" object that contains $x and $y properties. To solve this a
  35. * wrapper service is needed that extracts the properties and delegates a
  36. * proper call to the underlying service.
  37. *
  38. * The input variable from a document/literal SOAP-call to the client
  39. * MyCalculatorServiceClient#add(10, 20) would lead PHP ext/soap to create
  40. * the following request object:
  41. *
  42. * $addRequest = new \stdClass;
  43. * $addRequest->x = 10;
  44. * $addRequest->y = 20;
  45. *
  46. * This object does not match the signature of the server-side
  47. * MyCalculatorService and lead to failure.
  48. *
  49. * Also the response object in this case is supposed to be an array
  50. * or object with a property "addResult":
  51. *
  52. * $addResponse = new \stdClass;
  53. * $addResponse->addResult = 30;
  54. *
  55. * To keep your service object code free from this implementation detail
  56. * of SOAP this wrapper service handles the parsing between the formats.
  57. *
  58. * @example
  59. * <code>
  60. * $service = new MyCalculatorService();
  61. * $soap = new \Zend\Soap\Server($wsdlFile);
  62. * $soap->setObject(new \Zend\Soap\Server\DocumentLiteralWrapper($service));
  63. * $soap->handle();
  64. * </code>
  65. */
  66. class DocumentLiteralWrapper
  67. {
  68. /**
  69. * @var object
  70. */
  71. protected $object;
  72. /**
  73. * @var ReflectionObject
  74. */
  75. protected $reflection;
  76. /**
  77. * Pass Service object to the constructor
  78. *
  79. * @param object $object
  80. */
  81. public function __construct($object)
  82. {
  83. $this->object = $object;
  84. $this->reflection = new ReflectionObject($this->object);
  85. }
  86. /**
  87. * Proxy method that does the heavy document/literal decomposing.
  88. *
  89. * @param string $method
  90. * @param array $args
  91. * @return mixed
  92. */
  93. public function __call($method, $args)
  94. {
  95. $this->_assertOnlyOneArgument($args);
  96. $this->_assertServiceDelegateHasMethod($method);
  97. $delegateArgs = $this->_parseArguments($method, $args[0]);
  98. $ret = call_user_func_array(array($this->object, $method), $delegateArgs);
  99. return $this->_getResultMessage($method, $ret);
  100. }
  101. /**
  102. * Parse the document/literal wrapper into arguments to call the real
  103. * service.
  104. *
  105. * @param string $method
  106. * @param object $document
  107. * @return array
  108. * @throws Exception\UnexpectedValueException
  109. */
  110. protected function _parseArguments($method, $document)
  111. {
  112. $reflMethod = $this->reflection->getMethod($method);
  113. $params = array();
  114. foreach ($reflMethod->getParameters() as $param) {
  115. $params[$param->getName()] = $param;
  116. }
  117. $delegateArgs = array();
  118. foreach (get_object_vars($document) as $argName => $argValue) {
  119. if (!isset($params[$argName])) {
  120. throw new Exception\UnexpectedValueException(sprintf(
  121. "Received unknown argument %s which is not an argument to %s::%s",
  122. $argName,
  123. get_class($this->object),
  124. $method
  125. ));
  126. }
  127. $delegateArgs[$params[$argName]->getPosition()] = $argValue;
  128. }
  129. return $delegateArgs;
  130. }
  131. /**
  132. * Returns result message content
  133. *
  134. * @param string $method
  135. * @param mixed $ret
  136. * @return array
  137. */
  138. protected function _getResultMessage($method, $ret)
  139. {
  140. return array($method . 'Result' => $ret);
  141. }
  142. /**
  143. * @param string $method
  144. * @throws Exception\BadMethodCallException
  145. */
  146. protected function _assertServiceDelegateHasMethod($method)
  147. {
  148. if (!$this->reflection->hasMethod($method)) {
  149. throw new Exception\BadMethodCallException(sprintf(
  150. "Method %s does not exist on delegate object %s",
  151. $method,
  152. get_class($this->object)
  153. ));
  154. }
  155. }
  156. /**
  157. * @param array $args
  158. * @throws Exception\UnexpectedValueException
  159. */
  160. protected function _assertOnlyOneArgument(array $args)
  161. {
  162. if (count($args) != 1) {
  163. throw new Exception\UnexpectedValueException(sprintf(
  164. "Expecting exactly one argument that is the document/literal wrapper, got %d",
  165. count($args)
  166. ));
  167. }
  168. }
  169. }