diff --git a/app/code/Magento/AsynchronousOperations/Model/ConfigInterface.php b/app/code/Magento/AsynchronousOperations/Model/ConfigInterface.php
index 593ab52bbdf29..6e063fdb950db 100644
--- a/app/code/Magento/AsynchronousOperations/Model/ConfigInterface.php
+++ b/app/code/Magento/AsynchronousOperations/Model/ConfigInterface.php
@@ -30,6 +30,7 @@ interface ConfigInterface
const SERVICE_PARAM_KEY_INTERFACE = 'interface';
const SERVICE_PARAM_KEY_METHOD = 'method';
const SERVICE_PARAM_KEY_TOPIC = 'topic';
+ const SERVICE_PARAM_KEY_DESCRIPTION = 'description';
const DEFAULT_HANDLER_NAME = 'async';
const SYSTEM_TOPIC_NAME = 'async.system.required.wrapper.topic';
const SYSTEM_TOPIC_CONFIGURATION = [
@@ -48,7 +49,7 @@ interface ConfigInterface
* @return array
* @since 100.2.3
*/
- public function getServices();
+ public function getServices(): array;
/**
* Get topic name from webapi_async_config services config array by route url and http method
@@ -59,5 +60,15 @@ public function getServices();
* @throws \Magento\Framework\Exception\LocalizedException
* @since 100.2.3
*/
- public function getTopicName($routeUrl, $httpMethod);
+ public function getTopicName(string $routeUrl, string $httpMethod): string;
+
+ /**
+ * Get topic description from webapi_async_config services config array by route url and http method
+ *
+ * @param string $routeUrl
+ * @param string $httpMethod GET|POST|PUT|DELETE
+ * @return string
+ * @throws \Magento\Framework\Exception\LocalizedException
+ */
+ public function getTopicDescription(string $routeUrl, string $httpMethod): string;
}
diff --git a/app/code/Magento/AsynchronousOperations/Model/MassSchedule.php b/app/code/Magento/AsynchronousOperations/Model/MassSchedule.php
index d8efed5562131..d664b47ac4641 100644
--- a/app/code/Magento/AsynchronousOperations/Model/MassSchedule.php
+++ b/app/code/Magento/AsynchronousOperations/Model/MassSchedule.php
@@ -112,15 +112,24 @@ public function __construct(
*
* @param string $topicName
* @param array $entitiesArray
+ * @param string $topicDescription
* @param string $groupId
* @param string $userId
* @return AsyncResponseInterface
* @throws BulkException
* @throws LocalizedException
*/
- public function publishMass($topicName, array $entitiesArray, $groupId = null, $userId = null)
- {
+ public function publishMass(
+ $topicName,
+ array $entitiesArray,
+ $topicDescription = '',
+ $groupId = null,
+ $userId = null
+ ) {
$bulkDescription = __('Topic %1', $topicName);
+ if ($topicDescription !== '') {
+ $bulkDescription = $topicDescription;
+ }
if ($userId == null) {
$userId = $this->userContext->getUserId();
diff --git a/app/code/Magento/Webapi/Model/Config/Converter.php b/app/code/Magento/Webapi/Model/Config/Converter.php
index 837a0f84423ad..4d1010f0a2a2b 100644
--- a/app/code/Magento/Webapi/Model/Config/Converter.php
+++ b/app/code/Magento/Webapi/Model/Config/Converter.php
@@ -55,6 +55,10 @@ public function convert($source)
$soapMethod = trim($soapOperationNode->nodeValue);
}
$url = trim($route->attributes->getNamedItem('url')->nodeValue);
+ $description = '';
+ if ($descriptionNode = $route->attributes->getNamedItem('description')) {
+ $description = trim($descriptionNode->nodeValue);
+ }
$version = $this->convertVersion($url);
$serviceClassData = [];
@@ -104,6 +108,7 @@ public function convert($source)
],
self::KEY_ACL_RESOURCES => $resourceReferences,
self::KEY_DATA_PARAMETERS => $data,
+ self::KEY_DESCRIPTION => $description
];
$serviceSecure = false;
diff --git a/app/code/Magento/Webapi/Test/Unit/Model/Config/_files/webapi.php b/app/code/Magento/Webapi/Test/Unit/Model/Config/_files/webapi.php
index bd8fcc78953a4..da468ee58e89d 100644
--- a/app/code/Magento/Webapi/Test/Unit/Model/Config/_files/webapi.php
+++ b/app/code/Magento/Webapi/Test/Unit/Model/Config/_files/webapi.php
@@ -70,6 +70,7 @@
'value' => '%customer_id%',
],
],
+ 'description' => ''
],
],
'/V1/customers/me' => [
@@ -88,6 +89,7 @@
'value' => null,
],
],
+ 'description' => ''
],
'PUT' => [
'secure' => true,
@@ -104,6 +106,7 @@
'value' => null,
],
],
+ 'description' => ''
],
],
'/V1/customers' => [
@@ -118,6 +121,7 @@
],
'parameters' => [
],
+ 'description' => ''
],
],
'/V1/customers/:id' => [
@@ -132,6 +136,7 @@
],
'parameters' => [
],
+ 'description' => ''
],
'DELETE' => [
'secure' => false,
@@ -145,6 +150,7 @@
],
'parameters' => [
],
+ 'description' => ''
],
],
],
diff --git a/app/code/Magento/Webapi/etc/webapi_base.xsd b/app/code/Magento/Webapi/etc/webapi_base.xsd
index 7d1a5a14ba78f..82844355e65fc 100644
--- a/app/code/Magento/Webapi/etc/webapi_base.xsd
+++ b/app/code/Magento/Webapi/etc/webapi_base.xsd
@@ -30,6 +30,7 @@
+
diff --git a/app/code/Magento/WebapiAsync/Controller/Rest/AsynchronousRequestProcessor.php b/app/code/Magento/WebapiAsync/Controller/Rest/AsynchronousRequestProcessor.php
index 81235e335b8fa..20b83647ab979 100644
--- a/app/code/Magento/WebapiAsync/Controller/Rest/AsynchronousRequestProcessor.php
+++ b/app/code/Magento/WebapiAsync/Controller/Rest/AsynchronousRequestProcessor.php
@@ -87,7 +87,7 @@ public function __construct(
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function process(\Magento\Framework\Webapi\Rest\Request $request)
{
@@ -99,11 +99,13 @@ public function process(\Magento\Framework\Webapi\Rest\Request $request)
$entitiesParamsArray = $this->inputParamsResolver->resolve();
$topicName = $this->getTopicName($request);
+ $topicDescription = $this->getTopicDescription($request);
try {
$asyncResponse = $this->asyncBulkPublisher->publishMass(
$topicName,
- $entitiesParamsArray
+ $entitiesParamsArray,
+ $topicDescription
);
} catch (BulkException $bulkException) {
$asyncResponse = $bulkException->getData();
@@ -119,8 +121,11 @@ public function process(\Magento\Framework\Webapi\Rest\Request $request)
}
/**
+ * Get topic name from request
+ *
* @param \Magento\Framework\Webapi\Rest\Request $request
* @return string
+ * @throws \Magento\Framework\Exception\LocalizedException
*/
private function getTopicName($request)
{
@@ -133,7 +138,24 @@ private function getTopicName($request)
}
/**
- * {@inheritdoc}
+ * Get topic description from request
+ *
+ * @param \Magento\Framework\Webapi\Rest\Request $request
+ * @return string
+ * @throws \Magento\Framework\Exception\LocalizedException
+ */
+ private function getTopicDescription($request)
+ {
+ $route = $this->inputParamsResolver->getRoute();
+
+ return $this->webapiAsyncConfig->getTopicDescription(
+ $route->getRoutePath(),
+ $request->getHttpMethod()
+ );
+ }
+
+ /**
+ * @inheritdoc
*/
public function canProcess(\Magento\Framework\Webapi\Rest\Request $request)
{
@@ -148,6 +170,8 @@ public function canProcess(\Magento\Framework\Webapi\Rest\Request $request)
}
/**
+ * Check if path is bulk
+ *
* @param \Magento\Framework\Webapi\Rest\Request $request
* @return bool
*/
diff --git a/app/code/Magento/WebapiAsync/Model/Config.php b/app/code/Magento/WebapiAsync/Model/Config.php
index 7329862ca528c..b20fe3f69082d 100644
--- a/app/code/Magento/WebapiAsync/Model/Config.php
+++ b/app/code/Magento/WebapiAsync/Model/Config.php
@@ -59,7 +59,7 @@ public function __construct(
/**
* @inheritdoc
*/
- public function getServices()
+ public function getServices(): array
{
if (null === $this->asyncServices) {
$services = $this->cache->load(self::CACHE_ID);
@@ -77,7 +77,29 @@ public function getServices()
/**
* @inheritdoc
*/
- public function getTopicName($routeUrl, $httpMethod)
+ public function getTopicName(string $routeUrl, string $httpMethod): string
+ {
+ return $this->getServiceParameter($routeUrl, $httpMethod, self::SERVICE_PARAM_KEY_TOPIC);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getTopicDescription(string $routeUrl, string $httpMethod): string
+ {
+ return $this->getServiceParameter($routeUrl, $httpMethod, self::SERVICE_PARAM_KEY_DESCRIPTION);
+ }
+
+ /**
+ * Get service parameter by name
+ *
+ * @param string $routeUrl
+ * @param string $httpMethod
+ * @param string $attributeName
+ * @return string
+ * @throws LocalizedException
+ */
+ private function getServiceParameter(string $routeUrl, string $httpMethod, string $attributeName): string
{
$services = $this->getServices();
$lookupKey = $this->generateLookupKeyByRouteData(
@@ -91,7 +113,7 @@ public function getTopicName($routeUrl, $httpMethod)
);
}
- return $services[$lookupKey][self::SERVICE_PARAM_KEY_TOPIC];
+ return $services[$lookupKey][$attributeName];
}
/**
@@ -101,7 +123,7 @@ public function getTopicName($routeUrl, $httpMethod)
*
* @return array
*/
- private function generateTopicsDataFromWebapiConfig()
+ private function generateTopicsDataFromWebapiConfig(): array
{
$webApiConfig = $this->webApiConfig->getServices();
$services = [];
@@ -111,6 +133,11 @@ private function generateTopicsDataFromWebapiConfig()
$serviceInterface = $httpMethodData[Converter::KEY_SERVICE][Converter::KEY_SERVICE_CLASS];
$serviceMethod = $httpMethodData[Converter::KEY_SERVICE][Converter::KEY_SERVICE_METHOD];
+ $topicDescription = '';
+ if (isset($httpMethodData[Converter::KEY_DESCRIPTION])) {
+ $topicDescription = $httpMethodData[Converter::KEY_DESCRIPTION];
+ }
+
$lookupKey = $this->generateLookupKeyByRouteData(
$routeUrl,
$httpMethod
@@ -123,9 +150,10 @@ private function generateTopicsDataFromWebapiConfig()
);
$services[$lookupKey] = [
- self::SERVICE_PARAM_KEY_INTERFACE => $serviceInterface,
- self::SERVICE_PARAM_KEY_METHOD => $serviceMethod,
- self::SERVICE_PARAM_KEY_TOPIC => $topicName,
+ self::SERVICE_PARAM_KEY_INTERFACE => $serviceInterface,
+ self::SERVICE_PARAM_KEY_METHOD => $serviceMethod,
+ self::SERVICE_PARAM_KEY_TOPIC => $topicName,
+ self::SERVICE_PARAM_KEY_DESCRIPTION => $topicDescription
];
}
}
@@ -144,7 +172,7 @@ private function generateTopicsDataFromWebapiConfig()
* @param string $httpMethod
* @return string
*/
- private function generateLookupKeyByRouteData($routeUrl, $httpMethod)
+ private function generateLookupKeyByRouteData(string $routeUrl, string $httpMethod): string
{
return self::TOPIC_PREFIX . $this->generateKey($routeUrl, $httpMethod, '/', false);
}
@@ -161,7 +189,7 @@ private function generateLookupKeyByRouteData($routeUrl, $httpMethod)
* @param string $httpMethod
* @return string
*/
- private function generateTopicNameFromService($serviceInterface, $serviceMethod, $httpMethod)
+ private function generateTopicNameFromService(string $serviceInterface, string $serviceMethod, string $httpMethod): string
{
$typeName = strtolower(sprintf('%s.%s', $serviceInterface, $serviceMethod));
return strtolower(self::TOPIC_PREFIX . $this->generateKey($typeName, $httpMethod, '\\', false));
@@ -176,7 +204,7 @@ private function generateTopicNameFromService($serviceInterface, $serviceMethod,
* @param bool $lcfirst
* @return string
*/
- private function generateKey($typeName, $methodName, $delimiter = '\\', $lcfirst = true)
+ private function generateKey(string $typeName, string $methodName, string $delimiter = '\\', bool $lcfirst = true): string
{
$parts = explode($delimiter, trim($typeName, $delimiter));
foreach ($parts as &$part) {
diff --git a/app/code/Magento/WebapiAsync/Test/Unit/Model/ConfigTest.php b/app/code/Magento/WebapiAsync/Test/Unit/Model/ConfigTest.php
index df8367afe1775..007f7ee795e1d 100644
--- a/app/code/Magento/WebapiAsync/Test/Unit/Model/ConfigTest.php
+++ b/app/code/Magento/WebapiAsync/Test/Unit/Model/ConfigTest.php
@@ -67,7 +67,8 @@ public function testGetServicesSetsTopicFromServiceContractName()
'service' => [
'class' => ProductRepositoryInterface::class,
'method' => 'save',
- ]
+ ],
+ 'description' => ''
]
]
]
diff --git a/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Model/MassScheduleTest.php b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Model/MassScheduleTest.php
index 4976c8098103b..d0ff64c883bd0 100644
--- a/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Model/MassScheduleTest.php
+++ b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Model/MassScheduleTest.php
@@ -23,6 +23,8 @@
use Magento\Catalog\Model\ResourceModel\Product\Collection;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Framework\ObjectManagerInterface;
+use Magento\AsynchronousOperations\Model\ResourceModel\Bulk\Collection as BulkCollection;
+use Magento\Webapi\Model\Config\Reader as ConfigReader;
/**
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -74,8 +76,15 @@ class MassScheduleTest extends \PHPUnit\Framework\TestCase
*/
private $registry;
+ /** @var \PHPUnit\Framework\MockObject\MockObject */
+ protected $fileResolverMock;
+
+ /** @var ConfigReader */
+ protected $configReader;
+
protected function setUp(): void
{
+ $this->fileResolverMock = $this->createMock(\Magento\Framework\Config\FileResolverInterface::class);
$this->objectManager = Bootstrap::getObjectManager();
$this->registry = $this->objectManager->get(Registry::class);
$this->massSchedule = $this->objectManager->create(MassSchedule::class);
@@ -88,6 +97,10 @@ protected function setUp(): void
'logFilePath' => $this->logFilePath,
'appInitParams' => \Magento\TestFramework\Helper\Bootstrap::getInstance()->getAppInitParams()
]);
+ $this->configReader = $this->objectManager->create(
+ \Magento\Webapi\Model\Config\Reader::class,
+ ['fileResolver' => $this->fileResolverMock]
+ );
try {
$this->publisherConsumerController->initialize();
@@ -126,6 +139,8 @@ public function testScheduleMass($products)
public function sendBulk($products)
{
$this->skus = [];
+ $expectedDescription = 'Save Products Test Description';
+ $description = $this->readDescription();
foreach ($products as $data) {
if (isset($data['product'])) {
$this->skus[] = $data['product']->getSku();
@@ -135,7 +150,8 @@ public function sendBulk($products)
$result = $this->massSchedule->publishMass(
'async.magento.catalog.api.productrepositoryinterface.save.post',
- $products
+ $products,
+ $description
);
//assert bulk accepted with no errors
@@ -143,6 +159,13 @@ public function sendBulk($products)
//assert number of products sent to queue
$this->assertCount(count($this->skus), $result->getRequestItems());
+
+ //assert topic description
+ $this->assertEquals(
+ $expectedDescription,
+ $this->getDescription($result->getBulkUuid()),
+ 'Description is wrong'
+ );
}
protected function tearDown(): void
@@ -194,6 +217,18 @@ public function assertProductExists($productsSkus, $count)
return $size == $count;
}
+ public function getDescription($uuid)
+ {
+ $bulkDescription = '';
+ $collection = $this->objectManager->create(BulkCollection::class)
+ ->addFieldToFilter('uuid', ['in' => $uuid])
+ ->load();
+ if (!empty($collection->getFirstItem()->getData())) {
+ $bulkDescription = $collection->getFirstItem()->getDescription();
+ }
+ return $bulkDescription;
+ }
+
/**
* @dataProvider productExceptionDataProvider
* @param ProductInterface[] $products
@@ -305,4 +340,14 @@ public function productExceptionDataProvider()
],
];
}
+
+ public function readDescription()
+ {
+ $configFiles = [
+ file_get_contents(realpath(__DIR__ . '/../_files/webapiA.xml'))
+ ];
+ $this->fileResolverMock->expects($this->any())->method('get')->will($this->returnValue($configFiles));
+ $value = $this->configReader->read();
+ return $value['routes']['/V1/products']['POST']['description'];
+ }
}
diff --git a/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/webapiA.xml b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/webapiA.xml
new file mode 100644
index 0000000000000..6ec8bdae8809d
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/webapiA.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/dev/tests/integration/testsuite/Magento/Webapi/Model/Config/_files/webapi.php b/dev/tests/integration/testsuite/Magento/Webapi/Model/Config/_files/webapi.php
index 57c8fbf45c63c..232b92ac36700 100644
--- a/dev/tests/integration/testsuite/Magento/Webapi/Model/Config/_files/webapi.php
+++ b/dev/tests/integration/testsuite/Magento/Webapi/Model/Config/_files/webapi.php
@@ -138,6 +138,7 @@
],
'parameters' => [
],
+ 'description' => ''
],
],
'/V1/testmoduleMSC' => [
@@ -152,6 +153,7 @@
],
'parameters' => [
],
+ 'description' => ''
],
],
'/V1/testmodule1/:id' => [
@@ -166,6 +168,7 @@
],
'parameters' => [
],
+ 'description' => ''
],
],
'/V1/testmodule1' => [
@@ -184,6 +187,7 @@
'value' => null,
],
],
+ 'description' => ''
],
'POST' => [
'secure' => false,
@@ -200,6 +204,7 @@
'value' => null,
],
],
+ 'description' => ''
],
],
'/V2/testmodule1/:id' => [
@@ -215,6 +220,7 @@
],
'parameters' => [
],
+ 'description' => ''
],
'DELETE' => [
'secure' => false,
@@ -228,6 +234,7 @@
],
'parameters' => [
],
+ 'description' => ''
],
'PUT' => [
'secure' => false,
@@ -241,6 +248,7 @@
],
'parameters' => [
],
+ 'description' => ''
],
],
'/V2/testmodule1' => [
@@ -260,6 +268,7 @@
'value' => null,
],
],
+ 'description' => ''
],
],
'/V2/testmoduleMSC/itemPreconfigured' => [
@@ -274,6 +283,7 @@
'Magento_TestModuleMSC::resource2' => true,
],
'parameters' => [],
+ 'description' => ''
]
]
],