Handler.php 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Webapi\Controller\Soap\Request;
  7. use Magento\Framework\Api\ExtensibleDataInterface;
  8. use Magento\Framework\Api\MetadataObjectInterface;
  9. use Magento\Framework\Api\SimpleDataObjectConverter;
  10. use Magento\Framework\Webapi\Authorization;
  11. use Magento\Framework\Exception\AuthorizationException;
  12. use Magento\Framework\Reflection\DataObjectProcessor;
  13. use Magento\Framework\Webapi\ServiceInputProcessor;
  14. use Magento\Framework\Webapi\Request as SoapRequest;
  15. use Magento\Framework\Webapi\Exception as WebapiException;
  16. use Magento\Webapi\Model\Soap\Config as SoapConfig;
  17. use Magento\Framework\Reflection\MethodsMap;
  18. use Magento\Webapi\Model\ServiceMetadata;
  19. /**
  20. * Handler of requests to SOAP server.
  21. *
  22. * The main responsibility is to instantiate proper action controller (service) and execute requested method on it.
  23. *
  24. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  25. */
  26. class Handler
  27. {
  28. const RESULT_NODE_NAME = 'result';
  29. /**
  30. * @var \Magento\Framework\Webapi\Request
  31. */
  32. protected $_request;
  33. /**
  34. * @var \Magento\Framework\ObjectManagerInterface
  35. */
  36. protected $_objectManager;
  37. /**
  38. * @var \Magento\Webapi\Model\Soap\Config
  39. */
  40. protected $_apiConfig;
  41. /**
  42. * @var \Magento\Framework\Webapi\Authorization
  43. */
  44. protected $authorization;
  45. /**
  46. * @var \Magento\Framework\Api\SimpleDataObjectConverter
  47. */
  48. protected $_dataObjectConverter;
  49. /**
  50. * @var \Magento\Framework\Webapi\ServiceInputProcessor
  51. */
  52. protected $serviceInputProcessor;
  53. /**
  54. * @var \Magento\Framework\Reflection\DataObjectProcessor
  55. */
  56. protected $_dataObjectProcessor;
  57. /**
  58. * @var \Magento\Framework\Reflection\MethodsMap
  59. */
  60. protected $methodsMapProcessor;
  61. /**
  62. * Initialize dependencies.
  63. *
  64. * @param SoapRequest $request
  65. * @param \Magento\Framework\ObjectManagerInterface $objectManager
  66. * @param SoapConfig $apiConfig
  67. * @param Authorization $authorization
  68. * @param SimpleDataObjectConverter $dataObjectConverter
  69. * @param ServiceInputProcessor $serviceInputProcessor
  70. * @param DataObjectProcessor $dataObjectProcessor
  71. * @param MethodsMap $methodsMapProcessor
  72. */
  73. public function __construct(
  74. SoapRequest $request,
  75. \Magento\Framework\ObjectManagerInterface $objectManager,
  76. SoapConfig $apiConfig,
  77. Authorization $authorization,
  78. SimpleDataObjectConverter $dataObjectConverter,
  79. ServiceInputProcessor $serviceInputProcessor,
  80. DataObjectProcessor $dataObjectProcessor,
  81. MethodsMap $methodsMapProcessor
  82. ) {
  83. $this->_request = $request;
  84. $this->_objectManager = $objectManager;
  85. $this->_apiConfig = $apiConfig;
  86. $this->authorization = $authorization;
  87. $this->_dataObjectConverter = $dataObjectConverter;
  88. $this->serviceInputProcessor = $serviceInputProcessor;
  89. $this->_dataObjectProcessor = $dataObjectProcessor;
  90. $this->methodsMapProcessor = $methodsMapProcessor;
  91. }
  92. /**
  93. * Handler for all SOAP operations.
  94. *
  95. * @param string $operation
  96. * @param array $arguments
  97. * @return array
  98. * @throws WebapiException
  99. * @throws \LogicException
  100. * @throws AuthorizationException
  101. */
  102. public function __call($operation, $arguments)
  103. {
  104. $requestedServices = $this->_request->getRequestedServices();
  105. $serviceMethodInfo = $this->_apiConfig->getServiceMethodInfo($operation, $requestedServices);
  106. $serviceClass = $serviceMethodInfo[ServiceMetadata::KEY_CLASS];
  107. $serviceMethod = $serviceMethodInfo[ServiceMetadata::KEY_METHOD];
  108. // check if the operation is a secure operation & whether the request was made in HTTPS
  109. if ($serviceMethodInfo[ServiceMetadata::KEY_IS_SECURE] && !$this->_request->isSecure()) {
  110. throw new WebapiException(__("Operation allowed only in HTTPS"));
  111. }
  112. if (!$this->authorization->isAllowed($serviceMethodInfo[ServiceMetadata::KEY_ACL_RESOURCES])) {
  113. throw new AuthorizationException(
  114. __(
  115. "The consumer isn't authorized to access %resources.",
  116. ['resources' => implode(', ', $serviceMethodInfo[ServiceMetadata::KEY_ACL_RESOURCES])]
  117. )
  118. );
  119. }
  120. $service = $this->_objectManager->get($serviceClass);
  121. $inputData = $this->_prepareRequestData($serviceClass, $serviceMethod, $arguments);
  122. $outputData = call_user_func_array([$service, $serviceMethod], $inputData);
  123. return $this->_prepareResponseData($outputData, $serviceClass, $serviceMethod);
  124. }
  125. /**
  126. * Convert SOAP operation arguments into format acceptable by service method.
  127. *
  128. * @param string $serviceClass
  129. * @param string $serviceMethod
  130. * @param array $arguments
  131. * @return array
  132. */
  133. protected function _prepareRequestData($serviceClass, $serviceMethod, $arguments)
  134. {
  135. /** SoapServer wraps parameters into array. Thus this wrapping should be removed to get access to parameters. */
  136. $arguments = reset($arguments);
  137. $arguments = $this->_dataObjectConverter->convertStdObjectToArray($arguments, true);
  138. return $this->serviceInputProcessor->process($serviceClass, $serviceMethod, $arguments);
  139. }
  140. /**
  141. * Convert service response into format acceptable by SoapServer.
  142. *
  143. * @param object|array|string|int|float|null $data
  144. * @param string $serviceClassName
  145. * @param string $serviceMethodName
  146. * @return array
  147. * @throws \InvalidArgumentException
  148. */
  149. protected function _prepareResponseData($data, $serviceClassName, $serviceMethodName)
  150. {
  151. /** @var string $dataType */
  152. $dataType = $this->methodsMapProcessor->getMethodReturnType($serviceClassName, $serviceMethodName);
  153. $result = null;
  154. if (is_object($data)) {
  155. $result = $this->_dataObjectConverter
  156. ->convertKeysToCamelCase($this->_dataObjectProcessor->buildOutputDataArray($data, $dataType));
  157. } elseif (is_array($data)) {
  158. $dataType = substr($dataType, 0, -2);
  159. foreach ($data as $key => $value) {
  160. if ($value instanceof $dataType
  161. // the following two options are supported for backward compatibility
  162. || $value instanceof ExtensibleDataInterface
  163. || $value instanceof MetadataObjectInterface
  164. ) {
  165. $result[] = $this->_dataObjectConverter
  166. ->convertKeysToCamelCase($this->_dataObjectProcessor->buildOutputDataArray($value, $dataType));
  167. } else {
  168. $result[$key] = $value;
  169. }
  170. }
  171. } elseif (is_scalar($data) || $data === null) {
  172. $result = $data;
  173. } else {
  174. throw new \InvalidArgumentException("Service returned result in invalid format.");
  175. }
  176. return [self::RESULT_NODE_NAME => $result];
  177. }
  178. }