RemoteServiceGenerator.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\MessageQueue\Code\Generator;
  7. use Magento\Framework\Code\Generator\DefinedClasses;
  8. use Magento\Framework\Code\Generator\Io;
  9. use Magento\Framework\Communication\Config\ReflectionGenerator;
  10. use Magento\Framework\Communication\ConfigInterface as CommunicationConfig;
  11. use Magento\Framework\MessageQueue\Code\Generator\Config\RemoteServiceReader\Communication as RemoteServiceReader;
  12. use Magento\Framework\Reflection\MethodsMap as ServiceMethodsMap;
  13. use Zend\Code\Reflection\MethodReflection;
  14. /**
  15. * Code generator for remote services.
  16. *
  17. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  18. */
  19. class RemoteServiceGenerator extends \Magento\Framework\Code\Generator\EntityAbstract
  20. {
  21. const ENTITY_TYPE = 'remote';
  22. const REMOTE_SERVICE_SUFFIX = 'Remote';
  23. /**
  24. * @var CommunicationConfig
  25. */
  26. protected $communicationConfig;
  27. /**
  28. * @var ServiceMethodsMap
  29. */
  30. private $serviceMethodsMap;
  31. /**
  32. * @var ReflectionGenerator
  33. */
  34. private $reflectionGenerator;
  35. /**
  36. * Initialize dependencies.
  37. *
  38. * @param CommunicationConfig $communicationConfig
  39. * @param ServiceMethodsMap $serviceMethodsMap
  40. * @param RemoteServiceReader $communicationRemoteServiceReader
  41. * @param string|null $sourceClassName
  42. * @param string|null $resultClassName
  43. * @param Io $ioObject
  44. * @param \Magento\Framework\Code\Generator\CodeGeneratorInterface $classGenerator
  45. * @param DefinedClasses $definedClasses
  46. *
  47. * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  48. */
  49. public function __construct(
  50. CommunicationConfig $communicationConfig,
  51. ServiceMethodsMap $serviceMethodsMap,
  52. RemoteServiceReader $communicationRemoteServiceReader,
  53. $sourceClassName = null,
  54. $resultClassName = null,
  55. Io $ioObject = null,
  56. \Magento\Framework\Code\Generator\CodeGeneratorInterface $classGenerator = null,
  57. DefinedClasses $definedClasses = null
  58. ) {
  59. $this->communicationConfig = $communicationConfig;
  60. $this->serviceMethodsMap = $serviceMethodsMap;
  61. parent::__construct(
  62. $sourceClassName,
  63. $resultClassName,
  64. $ioObject,
  65. $classGenerator,
  66. $definedClasses
  67. );
  68. }
  69. /**
  70. * {@inheritdoc}
  71. */
  72. protected function _getDefaultConstructorDefinition()
  73. {
  74. return [
  75. 'name' => '__construct',
  76. 'parameters' => [
  77. ['name' => 'publisher', 'type' => '\\' . \Magento\Framework\MessageQueue\PublisherInterface::class],
  78. ],
  79. 'body' => "\$this->publisher = \$publisher;",
  80. 'docblock' => [
  81. 'shortDescription' => 'Initialize dependencies.',
  82. 'tags' => [
  83. [
  84. 'name' => 'param',
  85. 'description' => '\Magento\Framework\MessageQueue\PublisherInterface $publisher',
  86. ],
  87. ],
  88. ],
  89. ];
  90. }
  91. /**
  92. * {@inheritdoc}
  93. */
  94. protected function _getClassProperties()
  95. {
  96. return [
  97. [
  98. 'name' => 'publisher',
  99. 'visibility' => 'protected',
  100. 'docblock' => [
  101. 'shortDescription' => 'Publisher',
  102. 'tags' => [
  103. [
  104. 'name' => 'var',
  105. 'description' => '\\' . \Magento\Framework\MessageQueue\PublisherInterface::class,
  106. ],
  107. ],
  108. ],
  109. ],
  110. ];
  111. }
  112. /**
  113. * {@inheritdoc}
  114. */
  115. protected function _getClassMethods()
  116. {
  117. $methods = [$this->_getDefaultConstructorDefinition()];
  118. $interfaceMethodsMap = $this->serviceMethodsMap->getMethodsMap($this->getSourceClassName());
  119. foreach (array_keys($interfaceMethodsMap) as $methodName) {
  120. // Uses Zend Reflection instead MethodsMap service, because second does not support features of PHP 7.x
  121. $methodReflection = new MethodReflection($this->getSourceClassName(), $methodName);
  122. $sourceMethodParameters = $methodReflection->getParameters();
  123. $methodParameters = [];
  124. $topicParameters = [];
  125. /** @var \Zend\Code\Reflection\ParameterReflection $methodParameter */
  126. foreach ($sourceMethodParameters as $methodParameter) {
  127. $parameterName = $methodParameter->getName();
  128. $parameter = [
  129. 'name' => $parameterName,
  130. 'type' => $methodParameter->getType(),
  131. ];
  132. if ($methodParameter->isDefaultValueAvailable()) {
  133. $parameter['defaultValue'] = $methodParameter->getDefaultValue() !== null
  134. ? $methodParameter->getDefaultValue() : $this->_getNullDefaultValue();
  135. }
  136. $methodParameters[] = $parameter;
  137. $topicParameters[] = "'{$parameterName}' => \${$parameterName}";
  138. }
  139. $topicName = $this->getReflectionGenerator()->generateTopicName($this->getSourceClassName(), $methodName);
  140. $topicConfig = $this->communicationConfig->getTopic($topicName);
  141. $methodBody = $topicConfig[CommunicationConfig::TOPIC_IS_SYNCHRONOUS] ? 'return ' : '';
  142. $methodBody .= "\$this->publisher->publish(\n"
  143. . " '{$topicName}',\n"
  144. . " [" . implode(', ', $topicParameters) . "]\n"
  145. . ");";
  146. $annotations = [['name' => 'inheritdoc']];
  147. $method = [
  148. 'name' => $methodName,
  149. 'returnType' => $methodReflection->getReturnType(),
  150. 'parameters' => $methodParameters,
  151. 'body' => $methodBody,
  152. 'docblock' => ['tags' => $annotations],
  153. ];
  154. $methods[] = $method;
  155. }
  156. return $methods;
  157. }
  158. /**
  159. * {@inheritdoc}
  160. */
  161. protected function _validateData()
  162. {
  163. $classNameValidationResults = $this->validateResultClassName();
  164. return parent::_validateData() && $classNameValidationResults;
  165. }
  166. /**
  167. * {@inheritdoc}
  168. */
  169. protected function _generateCode()
  170. {
  171. $this->_classGenerator->setImplementedInterfaces([$this->getSourceClassName()]);
  172. return parent::_generateCode();
  173. }
  174. /**
  175. * Ensure that result class name corresponds to the source class name.
  176. *
  177. * @return bool
  178. */
  179. protected function validateResultClassName()
  180. {
  181. $result = true;
  182. $sourceClassName = $this->getSourceClassName();
  183. $resultClassName = $this->_getResultClassName();
  184. $interfaceSuffix = 'Interface';
  185. if (substr($sourceClassName, -strlen($interfaceSuffix)) !== $interfaceSuffix) {
  186. $this->_addError(
  187. sprintf(
  188. 'Remote service class "%s" should be set as preference for an interface, "%s" given',
  189. $resultClassName,
  190. $sourceClassName
  191. )
  192. );
  193. }
  194. $expectedResultClassName = $sourceClassName . self::REMOTE_SERVICE_SUFFIX;
  195. if ($resultClassName !== $expectedResultClassName) {
  196. $this->_addError(
  197. 'Invalid remote service class name [' . $resultClassName . ']. Use ' . $expectedResultClassName
  198. );
  199. $result = false;
  200. }
  201. return $result;
  202. }
  203. /**
  204. * Get reflection generator.
  205. *
  206. * @return ReflectionGenerator
  207. *
  208. * @deprecated 102.0.1
  209. */
  210. private function getReflectionGenerator()
  211. {
  212. if ($this->reflectionGenerator === null) {
  213. $this->reflectionGenerator = \Magento\Framework\App\ObjectManager::getInstance()
  214. ->get(ReflectionGenerator::class);
  215. }
  216. return $this->reflectionGenerator;
  217. }
  218. }