Converter.php 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\Communication\Config\Reader\XmlReader;
  7. use Magento\Framework\Communication\Config\ConfigParser;
  8. use Magento\Framework\Communication\Config\ReflectionGenerator;
  9. use Magento\Framework\Communication\ConfigInterface as Config;
  10. use Magento\Framework\Stdlib\BooleanUtils;
  11. /**
  12. * Converts Communication config from \DOMDocument to array
  13. */
  14. class Converter implements \Magento\Framework\Config\ConverterInterface
  15. {
  16. /**
  17. * @deprecated
  18. * @see ConfigParser::parseServiceMethod
  19. */
  20. const SERVICE_METHOD_NAME_PATTERN = '/^([a-zA-Z\\\\]+)::([a-zA-Z]+)$/';
  21. /**
  22. * @var ReflectionGenerator
  23. */
  24. private $reflectionGenerator;
  25. /**
  26. * @var BooleanUtils
  27. */
  28. private $booleanUtils;
  29. /**
  30. * @var Validator
  31. */
  32. private $xmlValidator;
  33. /**
  34. * @var ConfigParser
  35. */
  36. private $configParser;
  37. /**
  38. * Initialize dependencies
  39. *
  40. * @param ReflectionGenerator $reflectionGenerator
  41. * @param BooleanUtils $booleanUtils
  42. * @param Validator $xmlValidator
  43. */
  44. public function __construct(
  45. ReflectionGenerator $reflectionGenerator,
  46. BooleanUtils $booleanUtils,
  47. Validator $xmlValidator
  48. ) {
  49. $this->reflectionGenerator = $reflectionGenerator;
  50. $this->booleanUtils = $booleanUtils;
  51. $this->xmlValidator = $xmlValidator;
  52. }
  53. /**
  54. * The getter function to get the new ConfigParser dependency.
  55. *
  56. * @return \Magento\Framework\Communication\Config\ConfigParser
  57. * @deprecated 101.0.0
  58. */
  59. private function getConfigParser()
  60. {
  61. if ($this->configParser === null) {
  62. $this->configParser = \Magento\Framework\App\ObjectManager::getInstance()
  63. ->get(\Magento\Framework\Communication\Config\ConfigParser::class);
  64. }
  65. return $this->configParser;
  66. }
  67. /**
  68. * Convert dom node tree to array
  69. *
  70. * @param \DOMDocument $source
  71. * @return array
  72. */
  73. public function convert($source)
  74. {
  75. $topics = $this->extractTopics($source);
  76. return [
  77. Config::TOPICS => $topics,
  78. ];
  79. }
  80. /**
  81. * Extract topics configuration.
  82. *
  83. * @param \DOMDocument $config
  84. * @return array
  85. */
  86. protected function extractTopics($config)
  87. {
  88. $output = [];
  89. /** @var $topicNode \DOMNode */
  90. foreach ($config->getElementsByTagName('topic') as $topicNode) {
  91. $topicAttributes = $topicNode->attributes;
  92. $topicName = $topicAttributes->getNamedItem('name')->nodeValue;
  93. $serviceMethod = $this->getServiceMethodBySchema($topicNode);
  94. $requestResponseSchema = $serviceMethod
  95. ? $this->reflectionGenerator->extractMethodMetadata(
  96. $serviceMethod[ConfigParser::TYPE_NAME],
  97. $serviceMethod[ConfigParser::METHOD_NAME]
  98. )
  99. : null;
  100. $requestSchema = $this->extractTopicRequestSchema($topicNode);
  101. $responseSchema = $this->extractTopicResponseSchema($topicNode);
  102. $handlers = $this->extractTopicResponseHandlers($topicNode);
  103. $this->xmlValidator->validateResponseRequest(
  104. $requestResponseSchema,
  105. $requestSchema,
  106. $topicName,
  107. $responseSchema,
  108. $handlers
  109. );
  110. $this->xmlValidator->validateDeclarationOfTopic(
  111. $requestResponseSchema,
  112. $topicName,
  113. $requestSchema,
  114. $responseSchema
  115. );
  116. $isSynchronous = $this->extractTopicIsSynchronous($topicNode);
  117. if ($serviceMethod) {
  118. $output[$topicName] = $this->reflectionGenerator->generateTopicConfigForServiceMethod(
  119. $topicName,
  120. $serviceMethod[ConfigParser::TYPE_NAME],
  121. $serviceMethod[ConfigParser::METHOD_NAME],
  122. $handlers,
  123. $isSynchronous
  124. );
  125. } elseif ($requestSchema && $responseSchema) {
  126. $output[$topicName] = [
  127. Config::TOPIC_NAME => $topicName,
  128. Config::TOPIC_IS_SYNCHRONOUS => $isSynchronous,
  129. Config::TOPIC_REQUEST => $requestSchema,
  130. Config::TOPIC_REQUEST_TYPE => Config::TOPIC_REQUEST_TYPE_CLASS,
  131. Config::TOPIC_RESPONSE => ($isSynchronous) ? $responseSchema: null,
  132. Config::TOPIC_HANDLERS => $handlers
  133. ];
  134. } elseif ($requestSchema) {
  135. $output[$topicName] = [
  136. Config::TOPIC_NAME => $topicName,
  137. Config::TOPIC_IS_SYNCHRONOUS => false,
  138. Config::TOPIC_REQUEST => $requestSchema,
  139. Config::TOPIC_REQUEST_TYPE => Config::TOPIC_REQUEST_TYPE_CLASS,
  140. Config::TOPIC_RESPONSE => null,
  141. Config::TOPIC_HANDLERS => $handlers
  142. ];
  143. }
  144. }
  145. return $output;
  146. }
  147. /**
  148. * Extract response handlers.
  149. *
  150. * @param \DOMNode $topicNode
  151. * @return array List of handlers, each contain service name and method name
  152. */
  153. protected function extractTopicResponseHandlers($topicNode)
  154. {
  155. $topicName = $topicNode->attributes->getNamedItem('name')->nodeValue;
  156. $topicChildNodes = $topicNode->childNodes;
  157. $handlerNodes = [];
  158. /** @var \DOMNode $topicChildNode */
  159. foreach ($topicChildNodes as $topicChildNode) {
  160. if ($topicChildNode->nodeName === 'handler') {
  161. $handlerAttributes = $topicChildNode->attributes;
  162. if ($handlerAttributes->getNamedItem('disabled')
  163. && $this->booleanUtils->toBoolean($handlerAttributes->getNamedItem('disabled')->nodeValue)
  164. ) {
  165. continue;
  166. }
  167. $handlerName = $handlerAttributes->getNamedItem('name')->nodeValue;
  168. $serviceType = $handlerAttributes->getNamedItem('type')->nodeValue;
  169. $methodName = $handlerAttributes->getNamedItem('method')->nodeValue;
  170. $this->xmlValidator->validateResponseHandlersType($serviceType, $methodName, $handlerName, $topicName);
  171. $handlerNodes[$handlerName] = [
  172. Config::HANDLER_TYPE => $serviceType,
  173. Config::HANDLER_METHOD => $methodName
  174. ];
  175. }
  176. }
  177. return $handlerNodes;
  178. }
  179. /**
  180. * Extract request schema class name.
  181. *
  182. * @param \DOMNode $topicNode
  183. * @return string|null
  184. */
  185. protected function extractTopicRequestSchema($topicNode)
  186. {
  187. $topicAttributes = $topicNode->attributes;
  188. if (!$topicAttributes->getNamedItem('request')) {
  189. return null;
  190. }
  191. $topicName = $topicAttributes->getNamedItem('name')->nodeValue;
  192. $requestSchema = $topicAttributes->getNamedItem('request')->nodeValue;
  193. $this->xmlValidator->validateRequestSchemaType($requestSchema, $topicName);
  194. return $requestSchema;
  195. }
  196. /**
  197. * Extract response schema class name.
  198. *
  199. * @param \DOMNode $topicNode
  200. * @return string|null
  201. */
  202. protected function extractTopicResponseSchema($topicNode)
  203. {
  204. $topicAttributes = $topicNode->attributes;
  205. if (!$topicAttributes->getNamedItem('response')) {
  206. return null;
  207. }
  208. $topicName = $topicAttributes->getNamedItem('name')->nodeValue;
  209. $responseSchema = $topicAttributes->getNamedItem('response')->nodeValue;
  210. $this->xmlValidator->validateResponseSchemaType($responseSchema, $topicName);
  211. return $responseSchema;
  212. }
  213. /**
  214. * Get service class and method specified in schema attribute.
  215. *
  216. * @param \DOMNode $topicNode
  217. * @return array|null Contains class name and method name
  218. */
  219. protected function getServiceMethodBySchema($topicNode)
  220. {
  221. $topicAttributes = $topicNode->attributes;
  222. if (!$topicAttributes->getNamedItem('schema')) {
  223. return null;
  224. }
  225. $topicName = $topicAttributes->getNamedItem('name')->nodeValue;
  226. $serviceMethod = $topicAttributes->getNamedItem('schema')->nodeValue;
  227. return $this->parseServiceMethod($serviceMethod, $topicName);
  228. }
  229. /**
  230. * Parse service method name, also ensure that it exists.
  231. *
  232. * @param string $serviceMethod
  233. * @param string $topicName
  234. * @return array Contains class name and method name
  235. */
  236. protected function parseServiceMethod($serviceMethod, $topicName)
  237. {
  238. $parsedServiceMethod = $this->getConfigParser()->parseServiceMethod($serviceMethod);
  239. $this->xmlValidator->validateServiceMethod(
  240. $serviceMethod,
  241. $topicName,
  242. $parsedServiceMethod[ConfigParser::TYPE_NAME],
  243. $parsedServiceMethod[ConfigParser::METHOD_NAME]
  244. );
  245. return $parsedServiceMethod;
  246. }
  247. /**
  248. * Extract is_synchronous topic value.
  249. *
  250. * @param \DOMNode $topicNode
  251. * @return bool
  252. */
  253. private function extractTopicIsSynchronous($topicNode): bool
  254. {
  255. $attributeName = Config::TOPIC_IS_SYNCHRONOUS;
  256. $topicAttributes = $topicNode->attributes;
  257. if (!$topicAttributes->getNamedItem($attributeName)) {
  258. return true;
  259. }
  260. return $this->booleanUtils->toBoolean($topicAttributes->getNamedItem($attributeName)->nodeValue);
  261. }
  262. }