Skip to content

Commit 8cb6135

Browse files
author
Vasiliev.A
committed
WebapiAsync prototype of bulk request implementation
1 parent 5a7c3bd commit 8cb6135

File tree

11 files changed

+473
-10
lines changed

11 files changed

+473
-10
lines changed

app/code/Magento/AsynchronousOperations/Model/MassSchedule.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public function publishMass($topicName, array $entitiesArray, $groupId = null, $
110110
$requestItems = [];
111111
$bulkException = new BulkException();
112112
foreach ($entitiesArray as $key => $entityParams) {
113-
/** @var \Magento\WebapiAsync\Api\Data\ItemStatusInterface $requestItem */
113+
/** @var \Magento\AsynchronousOperations\Api\Data\ItemStatusInterface $requestItem */
114114
$requestItem = $this->itemStatusInterfaceFactory->create();
115115

116116
try {

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
* @api
1818
* @since 100.0.2
1919
*/
20-
class Config
20+
class Config implements ConfigInterface
2121
{
2222
const CACHE_ID = 'webapi_config';
2323

@@ -66,9 +66,7 @@ public function __construct(
6666
}
6767

6868
/**
69-
* Return services loaded from cache if enabled or from files merged previously
70-
*
71-
* @return array
69+
* {@inheritdoc}
7270
*/
7371
public function getServices()
7472
{
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Webapi\Model;
7+
/**
8+
* This class gives access to consolidated web API configuration from <Module_Name>/etc/webapi.xml files.
9+
*
10+
* @api
11+
*/
12+
interface ConfigInterface
13+
{
14+
/**
15+
* Return services loaded from cache if enabled or from files merged previously
16+
*
17+
* @return array
18+
*/
19+
public function getServices();
20+
}

app/code/Magento/Webapi/Model/Rest/Config.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
namespace Magento\Webapi\Model\Rest;
77

88
use Magento\Webapi\Controller\Rest\Router\Route;
9-
use Magento\Webapi\Model\Config as ModelConfig;
9+
use Magento\Webapi\Model\ConfigInterface as ModelConfigInterface;
1010
use Magento\Webapi\Model\Config\Converter;
1111

1212
/**
@@ -43,11 +43,13 @@ class Config
4343
protected $_routeFactory;
4444

4545
/**
46-
* @param ModelConfig $config
46+
* @param ModelConfigInterface $config
4747
* @param \Magento\Framework\Controller\Router\Route\Factory $routeFactory
4848
*/
49-
public function __construct(ModelConfig $config, \Magento\Framework\Controller\Router\Route\Factory $routeFactory)
50-
{
49+
public function __construct(
50+
ModelConfigInterface $config,
51+
\Magento\Framework\Controller\Router\Route\Factory $routeFactory
52+
) {
5153
$this->_config = $config;
5254
$this->_routeFactory = $routeFactory;
5355
}

app/code/Magento/Webapi/etc/di.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77
-->
88
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
9+
<preference for="Magento\Webapi\Model\ConfigInterface" type="Magento\Webapi\Model\Config" />
910
<type name="Magento\Framework\App\AreaList">
1011
<arguments>
1112
<argument name="areas" xsi:type="array">
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\WebapiAsync\Controller\Rest\Asynchronous;
8+
9+
use Magento\Framework\Webapi\ServiceInputProcessor;
10+
use Magento\Framework\Webapi\Rest\Request as RestRequest;
11+
use Magento\Webapi\Controller\Rest\Router;
12+
use Magento\Webapi\Controller\Rest\ParamsOverrider;
13+
use Magento\Webapi\Controller\Rest\RequestValidator;
14+
use Magento\Webapi\Controller\Rest\InputParamsResolver as WebapiInputParamsResolver;
15+
16+
/**
17+
* This class is responsible for retrieving resolved input data
18+
*/
19+
class InputParamsResolver
20+
{
21+
/**
22+
* @var RestRequest
23+
*/
24+
private $request;
25+
/**
26+
* @var ParamsOverrider
27+
*/
28+
private $paramsOverrider;
29+
/**
30+
* @var ServiceInputProcessor
31+
*/
32+
private $serviceInputProcessor;
33+
/**
34+
* @var Router
35+
*/
36+
private $router;
37+
/**
38+
* @var RequestValidator
39+
*/
40+
private $requestValidator;
41+
/**
42+
* @var \Magento\Webapi\Controller\Rest\InputParamsResolver
43+
*/
44+
private $inputParamsResolver;
45+
46+
/**
47+
* Initialize dependencies.
48+
*
49+
* @param \Magento\Framework\Webapi\Rest\Request $request
50+
* @param \Magento\Webapi\Controller\Rest\ParamsOverrider $paramsOverrider
51+
* @param \Magento\Framework\Webapi\ServiceInputProcessor $inputProcessor
52+
* @param \Magento\Webapi\Controller\Rest\Router $router
53+
* @param \Magento\Webapi\Controller\Rest\RequestValidator $requestValidator
54+
* @param \Magento\Webapi\Controller\Rest\InputParamsResolver $inputParamsResolver
55+
*/
56+
public function __construct(
57+
RestRequest $request,
58+
ParamsOverrider $paramsOverrider,
59+
ServiceInputProcessor $inputProcessor,
60+
Router $router,
61+
RequestValidator $requestValidator,
62+
WebapiInputParamsResolver $inputParamsResolver
63+
) {
64+
$this->request = $request;
65+
$this->paramsOverrider = $paramsOverrider;
66+
$this->serviceInputProcessor = $inputProcessor;
67+
$this->router = $router;
68+
$this->requestValidator = $requestValidator;
69+
$this->inputParamsResolver = $inputParamsResolver;
70+
}
71+
72+
/**
73+
* Process and resolve input parameters
74+
* Return array with validated input params
75+
* or throw \Exception if at least one request entity params is not valid
76+
*
77+
* @return array
78+
* @throws \Magento\Framework\Exception\InputException if no value is provided for required parameters
79+
* @throws \Magento\Framework\Webapi\Exception
80+
*/
81+
public function resolve()
82+
{
83+
$this->requestValidator->validate();
84+
$webapiResolvedParams = [];
85+
$inputData = $this->request->getRequestData();
86+
foreach ($inputData as $key => $singleEntityParams) {
87+
$webapiResolvedParams[$key] = $this->resolveBulkItemParams($singleEntityParams);
88+
}
89+
90+
return $webapiResolvedParams;
91+
}
92+
93+
/**
94+
* @return \Magento\Webapi\Controller\Rest\Router\Route
95+
*/
96+
public function getRoute()
97+
{
98+
return $this->inputParamsResolver->getRoute();
99+
}
100+
101+
/**
102+
* Convert the input array from key-value format to a list of parameters
103+
* suitable for the specified class / method.
104+
*
105+
* Instead of \Magento\Webapi\Controller\Rest\InputParamsResolver
106+
* we don't need to merge body params with url params and use only body params
107+
*
108+
* @param array $inputData data to send to method in key-value format
109+
* @return array list of parameters that can be used to call the service method
110+
* @throws \Magento\Framework\Exception\InputException if no value is provided for required parameters
111+
* @throws \Magento\Framework\Webapi\Exception
112+
*/
113+
private function resolveBulkItemParams($inputData)
114+
{
115+
$route = $this->getRoute();
116+
$serviceMethodName = $route->getServiceMethod();
117+
$serviceClassName = $route->getServiceClass();
118+
$inputParams = $this->serviceInputProcessor->process($serviceClassName, $serviceMethodName, $inputData);
119+
120+
return $inputParams;
121+
}
122+
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\WebapiAsync\Controller\Rest;
8+
9+
use Magento\Framework\Exception\BulkException;
10+
use Magento\Webapi\Controller\Rest\RequestProcessorInterface;
11+
use Magento\Framework\Webapi\Rest\Response as RestResponse;
12+
use Magento\WebapiAsync\Controller\Rest\Asynchronous\InputParamsResolver;
13+
use Magento\AsynchronousOperations\Model\MassSchedule;
14+
use Magento\AsynchronousOperations\Model\ConfigInterface as WebApiAsyncConfig;
15+
use Magento\Framework\Reflection\DataObjectProcessor;
16+
use Magento\AsynchronousOperations\Api\Data\AsyncResponseInterfaceFactory;
17+
use Magento\AsynchronousOperations\Api\Data\AsyncResponseInterface;
18+
19+
class AsynchronousBulkRequestProcessor implements RequestProcessorInterface
20+
{
21+
const PROCESSOR_PATH = "/^\\/async\/bulk(\\/V.+)/";
22+
/**
23+
* @var \Magento\Framework\Webapi\Rest\Response
24+
*/
25+
private $response;
26+
/**
27+
* @var \Magento\WebapiAsync\Controller\Rest\Asynchronous\InputParamsResolver
28+
*/
29+
private $inputParamsResolver;
30+
/**
31+
* @var MassSchedule
32+
*/
33+
private $asyncBulkPublisher;
34+
/**
35+
* @var WebApiAsyncConfig
36+
*/
37+
private $webapiAsyncConfig;
38+
/**
39+
* @var \Magento\Framework\Reflection\DataObjectProcessor
40+
*/
41+
private $dataObjectProcessor;
42+
/**
43+
* @var AsyncResponseInterfaceFactory
44+
*/
45+
private $asyncResponseFactory;
46+
47+
/**
48+
* Initialize dependencies.
49+
*
50+
* @param RestResponse $response
51+
* @param InputParamsResolver $inputParamsResolver
52+
* @param MassSchedule $asyncBulkPublisher
53+
* @param WebapiAsyncConfig $webapiAsyncConfig
54+
* @param DataObjectProcessor $dataObjectProcessor
55+
* @param AsyncResponseInterfaceFactory $asyncResponse
56+
*/
57+
public function __construct(
58+
RestResponse $response,
59+
InputParamsResolver $inputParamsResolver,
60+
MassSchedule $asyncBulkPublisher,
61+
WebApiAsyncConfig $webapiAsyncConfig,
62+
DataObjectProcessor $dataObjectProcessor,
63+
AsyncResponseInterfaceFactory $asyncResponse
64+
) {
65+
$this->response = $response;
66+
$this->inputParamsResolver = $inputParamsResolver;
67+
$this->asyncBulkPublisher = $asyncBulkPublisher;
68+
$this->webapiAsyncConfig = $webapiAsyncConfig;
69+
$this->dataObjectProcessor = $dataObjectProcessor;
70+
$this->asyncResponseFactory = $asyncResponse;
71+
}
72+
73+
/**
74+
* {@inheritdoc}
75+
*/
76+
public function process(\Magento\Framework\Webapi\Rest\Request $request)
77+
{
78+
$path = $request->getPathInfo();
79+
$path = preg_replace(self::PROCESSOR_PATH, "$1", $path);
80+
$request->setPathInfo(
81+
$path
82+
);
83+
$entitiesParamsArray = $this->inputParamsResolver->resolve();
84+
$topicName = $this->getTopicName($request);
85+
try {
86+
$asyncResponse = $this->asyncBulkPublisher->publishMass(
87+
$topicName,
88+
$entitiesParamsArray
89+
);
90+
} catch (BulkException $bulkException) {
91+
$asyncResponse = $bulkException->getData();
92+
}
93+
$responseData = $this->dataObjectProcessor->buildOutputDataArray(
94+
$asyncResponse,
95+
AsyncResponseInterface::class
96+
);
97+
$this->response->setStatusCode(RestResponse::STATUS_CODE_202)
98+
->prepareResponse($responseData);
99+
}
100+
101+
/**
102+
* @param \Magento\Framework\Webapi\Rest\Request $request
103+
* @return string
104+
*/
105+
private function getTopicName($request)
106+
{
107+
$route = $this->inputParamsResolver->getRoute();
108+
109+
return $this->webapiAsyncConfig->getTopicName(
110+
$route->getRoutePath(),
111+
$request->getHttpMethod()
112+
);
113+
}
114+
115+
/**
116+
* {@inheritdoc}
117+
*/
118+
public function canProcess(\Magento\Framework\Webapi\Rest\Request $request)
119+
{
120+
if ($request->getHttpMethod() === \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET) {
121+
return false;
122+
}
123+
if (preg_match(self::PROCESSOR_PATH, $request->getPathInfo()) === 1) {
124+
return true;
125+
}
126+
127+
return false;
128+
}
129+
}

0 commit comments

Comments
 (0)