Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
ServiceMetadata.php
Go to the documentation of this file.
1 <?php
7 declare(strict_types=1);
8 
10 
11 use Magento\Webapi\Model\Config\Converter as WebapiConverter;
15 
17 {
21  private $webapiConfig;
25  private $serviceConfig;
29  private $asynchronousSchemaRequestProcessor;
33  private $request;
37  private $typeProcessor;
41  private $responseDefinitionReplacement;
45  private $synchronousOnlyHttpMethods = [
46  'GET'
47  ];
48 
56  public function __construct(
57  \Magento\Webapi\Model\Config $webapiConfig,
58  \Magento\WebapiAsync\Model\ServiceConfig $serviceConfig,
59  \Magento\Framework\Webapi\Rest\Request $request,
60  AsynchronousSchemaRequestProcessor $asynchronousSchemaRequestProcessor,
61  \Magento\Framework\Reflection\TypeProcessor $typeProcessor
62  ) {
63  $this->webapiConfig = $webapiConfig;
64  $this->serviceConfig = $serviceConfig;
65  $this->request = $request;
66  $this->asynchronousSchemaRequestProcessor = $asynchronousSchemaRequestProcessor;
67  $this->typeProcessor = $typeProcessor;
68  }
69 
76  public function afterGetServicesConfig(\Magento\Webapi\Model\ServiceMetadata $subject, array $result)
77  {
78  if ($this->asynchronousSchemaRequestProcessor->canProcess($this->request)) {
79  $synchronousOnlyServiceMethods = $this->getSynchronousOnlyServiceMethods($subject);
80  // Replace all results with the async response schema
81  foreach ($result as $serviceName => $serviceData) {
82  // Check all of the methods on the service
83  foreach ($serviceData[WebapiConverter::KEY_METHODS] as $methodName => $methodData) {
84  // Exclude service methods that are marked as synchronous only
85  if ($this->isServiceMethodSynchronousOnly(
86  $serviceName,
87  $methodName,
88  $synchronousOnlyServiceMethods
89  )) {
90  $this->removeServiceMethodDefinition($result, $serviceName, $methodName);
91  } else {
92  $this->replaceResponseDefinition($result, $serviceName, $methodName);
93  }
94  }
95  }
96  }
97 
98  return $result;
99  }
100 
107  private function isServiceMethodSynchronousOnly($serviceName, $methodName, array $synchronousOnlyServiceMethods)
108  {
109  return isset($synchronousOnlyServiceMethods[$serviceName][$methodName]);
110  }
111 
116  private function getServiceVersions(string $serviceName)
117  {
118  $services = $this->webapiConfig->getServices();
119 
120  return array_keys($services[WebapiConverter::KEY_SERVICES][$serviceName]);
121  }
122 
129  private function getSynchronousOnlyServiceMethods(\Magento\Webapi\Model\ServiceMetadata $serviceMetadata)
130  {
131  $synchronousOnlyServiceMethods = [];
132  $services = $this->serviceConfig->getServices()[Converter::KEY_SERVICES] ?? [];
133  foreach ($services as $service => $serviceData) {
134  if (!isset($serviceData[Converter::KEY_METHODS])) {
135  continue;
136  }
137 
138  foreach ($serviceData[Converter::KEY_METHODS] as $method => $methodData) {
139  if ($this->isMethodDataSynchronousOnly($methodData)) {
140  $this->appendSynchronousOnlyServiceMethodsWithInterface(
141  $serviceMetadata,
142  $synchronousOnlyServiceMethods,
143  $service,
144  $method
145  );
146  }
147  }
148  }
149 
150  return array_merge_recursive(
151  $synchronousOnlyServiceMethods,
152  $this->getSynchronousOnlyRoutesAsServiceMethods($serviceMetadata)
153  );
154  }
155 
163  private function getSynchronousOnlyRoutesAsServiceMethods(
164  \Magento\Webapi\Model\ServiceMetadata $serviceMetadata
165  ) {
166  $synchronousOnlyServiceMethods = [];
167  $serviceRoutes = $this->webapiConfig->getServices()[\Magento\Webapi\Model\Config\Converter::KEY_ROUTES];
168  foreach ($serviceRoutes as $serviceRoutePath => $serviceRouteMethods) {
169  foreach ($serviceRouteMethods as $serviceRouteMethod => $serviceRouteMethodData) {
170  // Check if the HTTP method associated with the route is not able to be async.
171  if (in_array(strtoupper($serviceRouteMethod), $this->synchronousOnlyHttpMethods)) {
172  $this->appendSynchronousOnlyServiceMethodsWithInterface(
173  $serviceMetadata,
174  $synchronousOnlyServiceMethods,
175  $serviceRouteMethodData[WebapiConverter::KEY_SERVICE][WebapiConverter::KEY_SERVICE_CLASS],
176  $serviceRouteMethodData[WebapiConverter::KEY_SERVICE][WebapiConverter::KEY_SERVICE_METHOD]
177  );
178  }
179  }
180  }
181 
182  return $synchronousOnlyServiceMethods;
183  }
184 
191  private function appendSynchronousOnlyServiceMethodsWithInterface(
192  \Magento\Webapi\Model\ServiceMetadata $serviceMetadata,
193  array &$synchronousOnlyServiceMethods,
194  $serviceInterface,
195  $serviceMethod
196  ) {
197  foreach ($this->getServiceVersions($serviceInterface) as $serviceVersion) {
198  $serviceName = $serviceMetadata->getServiceName($serviceInterface, $serviceVersion);
199  if (!array_key_exists($serviceName, $synchronousOnlyServiceMethods)) {
200  $synchronousOnlyServiceMethods[$serviceName] = [];
201  }
202 
203  $synchronousOnlyServiceMethods[$serviceName][$serviceMethod] = true;
204  }
205  }
206 
212  private function removeServiceMethodDefinition(array &$result, $serviceName, $methodName)
213  {
214  unset($result[$serviceName][WebapiConverter::KEY_METHODS][$methodName]);
215 
216  // Remove the service altogether if there is no methods left.
217  if (count($result[$serviceName][WebapiConverter::KEY_METHODS]) === 0) {
218  unset($result[$serviceName]);
219  }
220  }
221 
227  private function replaceResponseDefinition(array &$result, $serviceName, $methodName)
228  {
229  if (isset($result[$serviceName][WebapiConverter::KEY_METHODS][$methodName]['interface']['out'])) {
230  $replacement = $this->getResponseDefinitionReplacement();
231  $result[$serviceName][WebapiConverter::KEY_METHODS][$methodName]['interface']['out'] = $replacement;
232  }
233  }
234 
241  private function isMethodDataSynchronousOnly(array $methodData)
242  {
243  if (!isset($methodData[Converter::KEY_SYNCHRONOUS_INVOCATION_ONLY])) {
244  return false;
245  }
246 
247  return $methodData[Converter::KEY_SYNCHRONOUS_INVOCATION_ONLY];
248  }
249 
253  private function getResponseDefinitionReplacement()
254  {
255  if ($this->responseDefinitionReplacement === null) {
256  $this->responseDefinitionReplacement = [
257  'parameters' => [
258  'result' => [
259  'type' => $this->typeProcessor->register(AsyncResponseInterface::class),
260  'documentation' => 'Returns response information for the asynchronous request.',
261  'required' => true,
262  'response_codes' => [
263  'success' => [
264  'code' => '202',
265  'description' => '202 Accepted.'
266  ]
267  ]
268  ]
269  ]
270  ];
271  }
272 
273  return $this->responseDefinitionReplacement;
274  }
275 }
$replacement
Definition: website.php:23
$method
Definition: info.phtml:13
__construct(\Magento\Webapi\Model\Config $webapiConfig, \Magento\WebapiAsync\Model\ServiceConfig $serviceConfig, \Magento\Framework\Webapi\Rest\Request $request, AsynchronousSchemaRequestProcessor $asynchronousSchemaRequestProcessor, \Magento\Framework\Reflection\TypeProcessor $typeProcessor)
afterGetServicesConfig(\Magento\Webapi\Model\ServiceMetadata $subject, array $result)