PageRenderTime 25ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/app/code/Magento/Webapi/Model/ServiceMetadata.php

https://gitlab.com/crazybutterfly815/magento2
PHP | 292 lines | 170 code | 31 blank | 91 comment | 28 complexity | 5e54db619da67e9c56c2ae86580b11ac MD5 | raw file
  1. <?php
  2. /**
  3. * Copyright © 2016 Magento. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Webapi\Model;
  7. use Magento\Webapi\Model\Config\Converter;
  8. use Magento\Webapi\Model\Cache\Type\Webapi as WebApiCache;
  9. /**
  10. * Service Metadata Model
  11. */
  12. class ServiceMetadata
  13. {
  14. /**#@+
  15. * Keys that a used for service config internal representation.
  16. */
  17. const KEY_CLASS = 'class';
  18. const KEY_IS_SECURE = 'isSecure';
  19. const KEY_SERVICE_METHODS = 'methods';
  20. const KEY_METHOD = 'method';
  21. const KEY_IS_REQUIRED = 'inputRequired';
  22. const KEY_ACL_RESOURCES = 'resources';
  23. const KEY_ROUTES = 'routes';
  24. const KEY_ROUTE_METHOD = 'method';
  25. const KEY_ROUTE_PARAMS = 'parameters';
  26. const SERVICES_CONFIG_CACHE_ID = 'services-services-config';
  27. const ROUTES_CONFIG_CACHE_ID = 'routes-services-config';
  28. const REFLECTED_TYPES_CACHE_ID = 'soap-reflected-types';
  29. /**#@-*/
  30. /**
  31. * API services
  32. *
  33. * @var array
  34. */
  35. protected $services;
  36. /**
  37. * List of services with route data
  38. *
  39. * @var array
  40. */
  41. protected $routes;
  42. /**
  43. * @var WebApiCache
  44. */
  45. protected $cache;
  46. /** @var \Magento\Webapi\Model\Config */
  47. protected $config;
  48. /**
  49. * @var \Magento\Webapi\Model\Config\ClassReflector
  50. */
  51. protected $classReflector;
  52. /**
  53. * @var \Magento\Framework\Reflection\TypeProcessor
  54. */
  55. protected $typeProcessor;
  56. /**
  57. * Initialize dependencies.
  58. *
  59. * @param \Magento\Webapi\Model\Config $config
  60. * @param WebApiCache $cache
  61. * @param \Magento\Webapi\Model\Config\ClassReflector $classReflector
  62. * @param \Magento\Framework\Reflection\TypeProcessor $typeProcessor
  63. */
  64. public function __construct(
  65. \Magento\Webapi\Model\Config $config,
  66. WebApiCache $cache,
  67. \Magento\Webapi\Model\Config\ClassReflector $classReflector,
  68. \Magento\Framework\Reflection\TypeProcessor $typeProcessor
  69. ) {
  70. $this->config = $config;
  71. $this->cache = $cache;
  72. $this->classReflector = $classReflector;
  73. $this->typeProcessor = $typeProcessor;
  74. }
  75. /**
  76. * Collect the list of services metadata
  77. *
  78. * @return array
  79. */
  80. protected function initServicesMetadata()
  81. {
  82. $services = [];
  83. foreach ($this->config->getServices()[Converter::KEY_SERVICES] as $serviceClass => $serviceVersionData) {
  84. foreach ($serviceVersionData as $version => $serviceData) {
  85. $serviceName = $this->getServiceName($serviceClass, $version);
  86. foreach ($serviceData[Converter::KEY_METHODS] as $methodName => $methodMetadata) {
  87. $services[$serviceName][self::KEY_SERVICE_METHODS][$methodName] = [
  88. self::KEY_METHOD => $methodName,
  89. self::KEY_IS_REQUIRED => (bool)$methodMetadata[Converter::KEY_SECURE],
  90. self::KEY_IS_SECURE => $methodMetadata[Converter::KEY_SECURE],
  91. self::KEY_ACL_RESOURCES => $methodMetadata[Converter::KEY_ACL_RESOURCES],
  92. ];
  93. $services[$serviceName][self::KEY_CLASS] = $serviceClass;
  94. }
  95. $reflectedMethodsMetadata = $this->classReflector->reflectClassMethods(
  96. $serviceClass,
  97. $services[$serviceName][self::KEY_SERVICE_METHODS]
  98. );
  99. $services[$serviceName][self::KEY_SERVICE_METHODS] = array_merge_recursive(
  100. $services[$serviceName][self::KEY_SERVICE_METHODS],
  101. $reflectedMethodsMetadata
  102. );
  103. $services[$serviceName][Converter::KEY_DESCRIPTION] = $this->classReflector->extractClassDescription(
  104. $serviceClass
  105. );
  106. }
  107. }
  108. return $services;
  109. }
  110. /**
  111. * Return services loaded from cache if enabled or from files merged previously
  112. *
  113. * @return array
  114. */
  115. public function getServicesConfig()
  116. {
  117. if (null === $this->services) {
  118. $servicesConfig = $this->cache->load(self::SERVICES_CONFIG_CACHE_ID);
  119. $typesData = $this->cache->load(self::REFLECTED_TYPES_CACHE_ID);
  120. if ($servicesConfig && is_string($servicesConfig) && $typesData && is_string($typesData)) {
  121. $this->services = unserialize($servicesConfig);
  122. $this->typeProcessor->setTypesData(unserialize($typesData));
  123. } else {
  124. $this->services = $this->initServicesMetadata();
  125. $this->cache->save(serialize($this->services), self::SERVICES_CONFIG_CACHE_ID);
  126. $this->cache->save(serialize($this->typeProcessor->getTypesData()), self::REFLECTED_TYPES_CACHE_ID);
  127. }
  128. }
  129. return $this->services;
  130. }
  131. /**
  132. * Retrieve specific service interface data.
  133. *
  134. * @param string $serviceName
  135. * @return array
  136. * @throws \RuntimeException
  137. */
  138. public function getServiceMetadata($serviceName)
  139. {
  140. $servicesConfig = $this->getServicesConfig();
  141. if (!isset($servicesConfig[$serviceName]) || !is_array($servicesConfig[$serviceName])) {
  142. throw new \RuntimeException(__('Requested service is not available: "%1"', $serviceName));
  143. }
  144. return $servicesConfig[$serviceName];
  145. }
  146. /**
  147. * Translate service interface name into service name.
  148. *
  149. * Example:
  150. * <pre>
  151. * - \Magento\Customer\Api\CustomerAccountInterface::class, 'V1', false => customerCustomerAccount
  152. * - \Magento\Customer\Api\CustomerAddressInterface::class, 'V1', true => customerCustomerAddressV1
  153. * </pre>
  154. *
  155. * @param string $interfaceName
  156. * @param string $version
  157. * @param bool $preserveVersion Should version be preserved during interface name conversion into service name
  158. * @return string
  159. * @throws \InvalidArgumentException
  160. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  161. */
  162. public function getServiceName($interfaceName, $version, $preserveVersion = true)
  163. {
  164. if (!preg_match(\Magento\Webapi\Model\Config::SERVICE_CLASS_PATTERN, $interfaceName, $matches)) {
  165. $apiClassPattern = "#^(.+?)\\\\(.+?)\\\\Api\\\\(.+?)(Interface)?$#";
  166. preg_match($apiClassPattern, $interfaceName, $matches);
  167. }
  168. if (!empty($matches)) {
  169. $moduleNamespace = $matches[1];
  170. $moduleName = $matches[2];
  171. $moduleNamespace = ($moduleNamespace == 'Magento') ? '' : $moduleNamespace;
  172. if ($matches[4] === 'Interface') {
  173. $matches[4] = $matches[3];
  174. }
  175. $serviceNameParts = explode('\\', trim($matches[4], '\\'));
  176. if ($moduleName == $serviceNameParts[0]) {
  177. /** Avoid duplication of words in service name */
  178. $moduleName = '';
  179. }
  180. $parentServiceName = $moduleNamespace . $moduleName . array_shift($serviceNameParts);
  181. array_unshift($serviceNameParts, $parentServiceName);
  182. if ($preserveVersion) {
  183. $serviceNameParts[] = $version;
  184. }
  185. } elseif (preg_match(\Magento\Webapi\Model\Config::API_PATTERN, $interfaceName, $matches)) {
  186. $moduleNamespace = $matches[1];
  187. $moduleName = $matches[2];
  188. $moduleNamespace = ($moduleNamespace == 'Magento') ? '' : $moduleNamespace;
  189. $serviceNameParts = explode('\\', trim($matches[3], '\\'));
  190. if ($moduleName == $serviceNameParts[0]) {
  191. /** Avoid duplication of words in service name */
  192. $moduleName = '';
  193. }
  194. $parentServiceName = $moduleNamespace . $moduleName . array_shift($serviceNameParts);
  195. array_unshift($serviceNameParts, $parentServiceName);
  196. if ($preserveVersion) {
  197. $serviceNameParts[] = $version;
  198. }
  199. } else {
  200. throw new \InvalidArgumentException(sprintf('The service interface name "%s" is invalid.', $interfaceName));
  201. }
  202. return lcfirst(implode('', $serviceNameParts));
  203. }
  204. /**
  205. * Retrieve specific service interface data with route.
  206. *
  207. * @param string $serviceName
  208. * @return array
  209. * @throws \RuntimeException
  210. */
  211. public function getRouteMetadata($serviceName)
  212. {
  213. $routesConfig = $this->getRoutesConfig();
  214. if (!isset($routesConfig[$serviceName]) || !is_array($routesConfig[$serviceName])) {
  215. throw new \RuntimeException(__('Requested service is not available: "%1"', $serviceName));
  216. }
  217. return $routesConfig[$serviceName];
  218. }
  219. /**
  220. * Return routes loaded from cache if enabled or from files merged previously
  221. *
  222. * @return array
  223. */
  224. public function getRoutesConfig()
  225. {
  226. if (null === $this->routes) {
  227. $routesConfig = $this->cache->load(self::ROUTES_CONFIG_CACHE_ID);
  228. $typesData = $this->cache->load(self::REFLECTED_TYPES_CACHE_ID);
  229. if ($routesConfig && is_string($routesConfig) && $typesData && is_string($typesData)) {
  230. $this->routes = unserialize($routesConfig);
  231. $this->typeProcessor->setTypesData(unserialize($typesData));
  232. } else {
  233. $this->routes = $this->initRoutesMetadata();
  234. $this->cache->save(serialize($this->routes), self::ROUTES_CONFIG_CACHE_ID);
  235. $this->cache->save(serialize($this->typeProcessor->getTypesData()), self::REFLECTED_TYPES_CACHE_ID);
  236. }
  237. }
  238. return $this->routes;
  239. }
  240. /**
  241. * Collect the list of services with routes and request types for use in REST.
  242. *
  243. * @return array
  244. */
  245. protected function initRoutesMetadata()
  246. {
  247. $routes = $this->getServicesConfig();
  248. foreach ($this->config->getServices()[Converter::KEY_ROUTES] as $url => $routeData) {
  249. foreach ($routeData as $method => $data) {
  250. $serviceClass = $data[Converter::KEY_SERVICE][Converter::KEY_SERVICE_CLASS];
  251. $version = explode('/', ltrim($url, '/'))[0];
  252. $serviceName = $this->getServiceName($serviceClass, $version);
  253. $methodName = $data[Converter::KEY_SERVICE][Converter::KEY_METHOD];
  254. $routes[$serviceName][self::KEY_ROUTES][$url][$method][self::KEY_ROUTE_METHOD] = $methodName;
  255. $routes[$serviceName][self::KEY_ROUTES][$url][$method][self::KEY_ROUTE_PARAMS]
  256. = $data[Converter::KEY_DATA_PARAMETERS];
  257. }
  258. }
  259. return $routes;
  260. }
  261. }