PageRenderTime 22ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/Webapi/Adapter/Soap.php

https://gitlab.com/crazybutterfly815/magento2
PHP | 241 lines | 132 code | 15 blank | 94 comment | 16 complexity | c9c643d13c13b78e62a04ff077bd33e2 MD5 | raw file
  1. <?php
  2. /**
  3. * Copyright © 2016 Magento. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\TestFramework\TestCase\Webapi\Adapter;
  7. use Magento\Framework\Api\SimpleDataObjectConverter;
  8. use Magento\TestFramework\Helper\Bootstrap;
  9. use Magento\Webapi\Controller\Soap\Request\Handler as SoapHandler;
  10. /**
  11. * Test client for SOAP API testing.
  12. */
  13. class Soap implements \Magento\TestFramework\TestCase\Webapi\AdapterInterface
  14. {
  15. const WSDL_BASE_PATH = '/soap';
  16. /**
  17. * SOAP client initialized with different WSDLs.
  18. *
  19. * @var \Zend\Soap\Client[]
  20. */
  21. protected $_soapClients = [];
  22. /**
  23. * @var \Magento\Webapi\Model\Soap\Config
  24. */
  25. protected $_soapConfig;
  26. /**
  27. * @var SimpleDataObjectConverter
  28. */
  29. protected $_converter;
  30. /**
  31. * Initialize dependencies.
  32. */
  33. public function __construct()
  34. {
  35. /** @var $objectManager \Magento\TestFramework\ObjectManager */
  36. $objectManager = Bootstrap::getObjectManager();
  37. $this->_soapConfig = $objectManager->get(\Magento\Webapi\Model\Soap\Config::class);
  38. $this->_converter = $objectManager->get(\Magento\Framework\Api\SimpleDataObjectConverter::class);
  39. ini_set('default_socket_timeout', 120);
  40. }
  41. /**
  42. * {@inheritdoc}
  43. */
  44. public function call($serviceInfo, $arguments = [], $storeCode = null, $integration = null)
  45. {
  46. $soapOperation = $this->_getSoapOperation($serviceInfo);
  47. $arguments = $this->_converter->convertKeysToCamelCase($arguments);
  48. $soapResponse = $this->_getSoapClient($serviceInfo, $storeCode)->$soapOperation($arguments);
  49. //Convert to snake case for tests to use same assertion data for both SOAP and REST tests
  50. $result = (is_array($soapResponse) || is_object($soapResponse))
  51. ? $this->toSnakeCase($this->_converter->convertStdObjectToArray($soapResponse, true))
  52. : $soapResponse;
  53. /** Remove result wrappers */
  54. $result = isset($result[SoapHandler::RESULT_NODE_NAME]) ? $result[SoapHandler::RESULT_NODE_NAME] : $result;
  55. return $result;
  56. }
  57. /**
  58. * Get proper SOAP client instance that is initialized with with WSDL corresponding to requested service interface.
  59. *
  60. * @param string $serviceInfo PHP service interface name, should include version if present
  61. * @param string|null $storeCode
  62. * @return \Zend\Soap\Client
  63. */
  64. protected function _getSoapClient($serviceInfo, $storeCode = null)
  65. {
  66. $wsdlUrl = $this->generateWsdlUrl(
  67. [$this->_getSoapServiceName($serviceInfo) . $this->_getSoapServiceVersion($serviceInfo)],
  68. $storeCode
  69. );
  70. /** Check if there is SOAP client initialized with requested WSDL available */
  71. if (!isset($this->_soapClients[$wsdlUrl])) {
  72. $token = isset($serviceInfo['soap']['token']) ? $serviceInfo['soap']['token'] : null;
  73. $this->_soapClients[$wsdlUrl] = $this->instantiateSoapClient($wsdlUrl, $token);
  74. }
  75. return $this->_soapClients[$wsdlUrl];
  76. }
  77. /**
  78. * Create SOAP client instance and initialize it with provided WSDL URL.
  79. *
  80. * @param string $wsdlUrl
  81. * @param string $token Authentication token
  82. * @return \Zend\Soap\Client
  83. */
  84. public function instantiateSoapClient($wsdlUrl, $token = null)
  85. {
  86. $accessCredentials = $token
  87. ? $token
  88. : \Magento\TestFramework\Authentication\OauthHelper::getApiAccessCredentials()['key'];
  89. $opts = ['http' => ['header' => "Authorization: Bearer " . $accessCredentials]];
  90. $context = stream_context_create($opts);
  91. $soapClient = new \Zend\Soap\Client($wsdlUrl);
  92. $soapClient->setSoapVersion(SOAP_1_2);
  93. $soapClient->setStreamContext($context);
  94. if (TESTS_XDEBUG_ENABLED) {
  95. $soapClient->setCookie('XDEBUG_SESSION', 1);
  96. }
  97. return $soapClient;
  98. }
  99. /**
  100. * Generate WSDL URL.
  101. *
  102. * @param array $services e.g.<pre>
  103. * array(
  104. * 'catalogProductV1',
  105. * 'customerV2'
  106. * );</pre>
  107. * @param string|null $storeCode
  108. * @return string
  109. */
  110. public function generateWsdlUrl($services, $storeCode = null)
  111. {
  112. /** Sort list of services to avoid having different WSDL URLs for the identical lists of services. */
  113. //TODO: This may change since same resource of multiple versions may be allowed after namespace changes
  114. ksort($services);
  115. if ($storeCode == null) {
  116. $storeCode = Bootstrap::getObjectManager()
  117. ->get(\Magento\Store\Model\StoreManagerInterface::class)
  118. ->getStore()
  119. ->getCode();
  120. }
  121. /** TESTS_BASE_URL is initialized in PHPUnit configuration */
  122. $wsdlUrl = rtrim(TESTS_BASE_URL, '/') . self::WSDL_BASE_PATH . '/' . $storeCode . '?wsdl=1&services=';
  123. $wsdlResourceArray = [];
  124. foreach ($services as $serviceName) {
  125. $wsdlResourceArray[] = $serviceName;
  126. }
  127. return $wsdlUrl . implode(",", $wsdlResourceArray);
  128. }
  129. /**
  130. * Retrieve SOAP operation name from available service info.
  131. *
  132. * @param array $serviceInfo
  133. * @return string
  134. * @throws \LogicException
  135. */
  136. protected function _getSoapOperation($serviceInfo)
  137. {
  138. if (isset($serviceInfo['soap']['operation'])) {
  139. $soapOperation = $serviceInfo['soap']['operation'];
  140. } elseif (isset($serviceInfo['serviceInterface']) && isset($serviceInfo['method'])) {
  141. $soapOperation = $this->_soapConfig->getSoapOperation(
  142. $serviceInfo['serviceInterface'],
  143. $serviceInfo['method']
  144. );
  145. } else {
  146. throw new \LogicException("SOAP operation cannot be identified.");
  147. }
  148. return $soapOperation;
  149. }
  150. /**
  151. * Retrieve service version from available service info.
  152. *
  153. * @param array $serviceInfo
  154. * @return string
  155. * @throws \LogicException
  156. */
  157. protected function _getSoapServiceVersion($serviceInfo)
  158. {
  159. if (isset($serviceInfo['soap']['operation'])) {
  160. /*
  161. TODO: Need to rework this to remove version call for serviceInfo array with 'operation' key
  162. since version will be part of the service name
  163. */
  164. return '';
  165. } elseif (isset($serviceInfo['serviceInterface'])) {
  166. preg_match(
  167. \Magento\Webapi\Model\Config::SERVICE_CLASS_PATTERN,
  168. $serviceInfo['serviceInterface'],
  169. $matches
  170. );
  171. if (isset($matches[3])) {
  172. $version = $matches[3];
  173. } else {
  174. //TODO: Need to add this temporary version until version is added back for new MSC based services
  175. $version = 1;
  176. //throw new \LogicException("Service interface name is invalid.");
  177. }
  178. } else {
  179. throw new \LogicException("Service version cannot be identified.");
  180. }
  181. /** Normalize version */
  182. $version = 'V' . ltrim($version, 'vV');
  183. return $version;
  184. }
  185. /**
  186. * Retrieve service name from available service info.
  187. *
  188. * @param array $serviceInfo
  189. * @return string
  190. * @throws \LogicException
  191. */
  192. protected function _getSoapServiceName($serviceInfo)
  193. {
  194. if (isset($serviceInfo['soap']['service'])) {
  195. $serviceName = $serviceInfo['soap']['service'];
  196. } elseif (isset($serviceInfo['serviceInterface'])) {
  197. $serviceName = $this->_soapConfig->getServiceName($serviceInfo['serviceInterface'], false);
  198. } else {
  199. throw new \LogicException("Service name cannot be identified.");
  200. }
  201. return $serviceName;
  202. }
  203. /**
  204. * Recursively transform array keys from camelCase to snake_case.
  205. *
  206. * Utility method for converting SOAP responses. Webapi framework's SOAP processing outputs
  207. * snake case Data Object properties(ex. item_id) as camel case(itemId) to adhere to the WSDL.
  208. * This method allows tests to use the same data for asserting both SOAP and REST responses.
  209. *
  210. * @param array $objectData An array of data.
  211. * @return array The array with all camelCase keys converted to snake_case.
  212. */
  213. protected function toSnakeCase(array $objectData)
  214. {
  215. $data = [];
  216. foreach ($objectData as $key => $value) {
  217. $key = strtolower(preg_replace("/(?<=\\w)(?=[A-Z])/", "_$1", $key));
  218. if (is_array($value)) {
  219. $data[$key] = $this->toSnakeCase($value);
  220. } else {
  221. $data[$key] = $value;
  222. }
  223. }
  224. return $data;
  225. }
  226. }