From 400334bdd74a4a958cc39a77b0cb800c181caf13 Mon Sep 17 00:00:00 2001 From: jekabs Date: Wed, 21 Oct 2020 16:06:34 +0300 Subject: [PATCH 01/23] Product variants -Added string type or message entity id to accomodate product variants --- app/code/Magento/CatalogExport/Event/Data/Entity.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/CatalogExport/Event/Data/Entity.php b/app/code/Magento/CatalogExport/Event/Data/Entity.php index 0d27bd082..8b4b55178 100644 --- a/app/code/Magento/CatalogExport/Event/Data/Entity.php +++ b/app/code/Magento/CatalogExport/Event/Data/Entity.php @@ -14,7 +14,7 @@ class Entity { /** - * @var int + * @var int|string */ private $entityId; @@ -26,9 +26,9 @@ class Entity /** * Get entity id. * - * @return int + * @return int|string */ - public function getEntityId(): int + public function getEntityId() { return $this->entityId; } @@ -36,11 +36,11 @@ public function getEntityId(): int /** * Set entity id. * - * @param int $entityId + * @param int|string $entityId * * @return void */ - public function setEntityId(int $entityId): void + public function setEntityId($entityId): void { $this->entityId = $entityId; } From e5dde0891feb4622281c6531a2abe26702f3cb68 Mon Sep 17 00:00:00 2001 From: jekabs Date: Tue, 27 Oct 2020 15:46:25 +0200 Subject: [PATCH 02/23] Product variants -Added product variant write and delete functionality to Catalog Storefront --- .../Model/FetchProductVariants.php | 90 +++++++++ .../Model/FetchProductVariantsInterface.php | 25 +++ .../Category/DeleteCategoriesConsumer.php | 2 +- .../Category/PublishCategoriesConsumer.php | 2 +- .../MessageBus/ConsumerEventInterface.php | 4 +- .../Product/DeleteProductsConsumer.php | 2 +- .../Product/PublishProductsConsumer.php | 2 +- .../DeleteProductVariantsConsumer.php | 70 +++++++ .../ProductVariantsConsumer.php | 73 ++++++++ .../PublishProductVariantsConsumer.php | 118 ++++++++++++ .../etc/communication.xml | 1 + .../Magento/CatalogMessageBroker/etc/di.xml | 7 + .../etc/queue_consumer.xml | 1 + .../Model/CatalogRepository.php | 30 +++ .../Model/Storage/Client/CommandInterface.php | 10 + .../Storage/Client/Config/ProductVariant.php | 60 ++++++ .../Storage/Client/ElasticsearchCommand.php | 70 +++++++ .../CatalogStorefront/Model/Storage/State.php | 1 + .../Model/VariantService.php | 173 ++++++++++++++++++ app/code/Magento/CatalogStorefront/etc/di.xml | 3 + .../Workaround/ConsumerInvoker.php | 1 + 21 files changed, 739 insertions(+), 6 deletions(-) create mode 100644 app/code/Magento/CatalogMessageBroker/Model/FetchProductVariants.php create mode 100644 app/code/Magento/CatalogMessageBroker/Model/FetchProductVariantsInterface.php create mode 100644 app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/DeleteProductVariantsConsumer.php create mode 100644 app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/ProductVariantsConsumer.php create mode 100644 app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/PublishProductVariantsConsumer.php create mode 100644 app/code/Magento/CatalogStorefront/Model/Storage/Client/Config/ProductVariant.php create mode 100644 app/code/Magento/CatalogStorefront/Model/VariantService.php diff --git a/app/code/Magento/CatalogMessageBroker/Model/FetchProductVariants.php b/app/code/Magento/CatalogMessageBroker/Model/FetchProductVariants.php new file mode 100644 index 000000000..7a5c3a112 --- /dev/null +++ b/app/code/Magento/CatalogMessageBroker/Model/FetchProductVariants.php @@ -0,0 +1,90 @@ +restClient = $restClient; + $this->logger = $logger; + } + + /** + * @inheritdoc + */ + public function execute(array $entities): array + { + try { + $variants = $this->restClient->get( + self::EXPORT_API_GET_VARIANTS, + $this->prepareRequestData($entities) + ); + } catch (\Throwable $e) { + $this->logger->error( + \sprintf( + 'Cannot load product variants via "%s" with ids "%s"', + self::EXPORT_API_GET_PRODUCTS, + \implode(',', \array_map(function (Entity $entity) { + return $entity->getEntityId(); + }, $entities)) + ), + ['exception' => $e] + ); + return []; + } + + return $variants; + } + + /** + * Prepare client request data + * + * @param Entity[] $entities + * @param string $storeCode + * + * @return array + */ + private function prepareRequestData(array $entities): array + { + $variants = []; + foreach ($entities as $entity) { + $variants['ids'][] = $entity->getEntityId(); + } + return $variants; + } +} diff --git a/app/code/Magento/CatalogMessageBroker/Model/FetchProductVariantsInterface.php b/app/code/Magento/CatalogMessageBroker/Model/FetchProductVariantsInterface.php new file mode 100644 index 000000000..0f1124a90 --- /dev/null +++ b/app/code/Magento/CatalogMessageBroker/Model/FetchProductVariantsInterface.php @@ -0,0 +1,25 @@ +fetchCategories->execute($entities, $scope); $attributesArray = $this->getAttributesArray($entities); diff --git a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ConsumerEventInterface.php b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ConsumerEventInterface.php index 923d54767..118f61670 100644 --- a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ConsumerEventInterface.php +++ b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ConsumerEventInterface.php @@ -18,9 +18,9 @@ interface ConsumerEventInterface * Execute consumers by ids for specified scope * * @param Entity[] $entities - * @param string $scope + * @param string|null $scope * * @return void */ - public function execute(array $entities, string $scope): void; + public function execute(array $entities, string $scope = null): void; } diff --git a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Product/DeleteProductsConsumer.php b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Product/DeleteProductsConsumer.php index af3e8e446..b4b64b571 100644 --- a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Product/DeleteProductsConsumer.php +++ b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Product/DeleteProductsConsumer.php @@ -49,7 +49,7 @@ public function __construct( /** * @inheritdoc */ - public function execute(array $entities, string $scope): void + public function execute(array $entities, string $scope = null): void { $ids = []; diff --git a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Product/PublishProductsConsumer.php b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Product/PublishProductsConsumer.php index 1b56322d4..99e47e4ce 100644 --- a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Product/PublishProductsConsumer.php +++ b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Product/PublishProductsConsumer.php @@ -73,7 +73,7 @@ public function __construct( /** * @inheritdoc */ - public function execute(array $entities, string $scope): void + public function execute(array $entities, string $scope = null): void { $productsData = $this->fetchProducts->execute($entities, $scope); $attributesArray = $this->getAttributesArray($entities); diff --git a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/DeleteProductVariantsConsumer.php b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/DeleteProductVariantsConsumer.php new file mode 100644 index 000000000..a0aea13ff --- /dev/null +++ b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/DeleteProductVariantsConsumer.php @@ -0,0 +1,70 @@ +deleteVariantsRequestInterfaceFactory = $deleteVariantsRequestInterfaceFactory; + $this->variantsServer = $variantsServer; + $this->logger = $logger; + } + + /** + * @inheritdoc + */ + public function execute(array $entities, string $scope = null): void + { + $ids = []; + foreach ($entities as $entity) { + $ids[] = $entity->getEntityId(); + } + + $deleteVariantsRequest = $this->deleteVariantsRequestInterfaceFactory->create(); + $deleteVariantsRequest->setId($ids); + + try { + $importResult = $this->variantsServer->DeleteProductVariants($deleteVariantsRequest); + if ($importResult->getStatus() === false) { + $this->logger->error(sprintf('Product variants deletion has failed: "%s"', $importResult->getMessage())); + } + } catch (\Throwable $e) { + $this->logger->critical(sprintf('Exception while deleting product variants: "%s"', $e)); + } + } +} diff --git a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/ProductVariantsConsumer.php b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/ProductVariantsConsumer.php new file mode 100644 index 000000000..d77e09b8a --- /dev/null +++ b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/ProductVariantsConsumer.php @@ -0,0 +1,73 @@ +logger = $logger; + $this->consumerEventFactory = $consumerEventFactory; + } + + /** + * Process message + * + * @param ChangedEntities $message + * @return void + */ + public function processMessage(ChangedEntities $message): void + { + try { + $eventType = $message->getMeta() ? $message->getMeta()->getEventType() : null; + $entities = $message->getData() ? $message->getData()->getEntities() : null; + + if (empty($entities)) { + throw new \InvalidArgumentException('Product variants data is missing in payload'); + } + + $variantsEvent = $this->consumerEventFactory->create($eventType); + $variantsEvent->execute($entities); + } catch (\Throwable $e) { + $this->logger->error( + \sprintf( + 'Unable to process collected product variants data. Event type: "%s", ids: "%s"', + $eventType ?? '', + \implode(',', \array_map(function (Entity $entity) { + return $entity->getEntityId(); + }, $entities ?? [])) + ), + ['exception' => $e] + ); + } + } +} diff --git a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/PublishProductVariantsConsumer.php b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/PublishProductVariantsConsumer.php new file mode 100644 index 000000000..bf6b8671e --- /dev/null +++ b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/PublishProductVariantsConsumer.php @@ -0,0 +1,118 @@ +logger = $logger; + $this->fetchProductVariants = $fetchProductVariants; + $this->variantService = $variantService; + $this->importVariantsRequestInterfaceFactory = $importVariantsRequestInterfaceFactory; + $this->productVariantImportMapper = $productVariantImportMapper; + } + + /** + * @inheritdoc + */ + public function execute(array $entities, string $scope = null): void + { + $variantsData = $this->fetchProductVariants->execute($entities); + $variantsImportData = []; + foreach ($variantsData as $variantData) { + $variantsImportData[] = $this->buildVariantImportObj($variantData); + } + if (!empty($variantsImportData)) { + $this->importVariants($variantsImportData); + } + } + + /** + * @param array $variantsData + * @return ProductVariantImportInterface + */ + private function buildVariantImportObj(array $variantsData): ProductVariantImportInterface + { + return $this->productVariantImportMapper->setData( + [ + 'id' => $variantsData['id'], + 'option_values' => $variantsData['option_values'], + ] + )->build(); + } + + /** + * Import variants + * + * @param ProductVariantImportInterface[] $variants + * + * @return void + */ + private function importVariants(array $variants): void + { + $importVariantsRequest = $this->importVariantsRequestInterfaceFactory->create(); + $importVariantsRequest->setVariants($variants); + + try { + $importResult = $this->variantService->ImportProductVariants($importVariantsRequest); + if ($importResult->getStatus() === false) { + $this->logger->error(sprintf('Product variants import failed: "%s"', $importResult->getMessage())); + } + } catch (\Throwable $e) { + $this->logger->critical(sprintf('Exception while publishing product variants: "%s"', $e)); + } + } +} diff --git a/app/code/Magento/CatalogMessageBroker/etc/communication.xml b/app/code/Magento/CatalogMessageBroker/etc/communication.xml index 5acf3f9ac..ddc1f8466 100644 --- a/app/code/Magento/CatalogMessageBroker/etc/communication.xml +++ b/app/code/Magento/CatalogMessageBroker/etc/communication.xml @@ -8,5 +8,6 @@ + diff --git a/app/code/Magento/CatalogMessageBroker/etc/di.xml b/app/code/Magento/CatalogMessageBroker/etc/di.xml index d1dea4652..9b33f94a6 100644 --- a/app/code/Magento/CatalogMessageBroker/etc/di.xml +++ b/app/code/Magento/CatalogMessageBroker/etc/di.xml @@ -7,6 +7,7 @@ --> + @@ -45,6 +46,12 @@ Magento\CatalogMessageBroker\Model\MessageBus\Product\DeleteProductsConsumer + + Magento\CatalogMessageBroker\Model\MessageBus\ProductVariants\PublishProductVariantsConsumer + + + Magento\CatalogMessageBroker\Model\MessageBus\ProductVariants\DeleteProductVariantsConsumer + diff --git a/app/code/Magento/CatalogMessageBroker/etc/queue_consumer.xml b/app/code/Magento/CatalogMessageBroker/etc/queue_consumer.xml index 686181a95..14059af0d 100644 --- a/app/code/Magento/CatalogMessageBroker/etc/queue_consumer.xml +++ b/app/code/Magento/CatalogMessageBroker/etc/queue_consumer.xml @@ -7,5 +7,6 @@ --> + diff --git a/app/code/Magento/CatalogStorefront/Model/CatalogRepository.php b/app/code/Magento/CatalogStorefront/Model/CatalogRepository.php index 81bfe35a8..24d687f80 100644 --- a/app/code/Magento/CatalogStorefront/Model/CatalogRepository.php +++ b/app/code/Magento/CatalogStorefront/Model/CatalogRepository.php @@ -20,6 +20,7 @@ class CatalogRepository { protected const DELETE = 'delete'; + protected const DELETE_BY_QUERY = 'delete_by_query'; protected const SAVE = 'save'; protected const UPDATE = 'update'; @@ -74,6 +75,7 @@ public function saveToStorage(array $dataPerType): void foreach ($dataPerStore as $storeCode => $data) { $sourceName = $this->storageState->getCurrentDataSourceName([$storeCode, $entityType]); $this->deleteEntities($data[self::DELETE] ?? [], $sourceName, $entityType); + $this->deleteEntitiesByQuery($data[self::DELETE_BY_QUERY] ?? [], $sourceName, $entityType); $this->saveEntities($data[self::SAVE] ?? [], $sourceName, $entityType); $this->updateEntities($data[self::UPDATE] ?? [], $sourceName, $entityType); } @@ -107,6 +109,34 @@ private function deleteEntities(array $data, string $sourceName, string $entityT $this->storageWriteSource->bulkDelete($sourceName, $entityType, $data); } + /** + * Delete bulk of entities by data, source name and entity type + * + * @param array $data + * @param string $sourceName + * @param string $entityType + * @return void + * @throws BulkException + */ + private function deleteEntitiesByQuery(array $data, string $sourceName, string $entityType): void + { + if (!$data) { + return; + } + if (!$this->storageSchemaManager->existsDataSource($sourceName)) { + $this->logger->debug( + \sprintf('Cannot delete entities "%s" by query: Index "%s" does not exist', \implode(',', $data), $sourceName) + ); + return; + } + + $this->logger->debug( + \sprintf('Delete from storage "%s" %s record(s)', $sourceName, count($data)), + ['verbose' => $data] + ); + $this->storageWriteSource->deleteByQuery($sourceName, $entityType, $data); + } + /** * Save bulk of entities by data, source name and entity type * diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Client/CommandInterface.php b/app/code/Magento/CatalogStorefront/Model/Storage/Client/CommandInterface.php index 53a849b92..bab4f6895 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Client/CommandInterface.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Client/CommandInterface.php @@ -59,4 +59,14 @@ public function bulkUpdate(string $dataSourceName, string $entityName, array $en * @return void */ public function bulkDelete(string $dataSourceName, string $entityName, array $ids): void; + + /** + * Performs delete by query. + * + * @param string $dataSourceName + * @param string $entityName + * @param array $entries + * @throws BulkException + */ + public function deleteByQuery(string $dataSourceName, string $entityName, array $entries): void; } diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Client/Config/ProductVariant.php b/app/code/Magento/CatalogStorefront/Model/Storage/Client/Config/ProductVariant.php new file mode 100644 index 000000000..c9180ef73 --- /dev/null +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Client/Config/ProductVariant.php @@ -0,0 +1,60 @@ + [ + [ + 'default_mapping' => [ + 'match' => '*', + 'match_mapping_type' => '*', + 'mapping' => [ + 'index' => false, + ], + ], + ] + ], + 'properties' => [ + 'id' => [ + 'type' => 'text' + ], + 'option_value' => [ + 'type' => 'text', + 'index' => false + ], + 'parent_id' => [ + 'type' => 'text', + 'index' => false + ], + 'product_id' => [ + 'type' => 'text', + 'index' => false + ], + ] + ]; + } +} diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchCommand.php b/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchCommand.php index db474d1c7..a4711a16e 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchCommand.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchCommand.php @@ -21,6 +21,7 @@ class ElasticsearchCommand implements CommandInterface private const BULK_ACTION_INDEX = 'index'; private const BULK_ACTION_CREATE = 'create'; private const BULK_ACTION_DELETE = 'delete'; + private const ACTION_DELETE_BY_QUERY = 'delete_by_query'; private const BULK_ACTION_UPDATE = 'update'; /**#@-*/ @@ -135,6 +136,10 @@ private function getDocsArrayInBulkIndexFormat( '_type' => $entityName, '_index' => $indexName ]; + if (isset($document['_id'])) { + $metaInfo['_id'] = $document['_id']; + unset($document['_id']); + } if (isset($document['parent_id']['parent'])) { $metaInfo['routing'] = $document['parent_id']['parent']; } @@ -152,6 +157,40 @@ private function getDocsArrayInBulkIndexFormat( return $bulkArray; } + /** + * Reformat documents array to delete by query format. + * + * todo: Improve this query for efficiency. + * + * @param string $indexName + * @param string $entityName + * @param array $documents + * @return array + */ + private function getDocsArrayInDeleteByQueryFormat( + string $indexName, + string $entityName, + array $documents + ): array { + $array = [ + 'index' => $indexName, + 'type' => $entityName, + 'body' => [ + 'min_score' => '1' + ], + 'refresh' => false, + ]; + foreach ($documents as $document) { + foreach ($document as $key => $value) { + $array['body']['query']['bool']['must'][] = [ + 'match' => [$key => $value] + ]; + } + } + + return $array; + } + /** * Handle error on Bulk insert * @@ -215,4 +254,35 @@ function ($id) { ); } } + + /** + * @inheritdoc + * + * @throws BulkException + */ + public function deleteByQuery(string $dataSourceName, string $entityName, array $entries): void + { + $query = $this->getDocsArrayInDeleteByQueryFormat( + $dataSourceName, + $entityName, + $entries + ); + try { + $result = $this->getConnection()->deleteByQuery($query); + $error = $result['errors'] ?? false; + if ($error) { + $this->handleBulkError($result['items'] ?? [], self::ACTION_DELETE_BY_QUERY); + } + } catch (\Throwable $throwable) { + throw new BulkException( + __( + 'Error occurred while deleting by query from "%1" index. Entity data: "%2". Error: %3', + $dataSourceName, + $entries, + $throwable->getMessage() + ), + $throwable + ); + } + } } diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/State.php b/app/code/Magento/CatalogStorefront/Model/Storage/State.php index 80c18230f..0aac4df09 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/State.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/State.php @@ -40,6 +40,7 @@ public function getAliasName(): string /** * Get current data source name of storage taking into account version of the data source. + * todo: adapt to work without store_code? * * @param array $scopes * @return string diff --git a/app/code/Magento/CatalogStorefront/Model/VariantService.php b/app/code/Magento/CatalogStorefront/Model/VariantService.php new file mode 100644 index 000000000..bb7bbc3e1 --- /dev/null +++ b/app/code/Magento/CatalogStorefront/Model/VariantService.php @@ -0,0 +1,173 @@ +variantArrayMapper = $variantArrayMapper; + $this->importVariantsResponseFactory = $importVariantsResponseFactory; + $this->logger = $logger; + $this->catalogRepository = $catalogRepository; + $this->deleteVariantsResponseFactory = $deleteVariantsResponseFactory; + } + + /** + * Import requested variants in storage + * + * @param ImportVariantsRequestInterface $request + * @return ImportVariantsResponseInterface + */ + public function ImportProductVariants(ImportVariantsRequestInterface $request): ImportVariantsResponseInterface + { + try { + $storeCode = 'default'; //todo: temporary solution. Remove store code or infer the default somehow. + + $variantsInElasticFormat = []; + foreach ($request->getVariants() as $variantData) { + $optionValues = $variantData->getOptionValues(); + $id = $variantData->getId(); + $explodedId = explode('/', $id); + $parentId = $explodedId[1]; + $childId = $explodedId[2]; + foreach ($optionValues as $optionValue) { + preg_match('/(?<=\:)(.*)(?=\/)/', $optionValue, $match); + $attrCode = $match[0]; + $variant = [ + '_id' => $id . '/' . $attrCode, + 'id' => $id, + 'option_value' => $optionValue, + 'product_id' => $childId, + 'parent_id' => $parentId + ]; + $variantsInElasticFormat['product_variant'][$storeCode]['save'][] = $variant; + } + } + + $this->catalogRepository->saveToStorage($variantsInElasticFormat); + $importVariantsResponse = $this->importVariantsResponseFactory->create(); + $importVariantsResponse->setMessage('Records imported successfully'); + $importVariantsResponse->setStatus(true); + + return $importVariantsResponse; + } catch (\Exception $e) { + $message = 'Cannot process product variants import: ' . $e->getMessage(); + $this->logger->error($message, ['exception' => $e]); + $importCategoriesResponse = $this->importVariantsResponseFactory->create(); + $importCategoriesResponse->setMessage($message); + $importCategoriesResponse->setStatus(false); + return $importCategoriesResponse; + } + } + + /** + * Delete product variants from storage. + * + * @param DeleteVariantsRequestInterface $request + * @return DeleteVariantsResponseInterface + */ + public function DeleteProductVariants(DeleteVariantsRequestInterface $request): DeleteVariantsResponseInterface + { + $decodedIds = \array_map(function ($id) { + return ['id' => $id]; + }, $request->getId()); + $storeId = 'default'; + + $variantsInElasticFormat = [ + 'product_variant' => [ + $storeId => [ + 'delete_by_query' => $decodedIds + ] + ] + ]; + + $deleteVariantsResponse = $this->deleteVariantsResponseFactory->create(); + try { + $this->catalogRepository->saveToStorage($variantsInElasticFormat); + $deleteVariantsResponse->setMessage('Product variants were removed successfully'); + $deleteVariantsResponse->setStatus(true); + } catch (\Throwable $e) { + $message = 'Unable to delete product variants'; + $this->logger->error($message, ['exception' => $e]); + $deleteVariantsResponse->setMessage($message); + $deleteVariantsResponse->setStatus(false); + } + + return $deleteVariantsResponse; + } + + public function GetProductVariants(ProductVariantRequestInterface $request): ProductVariantResponseInterface + { + // TODO: Implement GetProductVariants() method. + } + + public function GetVariantsMatch(OptionSelectionRequestInterface $request): ProductVariantResponseInterface + { + // TODO: Implement GetVariantsMatch() method. + } +} diff --git a/app/code/Magento/CatalogStorefront/etc/di.xml b/app/code/Magento/CatalogStorefront/etc/di.xml index 0b1276769..b497f8e84 100644 --- a/app/code/Magento/CatalogStorefront/etc/di.xml +++ b/app/code/Magento/CatalogStorefront/etc/di.xml @@ -13,12 +13,15 @@ + + Magento\CatalogStorefront\Model\Storage\Client\Config\Product Magento\CatalogStorefront\Model\Storage\Client\Config\Category + Magento\CatalogStorefront\Model\Storage\Client\Config\ProductVariant diff --git a/dev/tests/integration/framework/Magento/TestFramework/Workaround/ConsumerInvoker.php b/dev/tests/integration/framework/Magento/TestFramework/Workaround/ConsumerInvoker.php index eafb86cc4..0d3929e25 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/Workaround/ConsumerInvoker.php +++ b/dev/tests/integration/framework/Magento/TestFramework/Workaround/ConsumerInvoker.php @@ -26,6 +26,7 @@ class ConsumerInvoker 'storefront.catalog.category.update', 'storefront.catalog.product.update', 'catalog.product.export.consumer', + 'catalog.product.variants.export.consumer', 'catalog.category.export.consumer', ]; From 239f3e441265c7a913578a3b554bdab37c3d84d2 Mon Sep 17 00:00:00 2001 From: jekabs Date: Thu, 29 Oct 2020 14:57:10 +0200 Subject: [PATCH 03/23] Product variants -Modified GetProductVariants and DeleteProductVariants to the VariantService --- .../Model/FetchProductVariants.php | 7 +- .../ProductVariantsDataProvider.php | 86 ++++++++++++ .../Storage/Client/Config/ProductVariant.php | 1 - .../Storage/Client/ElasticsearchQuery.php | 47 +++++-- .../Model/Storage/Client/QueryInterface.php | 18 +++ .../Model/Storage/Data/Document.php | 2 +- .../Model/Storage/Data/DocumentIterator.php | 7 +- .../Storage/Data/DocumentIteratorFactory.php | 2 +- .../Storage/Data/EntryIteratorInterface.php | 3 +- .../Data/SearchResultIteratorFactory.php | 56 ++++++++ .../CatalogStorefront/Model/Storage/State.php | 2 +- .../Model/VariantService.php | 125 +++++++++++++++--- 12 files changed, 316 insertions(+), 40 deletions(-) create mode 100644 app/code/Magento/CatalogStorefront/DataProvider/ProductVariantsDataProvider.php create mode 100644 app/code/Magento/CatalogStorefront/Model/Storage/Data/SearchResultIteratorFactory.php diff --git a/app/code/Magento/CatalogMessageBroker/Model/FetchProductVariants.php b/app/code/Magento/CatalogMessageBroker/Model/FetchProductVariants.php index 7a5c3a112..cdce9f8e1 100644 --- a/app/code/Magento/CatalogMessageBroker/Model/FetchProductVariants.php +++ b/app/code/Magento/CatalogMessageBroker/Model/FetchProductVariants.php @@ -20,7 +20,6 @@ class FetchProductVariants implements FetchProductVariantsInterface * Route to Export API product variants retrieval */ private const EXPORT_API_GET_VARIANTS = '/V1/catalog-export/product-variants'; - private const EXPORT_API_GET_VARIANTS_BY_PRODUCT_ID = '/V1/catalog-export/product-variants/product-ids'; /** * @var RestClient @@ -49,16 +48,18 @@ public function __construct( */ public function execute(array $entities): array { + $data = $this->prepareRequestData($entities); try { $variants = $this->restClient->get( self::EXPORT_API_GET_VARIANTS, - $this->prepareRequestData($entities) + $data ); + } catch (\Throwable $e) { $this->logger->error( \sprintf( 'Cannot load product variants via "%s" with ids "%s"', - self::EXPORT_API_GET_PRODUCTS, + self::EXPORT_API_GET_VARIANTS, \implode(',', \array_map(function (Entity $entity) { return $entity->getEntityId(); }, $entities)) diff --git a/app/code/Magento/CatalogStorefront/DataProvider/ProductVariantsDataProvider.php b/app/code/Magento/CatalogStorefront/DataProvider/ProductVariantsDataProvider.php new file mode 100644 index 000000000..f6ece4abe --- /dev/null +++ b/app/code/Magento/CatalogStorefront/DataProvider/ProductVariantsDataProvider.php @@ -0,0 +1,86 @@ +query = $query; + $this->storageState = $storageState; + $this->logger = $logger; + } + + /** + * Fetch product variants data from storage + * + * @param int $parentId + * @return array + * @throws RuntimeException + * @throws \Throwable + */ + public function fetchByProductId(int $parentId): array + { + // todo: Adapt to work without store code + $storageName = $this->storageState->getCurrentDataSourceName([VariantService::EMPTY_STORE_VIEW, ProductVariant::ENTITY_NAME]); + try { + $entities = $this->query->searchEntries( + $storageName, + ProductVariant::ENTITY_NAME, + ['parent_id' => $parentId] + ); + } catch (NotFoundException $notFoundException) { + $this->logger->error( + \sprintf( + 'Cannot find product variants for product id "%s"', + $parentId, + ), + ['exception' => $notFoundException] + ); + return []; + } catch (\Throwable $e) { + $this->logger->error($e); + throw $e; + } + return $entities->toArray(false); + } +} diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Client/Config/ProductVariant.php b/app/code/Magento/CatalogStorefront/Model/Storage/Client/Config/ProductVariant.php index c9180ef73..11de10b3e 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Client/Config/ProductVariant.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Client/Config/ProductVariant.php @@ -48,7 +48,6 @@ public function getSettings() : array ], 'parent_id' => [ 'type' => 'text', - 'index' => false ], 'product_id' => [ 'type' => 'text', diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchQuery.php b/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchQuery.php index f1b0170fd..1fdc76d5c 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchQuery.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchQuery.php @@ -3,7 +3,6 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ - declare(strict_types=1); namespace Magento\CatalogStorefront\Model\Storage\Client; @@ -12,6 +11,7 @@ use Magento\CatalogStorefront\Model\Storage\Data\DocumentIteratorFactory; use Magento\CatalogStorefront\Model\Storage\Data\EntryInterface; use Magento\CatalogStorefront\Model\Storage\Data\EntryIteratorInterface; +use Magento\CatalogStorefront\Model\Storage\Data\SearchResultIteratorFactory; use Magento\Framework\Exception\NotFoundException; use Magento\Framework\Exception\RuntimeException; use Psr\Log\LoggerInterface; @@ -21,11 +21,6 @@ */ class ElasticsearchQuery implements QueryInterface { - /** - * @var Config - */ - private $config; - /** * @var ConnectionPull */ @@ -41,6 +36,11 @@ class ElasticsearchQuery implements QueryInterface */ private $documentIteratorFactory; + /** + * @var SearchResultIteratorFactory + */ + private $searchResultIteratorFactory; + /** * @var LoggerInterface */ @@ -49,22 +49,22 @@ class ElasticsearchQuery implements QueryInterface /** * Initialize Elasticsearch Client * - * @param Config $config * @param ConnectionPull $connectionPull * @param DocumentFactory $documentFactory * @param DocumentIteratorFactory $documentIteratorFactory + * @param SearchResultIteratorFactory $searchResultIteratorFactory * @param LoggerInterface $logger */ public function __construct( - Config $config, ConnectionPull $connectionPull, DocumentFactory $documentFactory, DocumentIteratorFactory $documentIteratorFactory, + SearchResultIteratorFactory $searchResultIteratorFactory, LoggerInterface $logger ) { - $this->config = $config; $this->documentFactory = $documentFactory; $this->documentIteratorFactory = $documentIteratorFactory; + $this->searchResultIteratorFactory = $searchResultIteratorFactory; $this->connectionPull = $connectionPull; $this->logger = $logger; } @@ -92,6 +92,33 @@ public function getEntry(string $indexName, string $entityName, int $id, array $ return $this->documentFactory->create($result); } + /** + * @inheritdoc + */ + public function searchEntries(string $indexName, string $entityName, array $searchBody): EntryIteratorInterface + { + $query = [ + 'index' => $indexName, + 'type' => $entityName, + ]; + + foreach ($searchBody as $key => $value) { + $query['body']['query']['bool']['must'][]['match'][$key] = $value; + } + + try { + $result = $this->connectionPull->getConnection()->search($query); + } catch (\Throwable $throwable) { + throw new RuntimeException( + __("Storage error: {$throwable->getMessage()} Query was:" . \json_encode($query)), + $throwable + ); + } + $this->checkErrors($result, $indexName); + + return $this->searchResultIteratorFactory->create($result); + } + /** * @inheritdoc */ @@ -127,7 +154,7 @@ public function getEntries(string $indexName, string $entityName, array $ids, ar * @param string $indexName * @throws NotFoundException */ - private function checkErrors(array $result, string $indexName) + private function checkErrors(array $result, string $indexName): void { $errors = []; $notFound = []; diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Client/QueryInterface.php b/app/code/Magento/CatalogStorefront/Model/Storage/Client/QueryInterface.php index d50efca87..ac781e2b2 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Client/QueryInterface.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Client/QueryInterface.php @@ -57,4 +57,22 @@ public function getEntries( array $ids, array $fields ): EntryIteratorInterface; + + /** + * Search entries by specified search arguments. + * Search works using the "must match" logic. + * + * $searchBody contains "search field" -> "search value". + * "search field" must be indexed. + * + * @param string $indexName + * @param string $entityName + * @param array $searchBody + * + * @return EntryIteratorInterface + * + * @throws NotFoundException + * @throws RuntimeException + */ + public function searchEntries(string $indexName, string $entityName, array $searchBody): EntryIteratorInterface; } diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Data/Document.php b/app/code/Magento/CatalogStorefront/Model/Storage/Data/Document.php index 38851648c..c96c68d60 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Data/Document.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Data/Document.php @@ -25,7 +25,7 @@ class Document implements EntryInterface public function __construct(array $data) { $this->data = $data['_source'] ?? []; - $this->data['id'] = (string)$data['_id']; + $this->data['id'] = $this->data['id'] ?? (string)$data['_id']; } /** diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Data/DocumentIterator.php b/app/code/Magento/CatalogStorefront/Model/Storage/Data/DocumentIterator.php index da096d6d9..bd2ef6988 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Data/DocumentIterator.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Data/DocumentIterator.php @@ -69,12 +69,13 @@ public function current(): EntryInterface /** * @inheritdoc */ - public function toArray(): array + public function toArray(bool $sortById = true): array { $data = []; reset($this->documents); - foreach ($this->documents as $doc) { - $data[$doc->getId()] = $doc->getData(); + foreach ($this->documents as $docKey => $doc) { + $id = $sortById ? $doc->getId() : $docKey; + $data[$id] = $doc->getData(); } return $data; } diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Data/DocumentIteratorFactory.php b/app/code/Magento/CatalogStorefront/Model/Storage/Data/DocumentIteratorFactory.php index 5a460140e..4f5ce830b 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Data/DocumentIteratorFactory.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Data/DocumentIteratorFactory.php @@ -54,7 +54,7 @@ public function create(array $ids, array $data = []): DocumentIterator if (isset($item['found']) && $item['found'] === false) { continue; } - $tmp[(int)$item['_id']] = $this->documentFactory->create($item); + $tmp[$item['_id']] = $this->documentFactory->create($item); } foreach ($ids as $id) { diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Data/EntryIteratorInterface.php b/app/code/Magento/CatalogStorefront/Model/Storage/Data/EntryIteratorInterface.php index 405eb3203..0c78cf558 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Data/EntryIteratorInterface.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Data/EntryIteratorInterface.php @@ -23,7 +23,8 @@ public function current(): EntryInterface; /** * Convert data to array. * + * @param bool $sortById * @return array */ - public function toArray(): array; + public function toArray(bool $sortById = true): array; } diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Data/SearchResultIteratorFactory.php b/app/code/Magento/CatalogStorefront/Model/Storage/Data/SearchResultIteratorFactory.php new file mode 100644 index 000000000..a70245337 --- /dev/null +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Data/SearchResultIteratorFactory.php @@ -0,0 +1,56 @@ +objectManager = $objectManager; + $this->documentFactory = $documentFactory; + } + + /** + * Create class instance with specified parameters + * + * @param array $result + * + * @return DocumentIterator + */ + public function create(array $result): DocumentIterator + { + $documents = []; + + foreach ($result['hits']['hits'] as $item) { + $documents[$item['_id']] = $this->documentFactory->create($item); + } + + return $this->objectManager->create(DocumentIterator::class, ['documents' => $documents]); + } +} diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/State.php b/app/code/Magento/CatalogStorefront/Model/Storage/State.php index 0aac4df09..813084a12 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/State.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/State.php @@ -40,7 +40,7 @@ public function getAliasName(): string /** * Get current data source name of storage taking into account version of the data source. - * todo: adapt to work without store_code? + * todo: Adapt to work without store code * * @param array $scopes * @return string diff --git a/app/code/Magento/CatalogStorefront/Model/VariantService.php b/app/code/Magento/CatalogStorefront/Model/VariantService.php index bb7bbc3e1..be9289136 100644 --- a/app/code/Magento/CatalogStorefront/Model/VariantService.php +++ b/app/code/Magento/CatalogStorefront/Model/VariantService.php @@ -7,6 +7,7 @@ namespace Magento\CatalogStorefront\Model; +use Magento\CatalogStorefront\DataProvider\ProductVariantsDataProvider; use Magento\CatalogStorefrontApi\Api\Data\DeleteVariantsRequestInterface; use Magento\CatalogStorefrontApi\Api\Data\DeleteVariantsResponseFactory; use Magento\CatalogStorefrontApi\Api\Data\DeleteVariantsResponseInterface; @@ -14,10 +15,13 @@ use Magento\CatalogStorefrontApi\Api\Data\ImportVariantsResponseFactory; use Magento\CatalogStorefrontApi\Api\Data\ImportVariantsResponseInterface; use Magento\CatalogStorefrontApi\Api\Data\OptionSelectionRequestInterface; -use Magento\CatalogStorefrontApi\Api\Data\ProductVariantArrayMapper; +use Magento\CatalogStorefrontApi\Api\Data\ProductsGetRequestInterfaceFactory; +use Magento\CatalogStorefrontApi\Api\Data\ProductVariantMapper; use Magento\CatalogStorefrontApi\Api\Data\ProductVariantRequestInterface; +use Magento\CatalogStorefrontApi\Api\Data\ProductVariantResponse; use Magento\CatalogStorefrontApi\Api\Data\ProductVariantResponseInterface; use Magento\CatalogStorefrontApi\Api\VariantServiceServerInterface; +use Magento\Framework\Exception\RuntimeException; use Psr\Log\LoggerInterface; /** @@ -31,14 +35,20 @@ class VariantService implements VariantServiceServerInterface { /** - * @var LoggerInterface + * Temporary store placeholder + * todo: Adapt to work without store code and remove this constant */ - private $logger; + public const EMPTY_STORE_VIEW = ''; + + /** + * Product enabled status. + */ + private const PRODUCT_STATUS_ENABLED = 'Enabled'; /** - * @var ProductVariantArrayMapper + * @var LoggerInterface */ - private $variantArrayMapper; + private $logger; /** * @var ImportVariantsResponseFactory @@ -56,25 +66,53 @@ class VariantService implements VariantServiceServerInterface private $deleteVariantsResponseFactory; /** - * @SuppressWarnings(PHPMD.ExcessiveParameterList) - * @param ProductVariantArrayMapper $variantArrayMapper + * @var ProductVariantsDataProvider + */ + private $productVariantsDataProvider; + + /** + * @var ProductVariantMapper + */ + private $productVariantMapper; + + /** + * @var CatalogService + */ + private $catalogService; + + /** + * @var ProductsGetRequestInterfaceFactory + */ + private $productsGetRequestInterfaceFactory; + + /** * @param ImportVariantsResponseFactory $importVariantsResponseFactory * @param DeleteVariantsResponseFactory $deleteVariantsResponseFactory * @param LoggerInterface $logger * @param CatalogRepository $catalogRepository + * @param ProductVariantsDataProvider $productVariantsDataProvider + * @param ProductVariantMapper $productVariantMapper + * @param CatalogService $catalogService + * @param ProductsGetRequestInterfaceFactory $productsGetRequestInterfaceFactory */ public function __construct( - ProductVariantArrayMapper $variantArrayMapper, ImportVariantsResponseFactory $importVariantsResponseFactory, DeleteVariantsResponseFactory $deleteVariantsResponseFactory, LoggerInterface $logger, - CatalogRepository $catalogRepository + CatalogRepository $catalogRepository, + ProductVariantsDataProvider $productVariantsDataProvider, + ProductVariantMapper $productVariantMapper, + CatalogService $catalogService, + ProductsGetRequestInterfaceFactory $productsGetRequestInterfaceFactory ) { - $this->variantArrayMapper = $variantArrayMapper; $this->importVariantsResponseFactory = $importVariantsResponseFactory; $this->logger = $logger; $this->catalogRepository = $catalogRepository; $this->deleteVariantsResponseFactory = $deleteVariantsResponseFactory; + $this->productVariantsDataProvider = $productVariantsDataProvider; + $this->productVariantMapper = $productVariantMapper; + $this->catalogService = $catalogService; + $this->productsGetRequestInterfaceFactory = $productsGetRequestInterfaceFactory; } /** @@ -86,8 +124,6 @@ public function __construct( public function ImportProductVariants(ImportVariantsRequestInterface $request): ImportVariantsResponseInterface { try { - $storeCode = 'default'; //todo: temporary solution. Remove store code or infer the default somehow. - $variantsInElasticFormat = []; foreach ($request->getVariants() as $variantData) { $optionValues = $variantData->getOptionValues(); @@ -105,7 +141,8 @@ public function ImportProductVariants(ImportVariantsRequestInterface $request): 'product_id' => $childId, 'parent_id' => $parentId ]; - $variantsInElasticFormat['product_variant'][$storeCode]['save'][] = $variant; + //todo: Adapt to work without store code + $variantsInElasticFormat['product_variant'][self::EMPTY_STORE_VIEW]['save'][] = $variant; } } @@ -133,15 +170,14 @@ public function ImportProductVariants(ImportVariantsRequestInterface $request): */ public function DeleteProductVariants(DeleteVariantsRequestInterface $request): DeleteVariantsResponseInterface { - $decodedIds = \array_map(function ($id) { + $deleteFields = \array_map(function ($id) { return ['id' => $id]; }, $request->getId()); - $storeId = 'default'; $variantsInElasticFormat = [ 'product_variant' => [ - $storeId => [ - 'delete_by_query' => $decodedIds + self::EMPTY_STORE_VIEW => [ + 'delete_by_query' => $deleteFields ] ] ]; @@ -161,13 +197,64 @@ public function DeleteProductVariants(DeleteVariantsRequestInterface $request): return $deleteVariantsResponse; } + /** + * Get product variants from storage. + * Only variants whose corresponding products are 'enabled' and stored in storage are returned. + * + * @param ProductVariantRequestInterface $request + * @return ProductVariantResponseInterface + * @throws \InvalidArgumentException + * @throws RuntimeException + * @throws \Throwable + */ public function GetProductVariants(ProductVariantRequestInterface $request): ProductVariantResponseInterface { - // TODO: Implement GetProductVariants() method. + $productId = $request->getProductId(); + $store = $request->getStore(); + $rawVariants = $this->productVariantsDataProvider->fetchByProductId((int)$productId); + + //todo: add exception for empty response. + + $compositeVariants = []; + foreach ($rawVariants as $rawVariant) { + $compositeVariants[$rawVariant['id']]['id'] = $rawVariant['id']; + $compositeVariants[$rawVariant['id']]['option_values'][] = $rawVariant['option_value']; + $compositeVariants[$rawVariant['id']]['product_id'] = $rawVariant['product_id']; + } + + $productsGetRequest = $this->productsGetRequestInterfaceFactory->create(); + $productsGetRequest->setIds(\array_column($compositeVariants, 'product_id')); + $productsGetRequest->setStore($store); + $productsGetRequest->setAttributeCodes(["id", "status"]); + $catalogProducts = $this->catalogService->getProducts($productsGetRequest)->getItems(); + + $activeProducts = []; + foreach ($catalogProducts as $product) { + if ($product->getStatus() === self::PRODUCT_STATUS_ENABLED) { + $activeProducts[$product->getId()] = $product->getId(); + } + } + + $variants = []; + foreach ($compositeVariants as $compositeVariant) { + if (isset($activeProducts[$compositeVariant['product_id']])) { + $variants[] = $this->productVariantMapper->setData($compositeVariant)->build(); + } + } + + $response = new ProductVariantResponse(); + $response->setMatchedVariants($variants); + return $response; } + /** + * TODO: Implement GetVariantsMatch() method. + * + * @param OptionSelectionRequestInterface $request + * @return ProductVariantResponseInterface + */ public function GetVariantsMatch(OptionSelectionRequestInterface $request): ProductVariantResponseInterface { - // TODO: Implement GetVariantsMatch() method. + return new ProductVariantResponse(); } } From 209937dac970730a781dbac58ab84eccbef0bbb0 Mon Sep 17 00:00:00 2001 From: jekabs Date: Thu, 29 Oct 2020 16:12:40 +0200 Subject: [PATCH 04/23] Product variants -static fixes --- .../Model/FetchProductVariants.php | 1 - .../DeleteProductVariantsConsumer.php | 4 +++- .../PublishProductVariantsConsumer.php | 3 ++- .../CatalogStorefront/Model/CatalogRepository.php | 12 +++++++----- .../Model/Storage/Client/ElasticsearchCommand.php | 3 +-- .../CatalogStorefront/Model/Storage/State.php | 2 +- .../CatalogStorefront/Model/VariantService.php | 14 ++++++++------ 7 files changed, 22 insertions(+), 17 deletions(-) diff --git a/app/code/Magento/CatalogMessageBroker/Model/FetchProductVariants.php b/app/code/Magento/CatalogMessageBroker/Model/FetchProductVariants.php index cdce9f8e1..12cf583a3 100644 --- a/app/code/Magento/CatalogMessageBroker/Model/FetchProductVariants.php +++ b/app/code/Magento/CatalogMessageBroker/Model/FetchProductVariants.php @@ -76,7 +76,6 @@ public function execute(array $entities): array * Prepare client request data * * @param Entity[] $entities - * @param string $storeCode * * @return array */ diff --git a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/DeleteProductVariantsConsumer.php b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/DeleteProductVariantsConsumer.php index a0aea13ff..fabf96027 100644 --- a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/DeleteProductVariantsConsumer.php +++ b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/DeleteProductVariantsConsumer.php @@ -61,7 +61,9 @@ public function execute(array $entities, string $scope = null): void try { $importResult = $this->variantsServer->DeleteProductVariants($deleteVariantsRequest); if ($importResult->getStatus() === false) { - $this->logger->error(sprintf('Product variants deletion has failed: "%s"', $importResult->getMessage())); + $this->logger->error( + sprintf('Product variants deletion has failed: "%s"', $importResult->getMessage()) + ); } } catch (\Throwable $e) { $this->logger->critical(sprintf('Exception while deleting product variants: "%s"', $e)); diff --git a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/PublishProductVariantsConsumer.php b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/PublishProductVariantsConsumer.php index bf6b8671e..46e8bae73 100644 --- a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/PublishProductVariantsConsumer.php +++ b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/PublishProductVariantsConsumer.php @@ -81,6 +81,8 @@ public function execute(array $entities, string $scope = null): void } /** + * Build product variant import object + * * @param array $variantsData * @return ProductVariantImportInterface */ @@ -98,7 +100,6 @@ private function buildVariantImportObj(array $variantsData): ProductVariantImpor * Import variants * * @param ProductVariantImportInterface[] $variants - * * @return void */ private function importVariants(array $variants): void diff --git a/app/code/Magento/CatalogStorefront/Model/CatalogRepository.php b/app/code/Magento/CatalogStorefront/Model/CatalogRepository.php index 24d687f80..c1d455531 100644 --- a/app/code/Magento/CatalogStorefront/Model/CatalogRepository.php +++ b/app/code/Magento/CatalogStorefront/Model/CatalogRepository.php @@ -124,9 +124,11 @@ private function deleteEntitiesByQuery(array $data, string $sourceName, string $ return; } if (!$this->storageSchemaManager->existsDataSource($sourceName)) { - $this->logger->debug( - \sprintf('Cannot delete entities "%s" by query: Index "%s" does not exist', \implode(',', $data), $sourceName) - ); + $this->logger->debug(\sprintf( + 'Cannot delete entities "%s" by query: Index "%s" does not exist', + \implode(',', $data), + $sourceName + )); return; } @@ -143,9 +145,9 @@ private function deleteEntitiesByQuery(array $data, string $sourceName, string $ * @param array $data * @param string $sourceName * @param string $entityType - * @throws BulkException - * @throws CouldNotSaveException * @return void + * @throws CouldNotSaveException + * @throws BulkException */ private function saveEntities(array $data, string $sourceName, string $entityType): void { diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchCommand.php b/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchCommand.php index a4711a16e..c62dd79f4 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchCommand.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchCommand.php @@ -159,8 +159,7 @@ private function getDocsArrayInBulkIndexFormat( /** * Reformat documents array to delete by query format. - * - * todo: Improve this query for efficiency. + * TODO: Improve this query for efficiency. * * @param string $indexName * @param string $entityName diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/State.php b/app/code/Magento/CatalogStorefront/Model/Storage/State.php index 813084a12..2fb0bd312 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/State.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/State.php @@ -40,7 +40,7 @@ public function getAliasName(): string /** * Get current data source name of storage taking into account version of the data source. - * todo: Adapt to work without store code + * TODO: Adapt to work without store code * * @param array $scopes * @return string diff --git a/app/code/Magento/CatalogStorefront/Model/VariantService.php b/app/code/Magento/CatalogStorefront/Model/VariantService.php index be9289136..e27cc24fa 100644 --- a/app/code/Magento/CatalogStorefront/Model/VariantService.php +++ b/app/code/Magento/CatalogStorefront/Model/VariantService.php @@ -36,9 +36,9 @@ class VariantService implements VariantServiceServerInterface { /** * Temporary store placeholder - * todo: Adapt to work without store code and remove this constant + * TODO: Adapt to work without store code and remove this constant */ - public const EMPTY_STORE_VIEW = ''; + public const EMPTY_STORE_CODE = ''; /** * Product enabled status. @@ -141,8 +141,8 @@ public function ImportProductVariants(ImportVariantsRequestInterface $request): 'product_id' => $childId, 'parent_id' => $parentId ]; - //todo: Adapt to work without store code - $variantsInElasticFormat['product_variant'][self::EMPTY_STORE_VIEW]['save'][] = $variant; + //TODO: Adapt to work without store code + $variantsInElasticFormat['product_variant'][self::EMPTY_STORE_CODE]['save'][] = $variant; } } @@ -176,7 +176,8 @@ public function DeleteProductVariants(DeleteVariantsRequestInterface $request): $variantsInElasticFormat = [ 'product_variant' => [ - self::EMPTY_STORE_VIEW => [ + //TODO: Adapt to work without store code + self::EMPTY_STORE_CODE => [ 'delete_by_query' => $deleteFields ] ] @@ -248,10 +249,11 @@ public function GetProductVariants(ProductVariantRequestInterface $request): Pro } /** - * TODO: Implement GetVariantsMatch() method. + * TODO: Implement GetVariantsMatch() method and remove the warning suppression. * * @param OptionSelectionRequestInterface $request * @return ProductVariantResponseInterface + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function GetVariantsMatch(OptionSelectionRequestInterface $request): ProductVariantResponseInterface { From 6d573884d9a868d448233b40b953622c98211250 Mon Sep 17 00:00:00 2001 From: jekabs Date: Mon, 2 Nov 2020 16:10:28 +0200 Subject: [PATCH 05/23] Product variants -Added test -Improved elasticsearch deleteByQuery -Added some exceptions for empty variant response --- .../ProductVariantsDataProvider.php | 4 +- .../Model/CatalogRepository.php | 3 +- .../Model/Storage/Client/CommandInterface.php | 2 +- .../Storage/Client/Config/ProductVariant.php | 2 +- .../Storage/Client/ElasticsearchCommand.php | 28 +-- .../Model/VariantService.php | 21 +- .../Test/Api/StorefrontTestsAbstract.php | 72 ++++-- .../Model/MessageBus/ProductVariantsTest.php | 205 ++++++++++++++++++ 8 files changed, 290 insertions(+), 47 deletions(-) create mode 100644 dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php diff --git a/app/code/Magento/CatalogStorefront/DataProvider/ProductVariantsDataProvider.php b/app/code/Magento/CatalogStorefront/DataProvider/ProductVariantsDataProvider.php index f6ece4abe..c1fda07e8 100644 --- a/app/code/Magento/CatalogStorefront/DataProvider/ProductVariantsDataProvider.php +++ b/app/code/Magento/CatalogStorefront/DataProvider/ProductVariantsDataProvider.php @@ -61,7 +61,9 @@ public function __construct( public function fetchByProductId(int $parentId): array { // todo: Adapt to work without store code - $storageName = $this->storageState->getCurrentDataSourceName([VariantService::EMPTY_STORE_VIEW, ProductVariant::ENTITY_NAME]); + $storageName = $this->storageState->getCurrentDataSourceName( + [VariantService::EMPTY_STORE_CODE, ProductVariant::ENTITY_NAME] + ); try { $entities = $this->query->searchEntries( $storageName, diff --git a/app/code/Magento/CatalogStorefront/Model/CatalogRepository.php b/app/code/Magento/CatalogStorefront/Model/CatalogRepository.php index c1d455531..99ae5c8c6 100644 --- a/app/code/Magento/CatalogStorefront/Model/CatalogRepository.php +++ b/app/code/Magento/CatalogStorefront/Model/CatalogRepository.php @@ -68,6 +68,7 @@ public function __construct( * @param array $dataPerType * @throws BulkException * @throws CouldNotSaveException + * @throws \RuntimeException */ public function saveToStorage(array $dataPerType): void { @@ -116,7 +117,7 @@ private function deleteEntities(array $data, string $sourceName, string $entityT * @param string $sourceName * @param string $entityType * @return void - * @throws BulkException + * @throws \RuntimeException */ private function deleteEntitiesByQuery(array $data, string $sourceName, string $entityType): void { diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Client/CommandInterface.php b/app/code/Magento/CatalogStorefront/Model/Storage/Client/CommandInterface.php index bab4f6895..f2540179c 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Client/CommandInterface.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Client/CommandInterface.php @@ -66,7 +66,7 @@ public function bulkDelete(string $dataSourceName, string $entityName, array $id * @param string $dataSourceName * @param string $entityName * @param array $entries - * @throws BulkException + * @throws \RuntimeException */ public function deleteByQuery(string $dataSourceName, string $entityName, array $entries): void; } diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Client/Config/ProductVariant.php b/app/code/Magento/CatalogStorefront/Model/Storage/Client/Config/ProductVariant.php index 11de10b3e..212f3eb6c 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Client/Config/ProductVariant.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Client/Config/ProductVariant.php @@ -40,7 +40,7 @@ public function getSettings() : array ], 'properties' => [ 'id' => [ - 'type' => 'text' + 'type' => 'keyword' ], 'option_value' => [ 'type' => 'text', diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchCommand.php b/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchCommand.php index c62dd79f4..bc5d1fb6c 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchCommand.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchCommand.php @@ -21,7 +21,6 @@ class ElasticsearchCommand implements CommandInterface private const BULK_ACTION_INDEX = 'index'; private const BULK_ACTION_CREATE = 'create'; private const BULK_ACTION_DELETE = 'delete'; - private const ACTION_DELETE_BY_QUERY = 'delete_by_query'; private const BULK_ACTION_UPDATE = 'update'; /**#@-*/ @@ -159,7 +158,6 @@ private function getDocsArrayInBulkIndexFormat( /** * Reformat documents array to delete by query format. - * TODO: Improve this query for efficiency. * * @param string $indexName * @param string $entityName @@ -174,19 +172,14 @@ private function getDocsArrayInDeleteByQueryFormat( $array = [ 'index' => $indexName, 'type' => $entityName, - 'body' => [ - 'min_score' => '1' - ], - 'refresh' => false, - ]; + 'body' => [], + 'refresh' => false + ]; foreach ($documents as $document) { foreach ($document as $key => $value) { - $array['body']['query']['bool']['must'][] = [ - 'match' => [$key => $value] - ]; + $array['body']['query']['bool']['filter']['terms'][$key][] = $value; } } - return $array; } @@ -257,7 +250,7 @@ function ($id) { /** * @inheritdoc * - * @throws BulkException + * @throws \RuntimeException */ public function deleteByQuery(string $dataSourceName, string $entityName, array $entries): void { @@ -265,19 +258,16 @@ public function deleteByQuery(string $dataSourceName, string $entityName, array $dataSourceName, $entityName, $entries + // 'wait_for_completion' => true ); try { - $result = $this->getConnection()->deleteByQuery($query); - $error = $result['errors'] ?? false; - if ($error) { - $this->handleBulkError($result['items'] ?? [], self::ACTION_DELETE_BY_QUERY); - } + $this->getConnection()->deleteByQuery($query); } catch (\Throwable $throwable) { - throw new BulkException( + throw new \RuntimeException( __( 'Error occurred while deleting by query from "%1" index. Entity data: "%2". Error: %3', $dataSourceName, - $entries, + \json_encode($entries), $throwable->getMessage() ), $throwable diff --git a/app/code/Magento/CatalogStorefront/Model/VariantService.php b/app/code/Magento/CatalogStorefront/Model/VariantService.php index e27cc24fa..103e7a1c7 100644 --- a/app/code/Magento/CatalogStorefront/Model/VariantService.php +++ b/app/code/Magento/CatalogStorefront/Model/VariantService.php @@ -200,6 +200,7 @@ public function DeleteProductVariants(DeleteVariantsRequestInterface $request): /** * Get product variants from storage. + * * Only variants whose corresponding products are 'enabled' and stored in storage are returned. * * @param ProductVariantRequestInterface $request @@ -210,11 +211,18 @@ public function DeleteProductVariants(DeleteVariantsRequestInterface $request): */ public function GetProductVariants(ProductVariantRequestInterface $request): ProductVariantResponseInterface { - $productId = $request->getProductId(); + $productId = $request->getProductId(); //todo test with null here from test. $store = $request->getStore(); $rawVariants = $this->productVariantsDataProvider->fetchByProductId((int)$productId); - //todo: add exception for empty response. + if (empty($rawVariants)) { + throw new \InvalidArgumentException( + sprintf( + 'No products variants for product with id %s are found in catalog.', + $productId + ) + ); + } $compositeVariants = []; foreach ($rawVariants as $rawVariant) { @@ -243,6 +251,15 @@ public function GetProductVariants(ProductVariantRequestInterface $request): Pro } } + if (empty($variants)) { + throw new \InvalidArgumentException( + sprintf( + 'No valid products variants for product with id %s are found in catalog.', + $productId + ) + ); + } + $response = new ProductVariantResponse(); $response->setMatchedVariants($variants); return $response; diff --git a/app/code/Magento/CatalogStorefront/Test/Api/StorefrontTestsAbstract.php b/app/code/Magento/CatalogStorefront/Test/Api/StorefrontTestsAbstract.php index de31d879b..446f91ec1 100644 --- a/app/code/Magento/CatalogStorefront/Test/Api/StorefrontTestsAbstract.php +++ b/app/code/Magento/CatalogStorefront/Test/Api/StorefrontTestsAbstract.php @@ -11,6 +11,7 @@ use Magento\CatalogStorefront\Model\Storage\State; use Magento\Framework\App\ResourceConnection; use Magento\Indexer\Model\Indexer; +use Magento\Store\Model\StoreManagerInterface; use Magento\TestFramework\Helper\Bootstrap; use PHPUnit\Framework\TestCase; use Magento\TestFramework\Workaround\ConsumerInvoker; @@ -29,7 +30,8 @@ abstract class StorefrontTestsAbstract extends TestCase */ private const FEEDS = [ 'catalog_data_exporter_categories', - 'catalog_data_exporter_products' + 'catalog_data_exporter_products', + 'catalog_data_exporter_product_variants' ]; /** @@ -38,6 +40,7 @@ abstract class StorefrontTestsAbstract extends TestCase private const QUEUES = [ 'catalog.category.export.queue', 'catalog.product.export.queue', + 'catalog.product.variants.export.queue', 'storefront.catalog.product.connector', 'storefront.catalog.category.connector', ]; @@ -47,6 +50,21 @@ abstract class StorefrontTestsAbstract extends TestCase */ private $compareArraysRecursively; + /** + * @var DataDefinitionInterface + */ + private $dataDefinition; + + /** + * @var State + */ + private $storageState; + + /** + * @var StoreManagerInterface + */ + private $storeManager; + /** * @inheritdoc */ @@ -54,6 +72,9 @@ protected function setUp(): void { parent::setUp(); $this->compareArraysRecursively = Bootstrap::getObjectManager()->create(CompareArraysRecursively::class); + $this->dataDefinition = Bootstrap::getObjectManager()->get(DataDefinitionInterface::class); + $this->storageState = Bootstrap::getObjectManager()->get(State::class); + $this->storeManager = Bootstrap::getObjectManager()->get(StoreManagerInterface::class); } /** @@ -72,31 +93,36 @@ protected function tearDown(): void */ private function clearCatalogStorage(): void { - /** @var DataDefinitionInterface $dataDefinition */ - $dataDefinition = Bootstrap::getObjectManager()->get( - DataDefinitionInterface::class - ); - /** @var State $storageState */ - $storageState = Bootstrap::getObjectManager()->get( - State::class - ); - $entityTypes = ['category', 'product']; - /** @var \Magento\Store\Model\StoreManagerInterface $storeManager */ - $storeManager = Bootstrap::getObjectManager() - ->get(\Magento\Store\Model\StoreManagerInterface::class); - $availableStores = $storeManager->getStores(); + $entityTypes = ['category', 'product', 'product_variants']; + $availableStores = $this->storeManager->getStores(); + foreach ($entityTypes as $entityType) { - foreach ($availableStores as $store) { - try { - $sourceName = $storageState->getCurrentDataSourceName([$store->getCode(), $entityType]); - $dataDefinition->deleteDataSource($sourceName); - } catch (\Exception $e) { - // Do nothing if no source + if ($entityType === 'product_variants') { + $this->deleteDataSource('', $entityType); + } else { + foreach ($availableStores as $store) { + $this->deleteDataSource($store->getCode(), $entityType); } } } } + /** + * Delete data source + * + * @param string $scope + * @param string $entityType + */ + private function deleteDataSource(string $scope, string $entityType): void + { + try { + $sourceName = $this->storageState->getCurrentDataSourceName([$scope, $entityType]); + $this->dataDefinition->deleteDataSource($sourceName); + } catch (\Exception $e) { + // Do nothing if no source + } + } + /** * On each tear down we need to clean all feed data * @@ -176,7 +202,7 @@ private function isSoap(): bool * * @param array $consumers */ - public function runConsumers(array $consumers = []) : void + public function runConsumers(array $consumers = []): void { $consumerInvoker = Bootstrap::getObjectManager()->create(ConsumerInvoker::class); $consumerInvoker->invoke($consumers); @@ -189,10 +215,12 @@ public function runConsumers(array $consumers = []) : void */ private function resetIndexerToOnSave(): void { - $indexer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + $indexer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() ->get(Indexer::class); $indexer->load('catalog_data_exporter_products'); $indexer->setScheduled(false); + $indexer->load('catalog_data_exporter_product_variants'); + $indexer->setScheduled(false); } /** diff --git a/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php b/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php new file mode 100644 index 000000000..5d10dbb67 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php @@ -0,0 +1,205 @@ +productVariantsConsumer = Bootstrap::getObjectManager()->create(ProductVariantsConsumer::class); + $this->variantService = Bootstrap::getObjectManager()->create(VariantService::class); + $this->variantsGetRequestInterface = Bootstrap::getObjectManager()->create( + ProductVariantRequestInterface::class + ); + $this->messageBuilder = Bootstrap::getObjectManager()->create(ChangedEntitiesMessageBuilder::class); + $this->productVariantFeed = Bootstrap::getObjectManager()->get(FeedPool::class)->getFeed('variants'); + $this->productRepository = Bootstrap::getObjectManager()->create(ProductRepositoryInterface::class); + $this->responseArrayMapper = Bootstrap::getObjectManager()->create(ProductVariantResponseArrayMapper::class); + } + + /** + * Validate something + * @magentoApiDataFixture Magento/ConfigurableProduct/_files/configurable_products_with_two_attributes.php + * @magentoDbIsolation disabled + * @throws NoSuchEntityException + * @throws StateException + * @throws \Throwable + */ + public function testSaveAndDeleteProduct(): void + { + $configurable = $this->getProduct(self::CONFIGURABLE_SKU); + $configurableId = $configurable->getId(); + $simple1 = $this->getProduct(self::SIMPLE1_SKU); + $simple1Id = $simple1->getId(); + $simple2 = $this->getProduct(self::SIMPLE2_SKU); + $simple2Id = $simple2->getId(); + $entitiesData = [ + [ + 'entity_id' => \sprintf('configurable/%1$s/%2$s', $configurableId, $simple1Id) + ], + [ + 'entity_id' => \sprintf('configurable/%1$s/%2$s', $configurableId, $simple2Id) + ] + ]; + + $productVariantFeed = $this->productVariantFeed->getFeedByProductIds([$configurableId]); + $this->assertNotEmpty($productVariantFeed['feed']); + $this->assertCount(2, $productVariantFeed['feed']); + $expectedData = $this->formatFeedData($productVariantFeed['feed']); + + $updateMessage = $this->messageBuilder->build( + 'product_variants_updated', + $entitiesData + ); + $this->productVariantsConsumer->processMessage($updateMessage); + + $this->variantsGetRequestInterface->setProductId((string)$configurableId); + $this->variantsGetRequestInterface->setStore(self::STORE_CODE); + $response = $this->variantService->GetProductVariants($this->variantsGetRequestInterface); + $variants = $this->responseArrayMapper->convertToArray($response); + + $this->assertNotEmpty($variants); + $this->compare($expectedData, $variants['matched_variants']); + + $this->deleteProduct($configurable->getSku()); + $deletedFeed = $this->productVariantFeed->getDeletedByProductIds([$configurableId]); + $this->assertNotEmpty($deletedFeed); + + $deleteMessage = $this->messageBuilder->build( + 'product_variants_deleted', + $entitiesData + ); + $this->productVariantsConsumer->processMessage($deleteMessage); + //This sleep ensures that the elastic index has sufficient time to refresh + // after the records have been deleted by the _delete_by_query call. + //See https://www.elastic.co/guide/en/elasticsearch/reference/6.8/docs-refresh.html#docs-refresh + sleep(3); + + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage(sprintf(self::ERROR_MESSAGE, $configurableId)); + $this->variantService->GetProductVariants($this->variantsGetRequestInterface); + } + + /** + * @param array $feedData + * @return array|void + */ + private function formatFeedData(array $feedData) + { + try { + return \array_map(function (array $feedItem) { + $childId = \explode('/', $feedItem['id'])[2]; + $feedItem['product_id'] = $childId; + unset($feedItem['modifiedAt'], $feedItem['deleted']); + return $feedItem; + }, $feedData); + } catch (\Exception $e) { + $this->fail('Feed data did not match the expected format'); + } + } + + /** + * @param string $sku + * @return ProductInterface + * @throws NoSuchEntityException + */ + private function getProduct(string $sku): ProductInterface + { + try { + return $this->productRepository->get($sku); + } catch (NoSuchEntityException $e) { + throw new NoSuchEntityException(); + } + } + + /** + * @param string $sku + * @throws NoSuchEntityException + * @throws StateException + */ + private function deleteProduct(string $sku): void + { + try { + $registry = Bootstrap::getObjectManager()->get(Registry::class); + $registry->unregister('isSecureArea'); + $registry->register('isSecureArea', true); + $this->productRepository->deleteById($sku); + $registry->unregister('isSecureArea'); + $registry->register('isSecureArea', false); + } catch (NoSuchEntityException $e) { + throw new NoSuchEntityException(); + } + } +} From eed02bc72a7bbba648b81ab367a9e075fe67f0a2 Mon Sep 17 00:00:00 2001 From: jekabs Date: Tue, 3 Nov 2020 14:23:57 +0200 Subject: [PATCH 06/23] Product variants -Test fix --- .../Model/MessageBus/ProductVariantsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php b/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php index 5d10dbb67..1b28dfd84 100644 --- a/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php +++ b/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php @@ -162,7 +162,7 @@ private function formatFeedData(array $feedData) return \array_map(function (array $feedItem) { $childId = \explode('/', $feedItem['id'])[2]; $feedItem['product_id'] = $childId; - unset($feedItem['modifiedAt'], $feedItem['deleted']); + unset($feedItem['modifiedAt'], $feedItem['deleted'], $feedItem['parent_id']); return $feedItem; }, $feedData); } catch (\Exception $e) { From 4300f91e360236e2e535b3160f56c4218d0fea77 Mon Sep 17 00:00:00 2001 From: jekabs Date: Tue, 3 Nov 2020 15:32:58 +0200 Subject: [PATCH 07/23] Product variants -Removed old ConfigurableVariantsExtractor --- .../DataProvider/ColumnsDataMapper.php | 58 ---- .../Model/Plugin/StockStatusQuery.php | 68 ----- .../CatalogInventoryExtractor/composer.json | 1 - .../CatalogInventoryExtractor/etc/di.xml | 4 - .../CatalogInventoryExtractor/etc/module.xml | 1 - .../Model/ProductDataProcessor.php | 1 - .../DataProvider/AttributeOptionsProvider.php | 116 -------- .../ConfigurableAttributesProvider.php | 81 ------ .../ConfigurableOptionValuesBuilder.php | 114 -------- .../Attributes/ConfigurableOptionsBuilder.php | 140 ---------- .../Query/ProductVariantsBuilder.php | 84 ------ .../DataProvider/VariantsDataProvider.php | 259 ------------------ .../ConfigurableProductExtractor/LICENSE.txt | 48 ---- .../LICENSE_AFL.txt | 48 ---- .../ConfigurableProductExtractor/README.md | 3 - .../composer.json | 29 -- .../ConfigurableProductExtractor/etc/di.xml | 19 -- .../etc/module.xml | 16 -- .../registration.php | 9 - .../composer_root_modules_storefront_ce.txt | 1 - 20 files changed, 1100 deletions(-) delete mode 100644 app/code/Magento/CatalogExtractor/DataProvider/ColumnsDataMapper.php delete mode 100644 app/code/Magento/CatalogInventoryExtractor/Model/Plugin/StockStatusQuery.php delete mode 100644 app/code/Magento/ConfigurableProductExtractor/DataProvider/AttributeOptionsProvider.php delete mode 100644 app/code/Magento/ConfigurableProductExtractor/DataProvider/ConfigurableAttributesProvider.php delete mode 100644 app/code/Magento/ConfigurableProductExtractor/DataProvider/Query/Attributes/ConfigurableOptionValuesBuilder.php delete mode 100644 app/code/Magento/ConfigurableProductExtractor/DataProvider/Query/Attributes/ConfigurableOptionsBuilder.php delete mode 100644 app/code/Magento/ConfigurableProductExtractor/DataProvider/Query/ProductVariantsBuilder.php delete mode 100644 app/code/Magento/ConfigurableProductExtractor/DataProvider/VariantsDataProvider.php delete mode 100644 app/code/Magento/ConfigurableProductExtractor/LICENSE.txt delete mode 100644 app/code/Magento/ConfigurableProductExtractor/LICENSE_AFL.txt delete mode 100644 app/code/Magento/ConfigurableProductExtractor/README.md delete mode 100644 app/code/Magento/ConfigurableProductExtractor/composer.json delete mode 100644 app/code/Magento/ConfigurableProductExtractor/etc/di.xml delete mode 100644 app/code/Magento/ConfigurableProductExtractor/etc/module.xml delete mode 100644 app/code/Magento/ConfigurableProductExtractor/registration.php diff --git a/app/code/Magento/CatalogExtractor/DataProvider/ColumnsDataMapper.php b/app/code/Magento/CatalogExtractor/DataProvider/ColumnsDataMapper.php deleted file mode 100644 index 5ad5fc714..000000000 --- a/app/code/Magento/CatalogExtractor/DataProvider/ColumnsDataMapper.php +++ /dev/null @@ -1,58 +0,0 @@ - [....] - * ] - * - * $available = [ - * 'attribute_code' => 'attribute.attribute_code', - * 'attribute_id' => 'attribute.attribute_id' - * 'id' => 'main_table.product_super_attribute_id', - * 'label' => new Zend_Db_Expr('') - * ] - * - * $result = [ - * 'attribute_code' => 'attribute.attribute_code', - * 'label' => new Zend_Db_Expr('') - * ] - * ``` - * - * @see \Magento\ConfigurableProductExtractor\DataProvider\Query\Attributes\ConfigurableOptionsBuilder::build - * @see \Magento\ConfigurableProductExtractor\DataProvider\Query\Attributes\ConfigurableOptionValuesBuilder::build - * - * @param array $requested - * @param array $available - * @return array - */ - public function filter(array $requested, array $available): array - { - if (empty($requested)) { - $columns = $available; - } else { - $requestedAttributes = array_filter($requested, 'is_string'); - $columns = array_intersect_key($available, array_fill_keys($requestedAttributes, 1)); - } - - return $columns; - } -} diff --git a/app/code/Magento/CatalogInventoryExtractor/Model/Plugin/StockStatusQuery.php b/app/code/Magento/CatalogInventoryExtractor/Model/Plugin/StockStatusQuery.php deleted file mode 100644 index d409178ce..000000000 --- a/app/code/Magento/CatalogInventoryExtractor/Model/Plugin/StockStatusQuery.php +++ /dev/null @@ -1,68 +0,0 @@ -resourceConnection = $resourceConnection; - $this->stockConfiguration = $stockConfiguration; - } - - /** - * Add join for IN_STOCK products only if the "Is Show Out Of Stock" option disabled - * - * @param ProductVariantsBuilder $subject - * @param Select $result - * @param array $parentProducts - * @param array $scopes - * @return Select - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function afterBuild( - ProductVariantsBuilder $subject, - Select $result, - array $parentProducts, - array $scopes - ): Select { - if (false === $this->stockConfiguration->isShowOutOfStock($scopes['store'])) { - $result->joinInner( - ['stock_status' => $this->resourceConnection->getTableName('cataloginventory_stock_status')], - 'stock_status.product_id = product_link.product_id AND stock_status.stock_status = ' - . Stock::STOCK_IN_STOCK, - [] - ); - } - - return $result; - } -} diff --git a/app/code/Magento/CatalogInventoryExtractor/composer.json b/app/code/Magento/CatalogInventoryExtractor/composer.json index 0f8a49329..d48b77f4c 100644 --- a/app/code/Magento/CatalogInventoryExtractor/composer.json +++ b/app/code/Magento/CatalogInventoryExtractor/composer.json @@ -8,7 +8,6 @@ "php": "~7.3.0||~7.4.0", "magento/framework": "*", "magento/module-catalog-inventory": "*", - "magento/module-configurable-product-extractor": "*", "magento/module-catalog-storefront-connector": "*", "magento/module-catalog-extractor": "*", "magento/module-catalog-search": "*", diff --git a/app/code/Magento/CatalogInventoryExtractor/etc/di.xml b/app/code/Magento/CatalogInventoryExtractor/etc/di.xml index 3c5076307..262a66c69 100644 --- a/app/code/Magento/CatalogInventoryExtractor/etc/di.xml +++ b/app/code/Magento/CatalogInventoryExtractor/etc/di.xml @@ -6,10 +6,6 @@ */ --> - - - - diff --git a/app/code/Magento/CatalogInventoryExtractor/etc/module.xml b/app/code/Magento/CatalogInventoryExtractor/etc/module.xml index 045cc997f..9ff9bc5a3 100644 --- a/app/code/Magento/CatalogInventoryExtractor/etc/module.xml +++ b/app/code/Magento/CatalogInventoryExtractor/etc/module.xml @@ -9,7 +9,6 @@ - diff --git a/app/code/Magento/CatalogMessageBroker/Model/ProductDataProcessor.php b/app/code/Magento/CatalogMessageBroker/Model/ProductDataProcessor.php index ebfd0737d..243d6c6fe 100644 --- a/app/code/Magento/CatalogMessageBroker/Model/ProductDataProcessor.php +++ b/app/code/Magento/CatalogMessageBroker/Model/ProductDataProcessor.php @@ -42,7 +42,6 @@ class ProductDataProcessor 'updated_at' => 'updated_at', 'attributes' => 'dynamic_attributes', 'price_view' => 'price_view', - // 'variants' => 'variants', // \Magento\CatalogStorefrontApi\Api\Data\VariantInterface[] 'category_ids' => 'categories', 'images' => 'images', //type: \Magento\CatalogStorefrontApi\Api\Data\ImageInterface[] 'videos' => 'videos', //type: \Magento\CatalogStorefrontApi\Api\Data\VideoInterface[] diff --git a/app/code/Magento/ConfigurableProductExtractor/DataProvider/AttributeOptionsProvider.php b/app/code/Magento/ConfigurableProductExtractor/DataProvider/AttributeOptionsProvider.php deleted file mode 100644 index 4ff68fa06..000000000 --- a/app/code/Magento/ConfigurableProductExtractor/DataProvider/AttributeOptionsProvider.php +++ /dev/null @@ -1,116 +0,0 @@ - [attribute], ...] return attribute options assigned to products in format - * [ - * child_id => [ - * attribute_id => [ - * product_id - * attribute_id - * attribute_id - * value_index - * ... - * ] - * ] - * - * ] - */ -class AttributeOptionsProvider -{ - private const ATTRIBUTES = [ - // "system" attributes - 'attribute_id', - 'product_id', - - // entity attributes - 'value_index', - 'default_label', - 'label', - 'store_label', - 'use_default_value', - ]; - - /** - * @var ResourceConnection - */ - private $resourceConnection; - - /** - * @var ConfigurableOptionValuesBuilder - */ - private $configurableOptionValuesBuilder; - - /** - * @param ResourceConnection $resourceConnection - * @param ConfigurableOptionValuesBuilder $configurableOptionValuesBuilder - */ - public function __construct( - ResourceConnection $resourceConnection, - ConfigurableOptionValuesBuilder $configurableOptionValuesBuilder - ) { - $this->configurableOptionValuesBuilder = $configurableOptionValuesBuilder; - $this->resourceConnection = $resourceConnection; - } - - /** - * Get configurable attribute options - * - * @param array $products - * @param array $attributesPerProduct - * @param array $scopes - * @return array - * @throws \Zend_Db_Statement_Exception - */ - public function provide( - array $products, - array $attributesPerProduct, - array $scopes - ): array { - $storeId = (int)$scopes['store']; - $childProductIds = []; - $attributeIds = []; - $childProductAttributes = []; - foreach ($products as $product) { - $childId = $product['variant_id']; - $parentId = $product['parent_id']; - if (isset($attributesPerProduct[$parentId]) && !isset($childProductAttributes[$childId])) { - $attributes = \array_column($attributesPerProduct[$parentId], 'attribute_id'); - $childProductAttributes[$childId] = $attributes; - $childProductIds[] = $childId; - $attributeIds[] = $attributes; - } - } - $attributeIds = \array_unique(\array_merge(...$attributeIds)); - - $optionValuesSelect = $this->configurableOptionValuesBuilder->build( - self::ATTRIBUTES, - $childProductIds, - $attributeIds, - $storeId - ); - /** @var AdapterInterface $connection */ - $statement = $this->resourceConnection->getConnection()->query($optionValuesSelect); - $attributeOptionsValues = []; - while ($row = $statement->fetch()) { - $childId = $row['product_id']; - if (\in_array($row['attribute_id'], $childProductAttributes[$childId], true)) { - $attributeOptionsValues[$childId][$row['attribute_id']] = $row; - } - } - - return $attributeOptionsValues; - } -} diff --git a/app/code/Magento/ConfigurableProductExtractor/DataProvider/ConfigurableAttributesProvider.php b/app/code/Magento/ConfigurableProductExtractor/DataProvider/ConfigurableAttributesProvider.php deleted file mode 100644 index e6b71cb91..000000000 --- a/app/code/Magento/ConfigurableProductExtractor/DataProvider/ConfigurableAttributesProvider.php +++ /dev/null @@ -1,81 +0,0 @@ - [ - * attribute_id => [ - * product_id - * attribute_id - * attribute_code - * label - * ... - * ] - * ] - * ] - */ -class ConfigurableAttributesProvider -{ - /** - * @var ResourceConnection - */ - private $resourceConnection; - - /** - * @var ConfigurableOptionsBuilder - */ - private $configurableOptionsBuilder; - - /** - * @param ResourceConnection $resourceConnection - * @param ConfigurableOptionsBuilder $configurableOptionsBuilder - */ - public function __construct( - ResourceConnection $resourceConnection, - ConfigurableOptionsBuilder $configurableOptionsBuilder - ) { - $this->configurableOptionsBuilder = $configurableOptionsBuilder; - $this->resourceConnection = $resourceConnection; - } - - /** - * Get configurable attributes - * - * @param array $parentProductIds - * @param array $requestedAttributes - * @param array $scopes - * @return array - * @throws \Exception - */ - public function provide(array $parentProductIds, array $requestedAttributes, array $scopes): array - { - $storeId = (int)$scopes['store']; - - /** @var \Magento\Framework\DB\Select $configurableOptionsSelect */ - $select = $this->configurableOptionsBuilder->build( - $parentProductIds, - $requestedAttributes['configurable_options'] ?? [], - $storeId - ); - - $configurableAttributes = []; - $statement = $this->resourceConnection->getConnection()->query($select); - - while ($row = $statement->fetch()) { - $configurableAttributes[$row['product_id']][$row['attribute_id']] = $row; - } - - return $configurableAttributes; - } -} diff --git a/app/code/Magento/ConfigurableProductExtractor/DataProvider/Query/Attributes/ConfigurableOptionValuesBuilder.php b/app/code/Magento/ConfigurableProductExtractor/DataProvider/Query/Attributes/ConfigurableOptionValuesBuilder.php deleted file mode 100644 index d2f9293c4..000000000 --- a/app/code/Magento/ConfigurableProductExtractor/DataProvider/Query/Attributes/ConfigurableOptionValuesBuilder.php +++ /dev/null @@ -1,114 +0,0 @@ -resourceConnection = $resourceConnection; - $this->columnsDataMapper = $columnsDataMapper; - $this->metadataPool = $metadataPool; - } - - /** - * Form and return query to get Option Values for given $attributeIds. - * - * @param array $requestedOptions - * @param array $childProductIds - * @param array $attributeIds - * @param int $storeId - * @return Select - * @throws \Exception - */ - public function build(array $requestedOptions, array $childProductIds, array $attributeIds, int $storeId): Select - { - /** @var \Magento\Framework\DB\Adapter\AdapterInterface $connection */ - $connection = $this->resourceConnection->getConnection(); - - /** @var \Magento\Framework\EntityManager\EntityMetadataInterface $metadata */ - $metadata = $this->metadataPool->getMetadata(ProductInterface::class); - $linkField = $metadata->getLinkField(); - - $optionColumns = $this->columnsDataMapper->filter($requestedOptions, $this->getAvailableColumns()); - - $optionValuesSelect = $connection->select() - ->from(['product' => $this->resourceConnection->getTableName('catalog_product_entity')], []) - ->columns($optionColumns) - ->join( - ['product_attribute' => $this->resourceConnection->getTableName('catalog_product_entity_int')], - 'product_attribute.' . $linkField . ' = product.' . $linkField, - [] - )->join( - ['default_option_value' => $this->resourceConnection->getTableName('eav_attribute_option_value')], - 'default_option_value.option_id = product_attribute.value', - [] - )->joinLeft( - ['option_value' => $this->resourceConnection->getTableName('eav_attribute_option_value')], - \sprintf( - 'option_value.option_id = product_attribute.value AND option_value.store_id = %1$d', - $storeId - ), - [] - )->where('product.entity_id IN (?)', $childProductIds) - ->where('product_attribute.attribute_id IN (?)', $attributeIds) - ->where('default_option_value.store_id = 0'); - - return $optionValuesSelect; - } - - /** - * Get list of supported columns. - * - * @return array - */ - private function getAvailableColumns(): array - { - return [ - 'value_index' => 'product_attribute.value', - 'label' => new \Zend_Db_Expr('IFNULL(option_value.value, default_option_value.value)'), - 'default_label' => new \Zend_Db_Expr('IFNULL(option_value.value, default_option_value.value)'), - 'store_label' => new \Zend_Db_Expr('IFNULL(option_value.value, default_option_value.value)'), - 'use_default_value' => new \Zend_Db_Expr('1'), - 'attribute_id' => new \Zend_Db_Expr('product_attribute.attribute_id'), - 'product_id' => new \Zend_Db_Expr('product.entity_id'), - ]; - } -} diff --git a/app/code/Magento/ConfigurableProductExtractor/DataProvider/Query/Attributes/ConfigurableOptionsBuilder.php b/app/code/Magento/ConfigurableProductExtractor/DataProvider/Query/Attributes/ConfigurableOptionsBuilder.php deleted file mode 100644 index 3287d4356..000000000 --- a/app/code/Magento/ConfigurableProductExtractor/DataProvider/Query/Attributes/ConfigurableOptionsBuilder.php +++ /dev/null @@ -1,140 +0,0 @@ -resourceConnection = $resourceConnection; - $this->metadataPool = $metadataPool; - $this->columnsDataMapper = $columnsDataMapper; - } - - /** - * Form and return query to get $attributes for given $productIds. - * - * @param array $parentProductIds - * @param array $requestedOptions - * @param int $storeId - * @return Select - * @throws \Exception - */ - public function build(array $parentProductIds, array $requestedOptions, int $storeId): Select - { - /** @var \Magento\Framework\DB\Adapter\AdapterInterface $connection */ - $connection = $this->resourceConnection->getConnection(); - - $eavAttributeTable = $this->resourceConnection->getTableName('eav_attribute'); - $superAttributeLabelTable = $this->resourceConnection->getTableName( - 'catalog_product_super_attribute_label' - ); - $attributeLabelTable = $this->resourceConnection->getTableName('eav_attribute_label'); - $catalogProductEntityTable = $this->resourceConnection->getTableName('catalog_product_entity'); - - /** @var \Magento\Framework\EntityManager\EntityMetadataInterface $metadata */ - $metadata = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class); - $linkField = $metadata->getLinkField(); - - $optionColumns = $this->columnsDataMapper->filter($requestedOptions, $this->getAvailableColumns()); - $optionColumns['product_id'] = 'product.entity_id'; - $optionColumns['attribute_code'] = 'attribute.attribute_code'; - $optionColumns['attribute_id'] = 'attribute.attribute_id'; - - $configurableOptionsSelect = $connection->select() - ->from(['main_table' => $this->resourceConnection->getTableName('catalog_product_super_attribute')], []) - ->columns($optionColumns) - ->join( - ['attribute' => $eavAttributeTable], - 'attribute.attribute_id = main_table.attribute_id', - [] - ) - ->join( - ['product' => $catalogProductEntityTable], - \sprintf('main_table.product_id = product.%1$s', $linkField), - [] - ) - ->joinLeft( - ['default_label' => $superAttributeLabelTable], - 'main_table.product_super_attribute_id = default_label.product_super_attribute_id ' . - ' AND (default_label.store_id = 0)', - [] - ) - ->joinLeft( - ['store' => $superAttributeLabelTable], - \sprintf( - 'store.product_super_attribute_id = default_label.product_super_attribute_id ' . - 'AND store.store_id = %1$d', - $storeId - ), - [] - ) - ->joinLeft( - ['eav_attr_label' => $attributeLabelTable], - \sprintf( - 'eav_attr_label.attribute_id = main_table.attribute_id AND eav_attr_label.store_id = %1$d', - $storeId - ), - [] - ) - ->where('product.entity_id IN (?)', $parentProductIds); - - return $configurableOptionsSelect; - } - - /** - * Get list of supported columns. - * - * @return array - */ - private function getAvailableColumns(): array - { - return [ - 'id' => 'main_table.product_super_attribute_id', - 'label' => new \Zend_Db_Expr( - 'IFNULL(eav_attr_label.value, IFNULL(store.VALUE, ' . - 'IFNULL(attribute.frontend_label, default_label.VALUE)))' - ), - 'position' => 'main_table.position', - 'use_default' => new \Zend_Db_Expr( - 'IF(store.use_default IS NULL, default_label.use_default, store.use_default)' - ), - ]; - } -} diff --git a/app/code/Magento/ConfigurableProductExtractor/DataProvider/Query/ProductVariantsBuilder.php b/app/code/Magento/ConfigurableProductExtractor/DataProvider/Query/ProductVariantsBuilder.php deleted file mode 100644 index 0a172cf28..000000000 --- a/app/code/Magento/ConfigurableProductExtractor/DataProvider/Query/ProductVariantsBuilder.php +++ /dev/null @@ -1,84 +0,0 @@ - parent ID' relations: - * [ - * 'variant_id' => 'parent_id - * ..... - * ] - */ -class ProductVariantsBuilder -{ - /** - * @var ResourceConnection - */ - private $resourceConnection; - - /** - * @var MetadataPool - */ - private $metadataPool; - /** - * @var StoreManagerInterface - */ - private $storeManager; - - /** - * @param ResourceConnection $resourceConnection - * @param MetadataPool $metadataPool - * @param StoreManagerInterface $storeManager - */ - public function __construct( - ResourceConnection $resourceConnection, - MetadataPool $metadataPool, - StoreManagerInterface $storeManager - ) { - $this->resourceConnection = $resourceConnection; - $this->metadataPool = $metadataPool; - $this->storeManager = $storeManager; - } - - /** - * Get select for retrieving child products assigned to configurable parents - * - * @param array $parentProducts - * @param array $scopes - * @return Select - * @throws \Exception - */ - public function build(array $parentProducts, array $scopes): Select - { - $websiteId = $this->storeManager->getStore($scopes['store'])->getWebsiteId(); - $linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField(); - $select = $this->resourceConnection->getConnection()->select() - ->from( - ['product_link' => $this->resourceConnection->getTableName('catalog_product_super_link')], - ['variant_id' => 'product_link.product_id'] - )->join( - ['parent_product' => $this->resourceConnection->getTableName('catalog_product_entity')], - 'parent_product.' . $linkField . ' = product_link.parent_id', - ['parent_id' => 'parent_product.entity_id'] - )->join( - ['product_website' => $this->resourceConnection->getTableName('catalog_product_website')], - 'product_website.product_id = product_link.product_id' - . ' AND product_website.website_id = ' . $websiteId, - [] - )->where('parent_product.entity_id in (?)', $parentProducts); - - return $select; - } -} diff --git a/app/code/Magento/ConfigurableProductExtractor/DataProvider/VariantsDataProvider.php b/app/code/Magento/ConfigurableProductExtractor/DataProvider/VariantsDataProvider.php deleted file mode 100644 index f8f2f141d..000000000 --- a/app/code/Magento/ConfigurableProductExtractor/DataProvider/VariantsDataProvider.php +++ /dev/null @@ -1,259 +0,0 @@ -resourceConnection = $resourceConnection; - $this->productVariantsBuilder = $productVariantsQuery; - $this->configurableAttributesProvider = $configurableAttributesProvider; - $this->attributeOptionsProvider = $attributeOptionsProvider; - } - - /** TODO: Remove module once configurable product variants provider is implemented in saasExport*/ - - /** - * @inheritdoc - * - * Fetches requested product variants attributes for given $parentProductIds. - * - * @throws \Zend_Db_Statement_Exception - */ - public function fetch(array $parentProductIds, array $requestedAttributes, array $scopes): array - { - $select = $this->productVariantsBuilder->build($parentProductIds, $scopes); - $products = $this->resourceConnection->getConnection()->fetchAll($select); - if (!$products) { - return []; - } - - [$attributesPerProduct, $childAttributeOptions] = $this->loadAttributes( - $parentProductIds, - $requestedAttributes, - $scopes, - $products - ); - - $result = []; - $result[] = $this->getLinkedProductIds($products); - - if (empty($requestedAttributes) || isset($requestedAttributes['variants']['attributes'])) { - $result[] = $this->buildVariantAttributes($products, $attributesPerProduct, $childAttributeOptions); - } -// if (empty($requestedAttributes) || isset($requestedAttributes['configurable_options'])) { -// $result[] = $this->buildConfigurableOptions($products, $attributesPerProduct, $childAttributeOptions); -// } - - return !empty($result) ? array_replace_recursive(...$result) : $result; - } - - /** - * Get configurable variant ids - * - * @param array $products - * @return array - */ - private function getLinkedProductIds(array $products): array - { - $childrenMap = []; - foreach ($products as $child) { - $variantId = $child['variant_id'] ?? null; - if ($variantId) { - $childrenMap[$child['parent_id']]['variants'][$variantId]['product'] = $variantId; - } - } - - return $childrenMap; - } - -// /** -// * Build configurable options -// * -// * @param array $products -// * @param array $attributesPerProduct -// * @param array $childProductAttributeOptions -// * @return array -// */ -// private function buildConfigurableOptions( -// array $products, -// array $attributesPerProduct, -// array $childProductAttributeOptions -// ): array { -// $configurableOptions = []; -// -// $parentChildMap = []; -// foreach ($products as $product) { -// $childId = $product['variant_id']; -// $parentChildMap[$product['parent_id']][$childId] = $childId; -// } -// -// foreach ($attributesPerProduct as $parentId => $configurableAttributes) { -// // handle case when configurable product do not contains variations -// if (!isset($parentChildMap[$parentId])) { -// continue; -// } -// $attributeOptionsPerAttribute = $this->convertToOptionsPerAttribute( -// $childProductAttributeOptions, -// $parentChildMap[$parentId] -// ); -// foreach ($configurableAttributes as $attributeId => &$attributes) { -// $attributes['values'] = $attributeOptionsPerAttribute[$attributeId]; -// } -// $configurableOptions[$parentId]['configurable_options'] = $configurableAttributes; -// } -// return $configurableOptions; -// } - - /** - * Build attributes for given configurable variants - * - * @param array $products - * @param array $attributesPerProduct - * @param array $childProductAttributeOptions - * @return array - */ - private function buildVariantAttributes( - array $products, - array $attributesPerProduct, - array $childProductAttributeOptions - ): array { - $variantAttributes = []; - foreach ($products as $product) { - $parentId = $product['parent_id']; - $childId = $product['variant_id']; - $attributeOptions = $childProductAttributeOptions[$childId] ?? []; - $variantAttributes[$parentId]['variants'][$childId]['attributes'] = \array_map( - function ($attribute) use ($parentId, $attributesPerProduct) { - $attributeId = $attribute['attribute_id']; - return [ - 'label' => $attribute['label'] ?? '', - 'code' => $attributesPerProduct[$parentId][$attributeId]['attribute_code'] ?? '', - 'value_index' => $attribute['value_index'] ?? '', - 'attribute_id' => $attributeId - ]; - }, - $attributeOptions - ); - } - return $variantAttributes; - } - -// /** -// * Find thought child products of configurable product attribute options belonging to the same attribute -// * -// * @param array $childProductAttributeOptions -// * @param array $childIds -// * @return array -// */ -// private function convertToOptionsPerAttribute(array $childProductAttributeOptions, array $childIds): array -// { -// $childrenAttributes = \array_intersect_key($childProductAttributeOptions, $childIds); -// $childrenAttributes = \array_merge(...$childrenAttributes); -// -// $options = []; -// foreach ($childrenAttributes as $attributeOption) { -// $options[$attributeOption['attribute_id']][$attributeOption['value_index']] = $attributeOption; -// } -// -// return $options; -// } - - /** - * Load required attributes - * - * @param array $parentProductIds - * @param array $requestedAttributes - * @param array $scopes - * @param array $products - * @return array - * @throws \Zend_Db_Statement_Exception - */ - private function loadAttributes( - array $parentProductIds, - array $requestedAttributes, - array $scopes, - array $products - ): array { - $attributesPerProduct = $this->configurableAttributesProvider->provide( - $parentProductIds, - $requestedAttributes, - $scopes - ); - if (!$attributesPerProduct) { - throw new \LogicException( - \sprintf( - 'Can not find attributes for the following configurable products: "%s"', - \implode(', ', $parentProductIds) - ) - ); - } - $childAttributeOptions = $this->attributeOptionsProvider->provide( - $products, - $attributesPerProduct, - $scopes - ); - if (!$childAttributeOptions) { - throw new \LogicException( - \sprintf( - 'Can not find attribute options for the following configurable products: "%s"', - \implode(', ', $parentProductIds) - ) - ); - } - return [$attributesPerProduct, $childAttributeOptions]; - } -} diff --git a/app/code/Magento/ConfigurableProductExtractor/LICENSE.txt b/app/code/Magento/ConfigurableProductExtractor/LICENSE.txt deleted file mode 100644 index 36b2459f6..000000000 --- a/app/code/Magento/ConfigurableProductExtractor/LICENSE.txt +++ /dev/null @@ -1,48 +0,0 @@ - -Open Software License ("OSL") v. 3.0 - -This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: - -Licensed under the Open Software License version 3.0 - - 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: - - 1. to reproduce the Original Work in copies, either alone or as part of a collective work; - - 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; - - 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License; - - 4. to perform the Original Work publicly; and - - 5. to display the Original Work publicly. - - 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. - - 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. - - 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. - - 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). - - 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. - - 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. - - 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. - - 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including 'fair use' or 'fair dealing'). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). - - 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. - - 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. - - 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. - - 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. - - 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - - 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. - - 16. Modification of This License. This License is Copyright (C) 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/app/code/Magento/ConfigurableProductExtractor/LICENSE_AFL.txt b/app/code/Magento/ConfigurableProductExtractor/LICENSE_AFL.txt deleted file mode 100644 index 496bf10ad..000000000 --- a/app/code/Magento/ConfigurableProductExtractor/LICENSE_AFL.txt +++ /dev/null @@ -1,48 +0,0 @@ - -Academic Free License ("AFL") v. 3.0 - -This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: - -Licensed under the Academic Free License version 3.0 - - 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: - - 1. to reproduce the Original Work in copies, either alone or as part of a collective work; - - 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; - - 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; - - 4. to perform the Original Work publicly; and - - 5. to display the Original Work publicly. - - 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. - - 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. - - 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. - - 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). - - 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. - - 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. - - 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. - - 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). - - 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. - - 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. - - 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. - - 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. - - 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - - 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. - - 16. Modification of This License. This License is Copyright © 2016 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/app/code/Magento/ConfigurableProductExtractor/README.md b/app/code/Magento/ConfigurableProductExtractor/README.md deleted file mode 100644 index 67596ecb7..000000000 --- a/app/code/Magento/ConfigurableProductExtractor/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Overview - -Magento_ConfigurableProductExtractor module extracts Configurable Product data which consumed by Magento_CatalogStorefrontConnector module \ No newline at end of file diff --git a/app/code/Magento/ConfigurableProductExtractor/composer.json b/app/code/Magento/ConfigurableProductExtractor/composer.json deleted file mode 100644 index 20a63da40..000000000 --- a/app/code/Magento/ConfigurableProductExtractor/composer.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "magento/module-configurable-product-extractor", - "description": "Module extracts Configurable Product data which consumed by Magento_CatalogStorefrontConnector module", - "config": { - "sort-packages": true - }, - "require": { - "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-catalog-extractor": "*", - "magento/module-configurable-product": "*", - "magento/module-store": "*", - "magento/module-eav": "*" - }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], - "autoload": { - "files": [ - "registration.php" - ], - "psr-4": { - "Magento\\ConfigurableProductExtractor\\": "" - } - } -} diff --git a/app/code/Magento/ConfigurableProductExtractor/etc/di.xml b/app/code/Magento/ConfigurableProductExtractor/etc/di.xml deleted file mode 100644 index f2e81f5d6..000000000 --- a/app/code/Magento/ConfigurableProductExtractor/etc/di.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - Magento\ConfigurableProductExtractor\DataProvider\VariantsDataProvider - - - configurable - - - - diff --git a/app/code/Magento/ConfigurableProductExtractor/etc/module.xml b/app/code/Magento/ConfigurableProductExtractor/etc/module.xml deleted file mode 100644 index 246cccfa6..000000000 --- a/app/code/Magento/ConfigurableProductExtractor/etc/module.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - diff --git a/app/code/Magento/ConfigurableProductExtractor/registration.php b/app/code/Magento/ConfigurableProductExtractor/registration.php deleted file mode 100644 index 98eac14fd..000000000 --- a/app/code/Magento/ConfigurableProductExtractor/registration.php +++ /dev/null @@ -1,9 +0,0 @@ - Date: Tue, 3 Nov 2020 16:38:24 +0200 Subject: [PATCH 08/23] Product variants --- .../Model/MessageBus/ProductVariantsTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php b/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php index 1b28dfd84..2c571ede2 100644 --- a/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php +++ b/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php @@ -24,7 +24,7 @@ use Magento\TestFramework\Helper\Bootstrap; /** - * Test class for Products message bus + * Test class for Products variants message bus * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ @@ -90,14 +90,14 @@ protected function setUp(): void } /** - * Validate something + * Validate save and delete product variant operations * @magentoApiDataFixture Magento/ConfigurableProduct/_files/configurable_products_with_two_attributes.php * @magentoDbIsolation disabled * @throws NoSuchEntityException * @throws StateException * @throws \Throwable */ - public function testSaveAndDeleteProduct(): void + public function testSaveAndDeleteProductVariant(): void { $configurable = $this->getProduct(self::CONFIGURABLE_SKU); $configurableId = $configurable->getId(); From 617352dcc9963a165d0cfc6d0520e04946c62d5b Mon Sep 17 00:00:00 2001 From: jekabs Date: Wed, 4 Nov 2020 16:31:18 +0200 Subject: [PATCH 09/23] Product variants -Changed entity_id type to string in order to pass product variant message correctly --- app/code/Magento/CatalogExport/Event/Data/Entity.php | 10 +++++----- .../Model/Storage/Client/Config/ProductVariant.php | 8 +++----- .../Model/CategoriesQueueConsumer.php | 2 +- .../Model/ProductsQueueConsumer.php | 2 +- .../Model/MessageBus/ProductVariantsTest.php | 4 ++-- 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/app/code/Magento/CatalogExport/Event/Data/Entity.php b/app/code/Magento/CatalogExport/Event/Data/Entity.php index 8b4b55178..6a82a09b8 100644 --- a/app/code/Magento/CatalogExport/Event/Data/Entity.php +++ b/app/code/Magento/CatalogExport/Event/Data/Entity.php @@ -14,7 +14,7 @@ class Entity { /** - * @var int|string + * @var string */ private $entityId; @@ -26,9 +26,9 @@ class Entity /** * Get entity id. * - * @return int|string + * @return string */ - public function getEntityId() + public function getEntityId(): string { return $this->entityId; } @@ -36,11 +36,11 @@ public function getEntityId() /** * Set entity id. * - * @param int|string $entityId + * @param string $entityId * * @return void */ - public function setEntityId($entityId): void + public function setEntityId(string $entityId): void { $this->entityId = $entityId; } diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Client/Config/ProductVariant.php b/app/code/Magento/CatalogStorefront/Model/Storage/Client/Config/ProductVariant.php index 212f3eb6c..f195e093c 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Client/Config/ProductVariant.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Client/Config/ProductVariant.php @@ -43,15 +43,13 @@ public function getSettings() : array 'type' => 'keyword' ], 'option_value' => [ - 'type' => 'text', - 'index' => false + 'type' => 'keyword', ], 'parent_id' => [ - 'type' => 'text', + 'type' => 'keyword', ], 'product_id' => [ - 'type' => 'text', - 'index' => false + 'type' => 'keyword', ], ] ]; diff --git a/app/code/Magento/CatalogStorefrontConnector/Model/CategoriesQueueConsumer.php b/app/code/Magento/CatalogStorefrontConnector/Model/CategoriesQueueConsumer.php index 7929bb141..dee8d5d1c 100644 --- a/app/code/Magento/CatalogStorefrontConnector/Model/CategoriesQueueConsumer.php +++ b/app/code/Magento/CatalogStorefrontConnector/Model/CategoriesQueueConsumer.php @@ -153,7 +153,7 @@ private function buildMessageEntitiesArray(array $entityIds): array $entitiesArray = []; foreach ($entityIds as $id) { $entitiesArray[] = [ - 'entity_id' => (int)$id, + 'entity_id' => (string)$id, ]; } diff --git a/app/code/Magento/CatalogStorefrontConnector/Model/ProductsQueueConsumer.php b/app/code/Magento/CatalogStorefrontConnector/Model/ProductsQueueConsumer.php index 2b86b7541..7dd9bf063 100644 --- a/app/code/Magento/CatalogStorefrontConnector/Model/ProductsQueueConsumer.php +++ b/app/code/Magento/CatalogStorefrontConnector/Model/ProductsQueueConsumer.php @@ -152,7 +152,7 @@ private function buildMessageEntitiesArray(array $entityIds): array $entitiesArray = []; foreach ($entityIds as $id) { $entitiesArray[] = [ - 'entity_id' => (int)$id, + 'entity_id' => (string)$id, ]; } diff --git a/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php b/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php index 2c571ede2..3155ec599 100644 --- a/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php +++ b/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php @@ -180,7 +180,7 @@ private function getProduct(string $sku): ProductInterface try { return $this->productRepository->get($sku); } catch (NoSuchEntityException $e) { - throw new NoSuchEntityException(); + throw new NoSuchEntityException(__('Could not retrieve product with sku ' . $sku)); } } @@ -199,7 +199,7 @@ private function deleteProduct(string $sku): void $registry->unregister('isSecureArea'); $registry->register('isSecureArea', false); } catch (NoSuchEntityException $e) { - throw new NoSuchEntityException(); + throw new NoSuchEntityException(__('Could not delete product with sku ' . $sku)); } } } From 6c5bf079b51f486fce53909e507a21add5b94dea Mon Sep 17 00:00:00 2001 From: jekabs Date: Thu, 5 Nov 2020 13:06:12 +0200 Subject: [PATCH 10/23] Product variants -Fixed and added tests -Other minor fixes and improvements like syntax, docBlock, constants, etc. --- .../Category/DeleteCategoriesConsumer.php | 2 +- .../Category/PublishCategoriesConsumer.php | 2 +- .../MessageBus/ConsumerEventInterface.php | 2 +- .../Product/DeleteProductsConsumer.php | 2 +- .../Product/PublishProductsConsumer.php | 2 +- .../DeleteProductVariantsConsumer.php | 2 +- .../PublishProductVariantsConsumer.php | 2 +- .../Model/CatalogRepository.php | 8 +- .../Model/CatalogService.php | 12 +- .../Storage/Client/ElasticsearchCommand.php | 1 - .../Data/SearchResultIteratorFactory.php | 2 +- .../Model/VariantService.php | 7 +- .../ConfigurableVariantsTest.php | 155 ++++++++++++++++++ .../Test/Api/StorefrontTestsAbstract.php | 4 +- .../Model/MessageBus/CatergoriesTest.php | 2 +- .../Model/MessageBus/ProductVariantsTest.php | 15 +- .../Model/MessageBus/ProductsTest.php | 6 +- 17 files changed, 193 insertions(+), 33 deletions(-) create mode 100644 app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php diff --git a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Category/DeleteCategoriesConsumer.php b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Category/DeleteCategoriesConsumer.php index 5355dcc19..d15e3f543 100644 --- a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Category/DeleteCategoriesConsumer.php +++ b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Category/DeleteCategoriesConsumer.php @@ -49,7 +49,7 @@ public function __construct( /** * @inheritdoc */ - public function execute(array $entities, string $scope = null): void + public function execute(array $entities, ?string $scope = null): void { $ids = []; diff --git a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Category/PublishCategoriesConsumer.php b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Category/PublishCategoriesConsumer.php index eac767e0c..8d215d931 100644 --- a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Category/PublishCategoriesConsumer.php +++ b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Category/PublishCategoriesConsumer.php @@ -78,7 +78,7 @@ public function __construct( /** * @inheritdoc */ - public function execute(array $entities, string $scope = null): void + public function execute(array $entities, ?string $scope = null): void { $categoriesData = $this->fetchCategories->execute($entities, $scope); $attributesArray = $this->getAttributesArray($entities); diff --git a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ConsumerEventInterface.php b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ConsumerEventInterface.php index 118f61670..4630fbf41 100644 --- a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ConsumerEventInterface.php +++ b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ConsumerEventInterface.php @@ -22,5 +22,5 @@ interface ConsumerEventInterface * * @return void */ - public function execute(array $entities, string $scope = null): void; + public function execute(array $entities, ?string $scope = null): void; } diff --git a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Product/DeleteProductsConsumer.php b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Product/DeleteProductsConsumer.php index b4b64b571..7ada98df7 100644 --- a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Product/DeleteProductsConsumer.php +++ b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Product/DeleteProductsConsumer.php @@ -49,7 +49,7 @@ public function __construct( /** * @inheritdoc */ - public function execute(array $entities, string $scope = null): void + public function execute(array $entities, ?string $scope = null): void { $ids = []; diff --git a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Product/PublishProductsConsumer.php b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Product/PublishProductsConsumer.php index 99e47e4ce..e61b68867 100644 --- a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Product/PublishProductsConsumer.php +++ b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/Product/PublishProductsConsumer.php @@ -73,7 +73,7 @@ public function __construct( /** * @inheritdoc */ - public function execute(array $entities, string $scope = null): void + public function execute(array $entities, ?string $scope = null): void { $productsData = $this->fetchProducts->execute($entities, $scope); $attributesArray = $this->getAttributesArray($entities); diff --git a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/DeleteProductVariantsConsumer.php b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/DeleteProductVariantsConsumer.php index fabf96027..ce88737c1 100644 --- a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/DeleteProductVariantsConsumer.php +++ b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/DeleteProductVariantsConsumer.php @@ -48,7 +48,7 @@ public function __construct( /** * @inheritdoc */ - public function execute(array $entities, string $scope = null): void + public function execute(array $entities, ?string $scope = null): void { $ids = []; foreach ($entities as $entity) { diff --git a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/PublishProductVariantsConsumer.php b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/PublishProductVariantsConsumer.php index 46e8bae73..198b1e341 100644 --- a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/PublishProductVariantsConsumer.php +++ b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/PublishProductVariantsConsumer.php @@ -68,7 +68,7 @@ public function __construct( /** * @inheritdoc */ - public function execute(array $entities, string $scope = null): void + public function execute(array $entities, ?string $scope = null): void { $variantsData = $this->fetchProductVariants->execute($entities); $variantsImportData = []; diff --git a/app/code/Magento/CatalogStorefront/Model/CatalogRepository.php b/app/code/Magento/CatalogStorefront/Model/CatalogRepository.php index 99ae5c8c6..f05b2eb17 100644 --- a/app/code/Magento/CatalogStorefront/Model/CatalogRepository.php +++ b/app/code/Magento/CatalogStorefront/Model/CatalogRepository.php @@ -19,10 +19,10 @@ */ class CatalogRepository { - protected const DELETE = 'delete'; - protected const DELETE_BY_QUERY = 'delete_by_query'; - protected const SAVE = 'save'; - protected const UPDATE = 'update'; + public const DELETE = 'delete'; + public const DELETE_BY_QUERY = 'delete_by_query'; + public const SAVE = 'save'; + public const UPDATE = 'update'; /** * @var CommandInterface diff --git a/app/code/Magento/CatalogStorefront/Model/CatalogService.php b/app/code/Magento/CatalogStorefront/Model/CatalogService.php index 9f8c743d7..870ab74cd 100644 --- a/app/code/Magento/CatalogStorefront/Model/CatalogService.php +++ b/app/code/Magento/CatalogStorefront/Model/CatalogService.php @@ -219,9 +219,9 @@ public function importProducts(ImportProductsRequestInterface $request): ImportP return \in_array($code, $productData->getAttributes()); }, ARRAY_FILTER_USE_KEY); - $productsInElasticFormat['product'][$storeCode]['update'][] = $product; + $productsInElasticFormat['product'][$storeCode][CatalogRepository::UPDATE][] = $product; } else { - $productsInElasticFormat['product'][$storeCode]['save'][] = $product; + $productsInElasticFormat['product'][$storeCode][CatalogRepository::SAVE][] = $product; } } @@ -251,7 +251,7 @@ public function deleteProducts(DeleteProductsRequestInterface $request): DeleteP $productsInElasticFormat = [ 'product' => [ $storeCode => [ - 'delete' => $request->getProductIds() + CatalogRepository::DELETE => $request->getProductIds() ] ] ]; @@ -297,9 +297,9 @@ public function importCategories(ImportCategoriesRequestInterface $request): Imp return \in_array($code, $categoryData->getAttributes()); }, ARRAY_FILTER_USE_KEY); - $categoriesInElasticFormat['category'][$storeCode]['update'][] = $category; + $categoriesInElasticFormat['category'][$storeCode][CatalogRepository::UPDATE][] = $category; } else { - $categoriesInElasticFormat['category'][$storeCode]['save'][] = $category; + $categoriesInElasticFormat['category'][$storeCode][CatalogRepository::SAVE][] = $category; } } @@ -333,7 +333,7 @@ public function deleteCategories(DeleteCategoriesRequestInterface $request): Del $categoriesInElasticFormat = [ 'category' => [ $storeId => [ - 'delete' => $request->getCategoryIds() + CatalogRepository::DELETE => $request->getCategoryIds() ] ] ]; diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchCommand.php b/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchCommand.php index bc5d1fb6c..62e373e19 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchCommand.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchCommand.php @@ -258,7 +258,6 @@ public function deleteByQuery(string $dataSourceName, string $entityName, array $dataSourceName, $entityName, $entries - // 'wait_for_completion' => true ); try { $this->getConnection()->deleteByQuery($query); diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Data/SearchResultIteratorFactory.php b/app/code/Magento/CatalogStorefront/Model/Storage/Data/SearchResultIteratorFactory.php index a70245337..f4d6dedd2 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Data/SearchResultIteratorFactory.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Data/SearchResultIteratorFactory.php @@ -37,7 +37,7 @@ public function __construct( } /** - * Create class instance with specified parameters + * Create SearchResultIterator class instance with specified parameters * * @param array $result * diff --git a/app/code/Magento/CatalogStorefront/Model/VariantService.php b/app/code/Magento/CatalogStorefront/Model/VariantService.php index 103e7a1c7..8be5cba71 100644 --- a/app/code/Magento/CatalogStorefront/Model/VariantService.php +++ b/app/code/Magento/CatalogStorefront/Model/VariantService.php @@ -132,7 +132,7 @@ public function ImportProductVariants(ImportVariantsRequestInterface $request): $parentId = $explodedId[1]; $childId = $explodedId[2]; foreach ($optionValues as $optionValue) { - preg_match('/(?<=\:)(.*)(?=\/)/', $optionValue, $match); + preg_match('/(?<=:)(.*)(?=\/)/', $optionValue, $match); $attrCode = $match[0]; $variant = [ '_id' => $id . '/' . $attrCode, @@ -142,7 +142,8 @@ public function ImportProductVariants(ImportVariantsRequestInterface $request): 'parent_id' => $parentId ]; //TODO: Adapt to work without store code - $variantsInElasticFormat['product_variant'][self::EMPTY_STORE_CODE]['save'][] = $variant; + $variantsInElasticFormat['product_variant'][self::EMPTY_STORE_CODE][CatalogRepository::SAVE][] = + $variant; } } @@ -178,7 +179,7 @@ public function DeleteProductVariants(DeleteVariantsRequestInterface $request): 'product_variant' => [ //TODO: Adapt to work without store code self::EMPTY_STORE_CODE => [ - 'delete_by_query' => $deleteFields + CatalogRepository::DELETE_BY_QUERY => $deleteFields ] ] ]; diff --git a/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php b/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php new file mode 100644 index 000000000..b128e1a09 --- /dev/null +++ b/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php @@ -0,0 +1,155 @@ +variantService = Bootstrap::getObjectManager()->create(VariantService::class); + $this->variantsRequestInterface = Bootstrap::getObjectManager()->create(ProductVariantRequestInterface::class); + $this->productRepository = Bootstrap::getObjectManager()->create(ProductRepositoryInterface::class); + $this->responseArrayMapper = Bootstrap::getObjectManager()->create( + ProductVariantResponseArrayMapper::class + ); + } + + /** + * Validate configurable product variants data + * + * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable_sku.php + * @magentoDbIsolation disabled + * @throws NoSuchEntityException + * @throws \Throwable + */ + public function testConfigurableProductVariants(): void + { + /** @var $configurable Product */ + $configurable = $this->productRepository->get('configurable'); + $simples = [ + $this->productRepository->get('simple_10'), + $this->productRepository->get('simple_20') + ]; + + $this->variantsRequestInterface->setProductId((string)$configurable->getId()); + $this->variantsRequestInterface->setStore('default'); + + /** @var $variantServiceItem ProductVariantResponse */ + $variantServiceItem = $this->variantService->GetProductVariants($this->variantsRequestInterface); + $actual = $this->responseArrayMapper->convertToArray($variantServiceItem)['matched_variants']; + + $expected = $this->getExpectedProductVariants($configurable, $simples); + self::assertCount(2, $actual); + $this->compare($expected, $actual); + } + + /** + * Validate that only one variant is returned when one simple product out of two is disabled. + * + * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable_disable_first_child.php + * @magentoDbIsolation disabled + * @throws NoSuchEntityException + * @throws \Throwable + */ + public function testProductVariantsDisabledProduct(): void + { + /** @var $configurable Product */ + $configurable = $this->productRepository->get('configurable'); + + $this->variantsRequestInterface->setProductId((string)$configurable->getId()); + $this->variantsRequestInterface->setStore('default'); + + /** @var $variantServiceItem ProductVariantResponse */ + $variantServiceItem = $this->variantService->GetProductVariants($this->variantsRequestInterface); + $actual = $this->responseArrayMapper->convertToArray($variantServiceItem)['matched_variants']; + self::assertCount(1, $actual); + } + + /** + * Get the expected variants for configurable products. + * + * @param Product $configurable + * @param Product[] $simples + * @return array + */ + private function getExpectedProductVariants(Product $configurable, array $simples): array + { + $configurableOptions = $configurable->getExtensionAttributes()->getConfigurableProductOptions(); + $variants = []; + foreach ($simples as $simple) { + $id = (\sprintf( + 'configurable/%1$s/%2$s', + $configurable->getId(), + $simple->getId(), + )); + $optionValues = []; + foreach ($configurableOptions as $configurableOption) { + $attributeCode = $configurableOption->getProductAttribute()->getAttributeCode(); + foreach ($configurableOption->getValues() as $configurableOptionValue) { + if ($simple->getData($attributeCode) === $configurableOptionValue->getValueIndex()) { + // phpcs:ignore Magento2.Functions.DiscouragedFunction + $optionUid = \base64_encode(\sprintf( + 'configurable/%1$s/%2$s', + $configurableOption->getAttributeId(), + $configurableOptionValue->getValueIndex() + )); + $optionValues[] = \sprintf( + '%1$s:%2$s/%3$s', + $configurable->getId(), + $attributeCode, + $optionUid + ); + } + } + } + $variants[$id] = [ + 'id' => $id, + 'option_values' => $optionValues, + 'product_id' => $simple->getId(), + ]; + } + return array_values($variants); + } +} diff --git a/app/code/Magento/CatalogStorefront/Test/Api/StorefrontTestsAbstract.php b/app/code/Magento/CatalogStorefront/Test/Api/StorefrontTestsAbstract.php index 446f91ec1..41bd03316 100644 --- a/app/code/Magento/CatalogStorefront/Test/Api/StorefrontTestsAbstract.php +++ b/app/code/Magento/CatalogStorefront/Test/Api/StorefrontTestsAbstract.php @@ -93,11 +93,11 @@ protected function tearDown(): void */ private function clearCatalogStorage(): void { - $entityTypes = ['category', 'product', 'product_variants']; + $entityTypes = ['category', 'product', 'product_variant']; $availableStores = $this->storeManager->getStores(); foreach ($entityTypes as $entityType) { - if ($entityType === 'product_variants') { + if ($entityType === 'product_variant') { $this->deleteDataSource('', $entityType); } else { foreach ($availableStores as $store) { diff --git a/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/CatergoriesTest.php b/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/CatergoriesTest.php index 1ba5853ce..c9c69d23e 100644 --- a/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/CatergoriesTest.php +++ b/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/CatergoriesTest.php @@ -104,7 +104,7 @@ public function testSaveAndDeleteCategory() : void self::assertEquals(self::CATEGORY_ID, $category->getId()); $entitiesData = [ [ - 'entity_id' => (int) $category->getId(), + 'entity_id' => (string) $category->getId(), ] ]; $message = $this->messageBuilder->build( diff --git a/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php b/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php index 3155ec599..9517d782c 100644 --- a/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php +++ b/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php @@ -3,7 +3,6 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ - declare(strict_types=1); namespace Magento\CatalogMessageBroker\Model\MessageBus; @@ -12,7 +11,7 @@ use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\CatalogExport\Model\ChangedEntitiesMessageBuilder; use Magento\CatalogMessageBroker\Model\MessageBus\ProductVariants\ProductVariantsConsumer; -use \Magento\CatalogStorefront\Model\VariantService; +use Magento\CatalogStorefront\Model\VariantService; use Magento\CatalogStorefront\Test\Api\StorefrontTestsAbstract; use Magento\CatalogStorefrontApi\Api\Data\ProductVariantRequestInterface; use Magento\CatalogStorefrontApi\Api\Data\ProductVariantResponseArrayMapper; @@ -91,7 +90,8 @@ protected function setUp(): void /** * Validate save and delete product variant operations - * @magentoApiDataFixture Magento/ConfigurableProduct/_files/configurable_products_with_two_attributes.php + * + * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable_sku.php * @magentoDbIsolation disabled * @throws NoSuchEntityException * @throws StateException @@ -143,9 +143,8 @@ public function testSaveAndDeleteProductVariant(): void ); $this->productVariantsConsumer->processMessage($deleteMessage); //This sleep ensures that the elastic index has sufficient time to refresh - // after the records have been deleted by the _delete_by_query call. //See https://www.elastic.co/guide/en/elasticsearch/reference/6.8/docs-refresh.html#docs-refresh - sleep(3); + sleep(5); $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage(sprintf(self::ERROR_MESSAGE, $configurableId)); @@ -153,6 +152,8 @@ public function testSaveAndDeleteProductVariant(): void } /** + * Transform variant feed data in catalog storefront format + * * @param array $feedData * @return array|void */ @@ -171,6 +172,8 @@ private function formatFeedData(array $feedData) } /** + * Get product + * * @param string $sku * @return ProductInterface * @throws NoSuchEntityException @@ -185,6 +188,8 @@ private function getProduct(string $sku): ProductInterface } /** + * Delete product + * * @param string $sku * @throws NoSuchEntityException * @throws StateException diff --git a/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductsTest.php b/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductsTest.php index dfbc559ae..a92bfd08e 100644 --- a/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductsTest.php +++ b/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductsTest.php @@ -92,10 +92,10 @@ public function testSaveAndDeleteProduct() : void $this->assertEquals(self::TEST_SKU, $product->getSku()); $entitiesData = [ [ - 'entity_id' => (int) $product->getId(), + 'entity_id' => (string) $product->getId(), ] ]; - $productFeed = $this->productFeed->getFeedByIds([(int)$product->getId()], [self::STORE_CODE]); + $productFeed = $this->productFeed->getFeedByIds([(string)$product->getId()], [self::STORE_CODE]); $this->assertNotEmpty($productFeed); $updateMessage = $this->messageBuilder->build( @@ -113,7 +113,7 @@ public function testSaveAndDeleteProduct() : void $this->assertEquals($item->getSku(), $product->getSku()); $this->deleteProduct($product->getSku()); - $deletedFeed = $this->productFeed->getDeletedByIds([(int)$product->getId()], [self::STORE_CODE]); + $deletedFeed = $this->productFeed->getDeletedByIds([(string)$product->getId()], [self::STORE_CODE]); $this->assertNotEmpty($deletedFeed); $deleteMessage = $this->messageBuilder->build( From e4a31d5fe10776d8e6deb24149dce758cf11fc6c Mon Sep 17 00:00:00 2001 From: jekabs Date: Fri, 6 Nov 2020 13:17:29 +0200 Subject: [PATCH 11/23] Product variants -Test fix --- .../Test/Api/ProductVariants/ConfigurableVariantsTest.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php b/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php index b128e1a09..afd12904a 100644 --- a/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php +++ b/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php @@ -5,7 +5,7 @@ */ declare(strict_types=1); -namespace Magento\CatalogStorefront\Test\Api\ProductVariants\ConfigurableTest; +namespace Magento\CatalogStorefront\Test\Api\ProductVariants; use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\Product; @@ -76,6 +76,9 @@ public function testConfigurableProductVariants(): void $this->variantsRequestInterface->setProductId((string)$configurable->getId()); $this->variantsRequestInterface->setStore('default'); + //Seems that elastic needs time to refresh the product and variant indexes + //See https://www.elastic.co/guide/en/elasticsearch/reference/6.8/docs-refresh.html#docs-refresh + sleep(1); /** @var $variantServiceItem ProductVariantResponse */ $variantServiceItem = $this->variantService->GetProductVariants($this->variantsRequestInterface); $actual = $this->responseArrayMapper->convertToArray($variantServiceItem)['matched_variants']; @@ -101,6 +104,9 @@ public function testProductVariantsDisabledProduct(): void $this->variantsRequestInterface->setProductId((string)$configurable->getId()); $this->variantsRequestInterface->setStore('default'); + //Seems that elastic needs time to refresh the product and variant indexes + //See https://www.elastic.co/guide/en/elasticsearch/reference/6.8/docs-refresh.html#docs-refresh + sleep(1); /** @var $variantServiceItem ProductVariantResponse */ $variantServiceItem = $this->variantService->GetProductVariants($this->variantsRequestInterface); $actual = $this->responseArrayMapper->convertToArray($variantServiceItem)['matched_variants']; From 6d27f375206ef6f0a8e6f0a82a197807317aa1ed Mon Sep 17 00:00:00 2001 From: jekabs Date: Mon, 9 Nov 2020 10:36:41 +0200 Subject: [PATCH 12/23] Product variants -Extended searchEntries and other small fixes --- .../ProductVariantsDataProvider.php | 2 +- .../Storage/Client/ElasticsearchQuery.php | 28 +++++++++++++++++-- .../Model/Storage/Client/QueryInterface.php | 24 ++++++++++++---- .../Storage/Data/DocumentIteratorFactory.php | 2 +- .../Data/SearchResultIteratorFactory.php | 2 +- .../CatalogStorefront/Model/Storage/State.php | 1 + .../ConfigurableVariantsTest.php | 4 +-- .../Model/MessageBus/ProductVariantsTest.php | 5 +++- 8 files changed, 55 insertions(+), 13 deletions(-) diff --git a/app/code/Magento/CatalogStorefront/DataProvider/ProductVariantsDataProvider.php b/app/code/Magento/CatalogStorefront/DataProvider/ProductVariantsDataProvider.php index c1fda07e8..adf8fada9 100644 --- a/app/code/Magento/CatalogStorefront/DataProvider/ProductVariantsDataProvider.php +++ b/app/code/Magento/CatalogStorefront/DataProvider/ProductVariantsDataProvider.php @@ -65,7 +65,7 @@ public function fetchByProductId(int $parentId): array [VariantService::EMPTY_STORE_CODE, ProductVariant::ENTITY_NAME] ); try { - $entities = $this->query->searchEntries( + $entities = $this->query->searchFilteredEntries( $storageName, ProductVariant::ENTITY_NAME, ['parent_id' => $parentId] diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchQuery.php b/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchQuery.php index 1fdc76d5c..6f2226605 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchQuery.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchQuery.php @@ -95,15 +95,39 @@ public function getEntry(string $indexName, string $entityName, int $id, array $ /** * @inheritdoc */ - public function searchEntries(string $indexName, string $entityName, array $searchBody): EntryIteratorInterface + public function searchMatchedEntries(string $indexName, string $entityName, array $searchBody, ?string $queryContext = 'must'): EntryIteratorInterface + { + return $this->searchEntries($indexName, $entityName, $searchBody, $queryContext, 'match'); + } + + /** + * @inheritdoc + */ + public function searchFilteredEntries(string $indexName, string $entityName, array $searchBody, ?string $clauseType = 'term'): EntryIteratorInterface + { + return $this->searchEntries($indexName, $entityName, $searchBody, 'filter', $clauseType); + } + + /** + * @param string $indexName + * @param string $entityName + * @param array $searchBody + * @param string $queryContext + * @param string $clauseType + * @return EntryIteratorInterface + * @throws NotFoundException + * @throws RuntimeException + */ + private function searchEntries(string $indexName, string $entityName, array $searchBody, string $queryContext, string $clauseType): EntryIteratorInterface { $query = [ 'index' => $indexName, 'type' => $entityName, + 'body' => [] ]; foreach ($searchBody as $key => $value) { - $query['body']['query']['bool']['must'][]['match'][$key] = $value; + $query['body']['query']['bool'][$queryContext][][$clauseType][$key] = $value; } try { diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Client/QueryInterface.php b/app/code/Magento/CatalogStorefront/Model/Storage/Client/QueryInterface.php index ac781e2b2..7663e1624 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Client/QueryInterface.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Client/QueryInterface.php @@ -59,20 +59,34 @@ public function getEntries( ): EntryIteratorInterface; /** - * Search entries by specified search arguments. - * Search works using the "must match" logic. + * Search entries by specified search arguments using match query context and supplied clause type. * * $searchBody contains "search field" -> "search value". - * "search field" must be indexed. + * "search field" must be indexed in order for this query to work. * * @param string $indexName * @param string $entityName * @param array $searchBody - * + * @param string|null $queryContext * @return EntryIteratorInterface + * @throws NotFoundException + * @throws RuntimeException + */ + public function searchMatchedEntries(string $indexName, string $entityName, array $searchBody, ?string $queryContext = 'must'): EntryIteratorInterface; + + /** + * Search entries by specified search arguments using filter query context and supplied clause type. * + * $searchBody contains "search field" -> "search value". + * "search field" must be indexed in order for this query to work. + * + * @param string $indexName + * @param string $entityName + * @param array $searchBody + * @param string|null $clauseType + * @return EntryIteratorInterface * @throws NotFoundException * @throws RuntimeException */ - public function searchEntries(string $indexName, string $entityName, array $searchBody): EntryIteratorInterface; + public function searchFilteredEntries(string $indexName, string $entityName, array $searchBody, ?string $clauseType = 'term'): EntryIteratorInterface; } diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Data/DocumentIteratorFactory.php b/app/code/Magento/CatalogStorefront/Model/Storage/Data/DocumentIteratorFactory.php index 4f5ce830b..e71b3ef4a 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Data/DocumentIteratorFactory.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Data/DocumentIteratorFactory.php @@ -9,7 +9,7 @@ namespace Magento\CatalogStorefront\Model\Storage\Data; /** - * Document iterator factory. + * Factory for DocumentIterator class */ class DocumentIteratorFactory { diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Data/SearchResultIteratorFactory.php b/app/code/Magento/CatalogStorefront/Model/Storage/Data/SearchResultIteratorFactory.php index f4d6dedd2..96276e386 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Data/SearchResultIteratorFactory.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Data/SearchResultIteratorFactory.php @@ -10,7 +10,7 @@ use Magento\Framework\ObjectManagerInterface; /** - * Search result iterator factory. + * Factory for SearchResultIterator class */ class SearchResultIteratorFactory { diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/State.php b/app/code/Magento/CatalogStorefront/Model/Storage/State.php index 2fb0bd312..65b88813e 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/State.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/State.php @@ -40,6 +40,7 @@ public function getAliasName(): string /** * Get current data source name of storage taking into account version of the data source. + * * TODO: Adapt to work without store code * * @param array $scopes diff --git a/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php b/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php index afd12904a..2c64ac193 100644 --- a/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php +++ b/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php @@ -76,7 +76,7 @@ public function testConfigurableProductVariants(): void $this->variantsRequestInterface->setProductId((string)$configurable->getId()); $this->variantsRequestInterface->setStore('default'); - //Seems that elastic needs time to refresh the product and variant indexes + //This sleep ensures that the elastic index has sufficient time to refresh //See https://www.elastic.co/guide/en/elasticsearch/reference/6.8/docs-refresh.html#docs-refresh sleep(1); /** @var $variantServiceItem ProductVariantResponse */ @@ -104,7 +104,7 @@ public function testProductVariantsDisabledProduct(): void $this->variantsRequestInterface->setProductId((string)$configurable->getId()); $this->variantsRequestInterface->setStore('default'); - //Seems that elastic needs time to refresh the product and variant indexes + //This sleep ensures that the elastic index has sufficient time to refresh //See https://www.elastic.co/guide/en/elasticsearch/reference/6.8/docs-refresh.html#docs-refresh sleep(1); /** @var $variantServiceItem ProductVariantResponse */ diff --git a/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php b/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php index 9517d782c..2e7a247ee 100644 --- a/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php +++ b/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php @@ -127,6 +127,9 @@ public function testSaveAndDeleteProductVariant(): void $this->variantsGetRequestInterface->setProductId((string)$configurableId); $this->variantsGetRequestInterface->setStore(self::STORE_CODE); + //This sleep ensures that the elastic index has sufficient time to refresh + //See https://www.elastic.co/guide/en/elasticsearch/reference/6.8/docs-refresh.html#docs-refresh + sleep(1); $response = $this->variantService->GetProductVariants($this->variantsGetRequestInterface); $variants = $this->responseArrayMapper->convertToArray($response); @@ -144,7 +147,7 @@ public function testSaveAndDeleteProductVariant(): void $this->productVariantsConsumer->processMessage($deleteMessage); //This sleep ensures that the elastic index has sufficient time to refresh //See https://www.elastic.co/guide/en/elasticsearch/reference/6.8/docs-refresh.html#docs-refresh - sleep(5); + sleep(4); $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage(sprintf(self::ERROR_MESSAGE, $configurableId)); From a400541ba30319ba427b95fb5dab60c095630dac Mon Sep 17 00:00:00 2001 From: jekabs Date: Tue, 10 Nov 2020 17:25:21 +0200 Subject: [PATCH 13/23] Product variants -Added more variants to tests -Fixed search bug --- .../ProductVariantsDataProvider.php | 2 +- .../Storage/Client/ElasticsearchQuery.php | 39 +++++- .../CatalogStorefront/Model/Storage/State.php | 2 +- .../Model/VariantService.php | 9 +- .../ConfigurableVariantsTest.php | 23 +++- .../Model/MessageBus/ProductVariantsTest.php | 35 ++--- .../configurable_product_nine_simples.php | 126 ++++++++++++++++++ ...igurable_product_nine_simples_rollback.php | 53 ++++++++ ...figurable_two_attributes_three_options.php | 105 +++++++++++++++ ..._two_attributes_three_options_rollback.php | 33 +++++ 10 files changed, 392 insertions(+), 35 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_nine_simples.php create mode 100644 dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_nine_simples_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_two_attributes_three_options.php create mode 100644 dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_two_attributes_three_options_rollback.php diff --git a/app/code/Magento/CatalogStorefront/DataProvider/ProductVariantsDataProvider.php b/app/code/Magento/CatalogStorefront/DataProvider/ProductVariantsDataProvider.php index adf8fada9..6fff424fd 100644 --- a/app/code/Magento/CatalogStorefront/DataProvider/ProductVariantsDataProvider.php +++ b/app/code/Magento/CatalogStorefront/DataProvider/ProductVariantsDataProvider.php @@ -60,7 +60,7 @@ public function __construct( */ public function fetchByProductId(int $parentId): array { - // todo: Adapt to work without store code + // TODO: Adapt to work without store code https://github.com/magento/catalog-storefront/issues/417 $storageName = $this->storageState->getCurrentDataSourceName( [VariantService::EMPTY_STORE_CODE, ProductVariant::ENTITY_NAME] ); diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchQuery.php b/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchQuery.php index 6f2226605..5c2464e40 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchQuery.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchQuery.php @@ -21,6 +21,9 @@ */ class ElasticsearchQuery implements QueryInterface { + //TODO: Add pagination and remove max size search size https://github.com/magento/catalog-storefront/issues/418 + private const SEARCH_LIMIT = 5000; + /** * @var ConnectionPull */ @@ -95,16 +98,24 @@ public function getEntry(string $indexName, string $entityName, int $id, array $ /** * @inheritdoc */ - public function searchMatchedEntries(string $indexName, string $entityName, array $searchBody, ?string $queryContext = 'must'): EntryIteratorInterface - { + public function searchMatchedEntries( + string $indexName, + string $entityName, + array $searchBody, + ?string $queryContext = 'must' + ): EntryIteratorInterface { return $this->searchEntries($indexName, $entityName, $searchBody, $queryContext, 'match'); } /** * @inheritdoc */ - public function searchFilteredEntries(string $indexName, string $entityName, array $searchBody, ?string $clauseType = 'term'): EntryIteratorInterface - { + public function searchFilteredEntries( + string $indexName, + string $entityName, + array $searchBody, + ?string $clauseType = 'term' + ): EntryIteratorInterface { return $this->searchEntries($indexName, $entityName, $searchBody, 'filter', $clauseType); } @@ -118,12 +129,19 @@ public function searchFilteredEntries(string $indexName, string $entityName, arr * @throws NotFoundException * @throws RuntimeException */ - private function searchEntries(string $indexName, string $entityName, array $searchBody, string $queryContext, string $clauseType): EntryIteratorInterface - { + private function searchEntries( + string $indexName, + string $entityName, + array $searchBody, + string $queryContext, + string $clauseType + ): EntryIteratorInterface { + //TODO: Add pagination and remove max size search size https://github.com/magento/catalog-storefront/issues/418 $query = [ 'index' => $indexName, 'type' => $entityName, - 'body' => [] + 'body' => [], + 'size' => self::SEARCH_LIMIT ]; foreach ($searchBody as $key => $value) { @@ -138,6 +156,13 @@ private function searchEntries(string $indexName, string $entityName, array $sea $throwable ); } + //TODO: Add pagination and remove max size search size https://github.com/magento/catalog-storefront/issues/418 + if (isset($result['hits']['total']['value']) && $result['hits']['total']['value'] > self::SEARCH_LIMIT) { + throw new \OverflowException( + "Storage error: Search returned too many results to handle. Query was: " . \json_encode($query) + ); + } + $this->checkErrors($result, $indexName); return $this->searchResultIteratorFactory->create($result); diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/State.php b/app/code/Magento/CatalogStorefront/Model/Storage/State.php index 65b88813e..2ff1dad97 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/State.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/State.php @@ -41,7 +41,7 @@ public function getAliasName(): string /** * Get current data source name of storage taking into account version of the data source. * - * TODO: Adapt to work without store code + * TODO: Adapt to work without store code https://github.com/magento/catalog-storefront/issues/417 * * @param array $scopes * @return string diff --git a/app/code/Magento/CatalogStorefront/Model/VariantService.php b/app/code/Magento/CatalogStorefront/Model/VariantService.php index 8be5cba71..0d99b83c1 100644 --- a/app/code/Magento/CatalogStorefront/Model/VariantService.php +++ b/app/code/Magento/CatalogStorefront/Model/VariantService.php @@ -36,7 +36,7 @@ class VariantService implements VariantServiceServerInterface { /** * Temporary store placeholder - * TODO: Adapt to work without store code and remove this constant + * TODO: Adapt to work without store code https://github.com/magento/catalog-storefront/issues/417 and remove this constant */ public const EMPTY_STORE_CODE = ''; @@ -141,7 +141,7 @@ public function ImportProductVariants(ImportVariantsRequestInterface $request): 'product_id' => $childId, 'parent_id' => $parentId ]; - //TODO: Adapt to work without store code + //TODO: Adapt to work without store code https://github.com/magento/catalog-storefront/issues/417 $variantsInElasticFormat['product_variant'][self::EMPTY_STORE_CODE][CatalogRepository::SAVE][] = $variant; } @@ -177,7 +177,7 @@ public function DeleteProductVariants(DeleteVariantsRequestInterface $request): $variantsInElasticFormat = [ 'product_variant' => [ - //TODO: Adapt to work without store code + //TODO: Adapt to work without store code https://github.com/magento/catalog-storefront/issues/417 self::EMPTY_STORE_CODE => [ CatalogRepository::DELETE_BY_QUERY => $deleteFields ] @@ -203,6 +203,7 @@ public function DeleteProductVariants(DeleteVariantsRequestInterface $request): * Get product variants from storage. * * Only variants whose corresponding products are 'enabled' and stored in storage are returned. + * TODO: Add pagination https://github.com/magento/catalog-storefront/issues/418 * * @param ProductVariantRequestInterface $request * @return ProductVariantResponseInterface @@ -212,7 +213,7 @@ public function DeleteProductVariants(DeleteVariantsRequestInterface $request): */ public function GetProductVariants(ProductVariantRequestInterface $request): ProductVariantResponseInterface { - $productId = $request->getProductId(); //todo test with null here from test. + $productId = $request->getProductId(); $store = $request->getStore(); $rawVariants = $this->productVariantsDataProvider->fetchByProductId((int)$productId); diff --git a/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php b/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php index 2c64ac193..c43b73929 100644 --- a/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php +++ b/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php @@ -59,19 +59,30 @@ protected function setUp(): void /** * Validate configurable product variants data * - * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable_sku.php + * @magentoApiDataFixture Magento/ConfigurableProduct/_files/configurable_product_nine_simples.php * @magentoDbIsolation disabled * @throws NoSuchEntityException * @throws \Throwable */ public function testConfigurableProductVariants(): void { + $simpleSkus = [ + 'simple_0', + 'simple_1', + 'simple_2', + 'simple_3', + 'simple_4', + 'simple_5', + 'simple_6', + 'simple_7', + 'simple_8' + ]; /** @var $configurable Product */ $configurable = $this->productRepository->get('configurable'); - $simples = [ - $this->productRepository->get('simple_10'), - $this->productRepository->get('simple_20') - ]; + $simples = []; + foreach ($simpleSkus as $sku) { + $simples[] = $this->productRepository->get($sku); + } $this->variantsRequestInterface->setProductId((string)$configurable->getId()); $this->variantsRequestInterface->setStore('default'); @@ -84,7 +95,7 @@ public function testConfigurableProductVariants(): void $actual = $this->responseArrayMapper->convertToArray($variantServiceItem)['matched_variants']; $expected = $this->getExpectedProductVariants($configurable, $simples); - self::assertCount(2, $actual); + self::assertCount(9, $actual); $this->compare($expected, $actual); } diff --git a/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php b/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php index 2e7a247ee..c9b07657e 100644 --- a/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php +++ b/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php @@ -30,8 +30,17 @@ class ProductVariantsTest extends StorefrontTestsAbstract { const CONFIGURABLE_SKU = 'configurable'; - const SIMPLE1_SKU = 'simple_10'; - const SIMPLE2_SKU = 'simple_20'; + const SIMPLE_SKUS = [ + 'simple_0', + 'simple_1', + 'simple_2', + 'simple_3', + 'simple_4', + 'simple_5', + 'simple_6', + 'simple_7', + 'simple_8' + ]; const STORE_CODE = 'default'; const ERROR_MESSAGE = 'No products variants for product with id %s are found in catalog.'; @@ -91,7 +100,7 @@ protected function setUp(): void /** * Validate save and delete product variant operations * - * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable_sku.php + * @magentoApiDataFixture Magento/ConfigurableProduct/_files/configurable_product_nine_simples.php * @magentoDbIsolation disabled * @throws NoSuchEntityException * @throws StateException @@ -101,22 +110,16 @@ public function testSaveAndDeleteProductVariant(): void { $configurable = $this->getProduct(self::CONFIGURABLE_SKU); $configurableId = $configurable->getId(); - $simple1 = $this->getProduct(self::SIMPLE1_SKU); - $simple1Id = $simple1->getId(); - $simple2 = $this->getProduct(self::SIMPLE2_SKU); - $simple2Id = $simple2->getId(); - $entitiesData = [ - [ - 'entity_id' => \sprintf('configurable/%1$s/%2$s', $configurableId, $simple1Id) - ], - [ - 'entity_id' => \sprintf('configurable/%1$s/%2$s', $configurableId, $simple2Id) - ] - ]; + + $entitiesData = []; + foreach (self::SIMPLE_SKUS as $simpleSku) { + $simpleId = $this->getProduct($simpleSku)->getId(); + $entitiesData[]['entity_id'] = \sprintf('configurable/%1$s/%2$s', $configurableId, $simpleId); + } $productVariantFeed = $this->productVariantFeed->getFeedByProductIds([$configurableId]); $this->assertNotEmpty($productVariantFeed['feed']); - $this->assertCount(2, $productVariantFeed['feed']); + $this->assertCount(9, $productVariantFeed['feed']); $expectedData = $this->formatFeedData($productVariantFeed['feed']); $updateMessage = $this->messageBuilder->build( diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_nine_simples.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_nine_simples.php new file mode 100644 index 000000000..e1bc567f2 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_nine_simples.php @@ -0,0 +1,126 @@ +requireDataFixture( + 'Magento/ConfigurableProduct/_files/configurable_two_attributes_three_options.php' +); + +/** @var ObjectManagerInterface $objectManager */ +$objectManager = Bootstrap::getObjectManager(); +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager + ->get(ProductRepositoryInterface::class); +/** @var AttributeRepository $attributeRepository */ +$attributeRepository = $objectManager->create(AttributeRepository::class); +/** @var WebsiteRepositoryInterface $websiteRepository */ +$websiteRepository = $objectManager->get(WebsiteRepositoryInterface::class); +$defaultWebsiteId = $websiteRepository->get('base')->getId(); + +/** @var $installer CategorySetup */ +$installer = $objectManager->create(CategorySetup::class); +$attributeSetId = $installer->getAttributeSetId('catalog_product', 'Default'); + +/** Get attributes */ +$colorAttribute = $attributeRepository->get('catalog_product', 'color_test'); +$sizeAttribute = $attributeRepository->get('catalog_product', 'size_test'); +$colorAttributeOptions = $colorAttribute->getOptions(); +$sizeAttributeOptions = $sizeAttribute->getOptions(); + +//remove the first option which is empty +array_shift($sizeAttributeOptions); +array_shift($colorAttributeOptions); + +/** Create simple products */ +$associatedProductIds = []; +$colorAttributeValues = []; +$sizeAttributeValues = []; +$i = 0; +foreach ($colorAttributeOptions as $colorOption) { + foreach ($sizeAttributeOptions as $sizeOption) { + /** @var $childProduct Product */ + $childProduct = $objectManager->create(Product::class); + $childProduct->setTypeId(Type::TYPE_SIMPLE) + ->setAttributeSetId($attributeSetId) + ->setWebsiteIds([$defaultWebsiteId]) + ->setName('Simple ' . $colorOption->getLabel() . '-' . $sizeOption->getLabel()) + ->setSku('simple_' . $i) + ->setPrice(45) + ->setVisibility(Visibility::VISIBILITY_NOT_VISIBLE) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]) + ->setColorTest($colorOption->getValue()) + ->setSizeTest($sizeOption->getValue()); + + $childProduct = $productRepository->save($childProduct); + + $colorAttributeValues[] = [ + 'label' => 'color test ' . $i, + 'attribute_id' => $colorAttribute->getId(), + 'value_index' => $colorOption->getValue(), + ]; + $sizeAttributeValues[] = [ + 'label' => 'size test ' . $i, + 'attribute_id' => $sizeAttribute->getId(), + 'value_index' => $sizeOption->getValue(), + ]; + $associatedProductIds[] = $childProduct->getId(); + $i++; + } +} + +/** Create configurable product */ +/** @var Factory $optionsFactory */ +$optionsFactory = $objectManager->create(Factory::class); +$configurableAttributesData = [ + [ + 'attribute_id' => $colorAttribute->getId(), + 'code' => $colorAttribute->getAttributeCode(), + 'label' => $colorAttribute->getStoreLabel(), + 'position' => '0', + 'values' => $colorAttributeValues, + ], + [ + 'attribute_id' => $sizeAttribute->getId(), + 'code' => $sizeAttribute->getAttributeCode(), + 'label' => $sizeAttribute->getStoreLabel(), + 'position' => '1', + 'values' => $sizeAttributeValues, + ], +]; + +$configurableProduct = $objectManager->create(Product::class); +$configurableProduct->setTypeId(Configurable::TYPE_CODE) + ->setAttributeSetId($attributeSetId) + ->setWebsiteIds([$defaultWebsiteId]) + ->setName('Configurable Product') + ->setSku('configurable') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 1, 'is_in_stock' => 1]); +$productRepository = Bootstrap::getObjectManager()->get(ProductRepositoryInterface::class); + +$configurableOptions = $optionsFactory->create($configurableAttributesData); +$extensionConfigurableAttributes = $configurableProduct->getExtensionAttributes(); +$extensionConfigurableAttributes->setConfigurableProductOptions($configurableOptions); +$extensionConfigurableAttributes->setConfigurableProductLinks($associatedProductIds); +$configurableProduct->setExtensionAttributes($extensionConfigurableAttributes); + +$productRepository->save($configurableProduct); diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_nine_simples_rollback.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_nine_simples_rollback.php new file mode 100644 index 000000000..1d4f25cc0 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_product_nine_simples_rollback.php @@ -0,0 +1,53 @@ +get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ +$productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); +//simple_' . $colorOption->getLabel() . '-' . $sizeOption->getLabel() +$productsToDelete = [ + 'simple_0', + 'simple_1', + 'simple_2', + 'simple_3', + 'simple_4', + 'simple_5', + 'simple_6', + 'simple_7', + 'simple_8', + 'configurable' +]; + +foreach ($productsToDelete as $sku) { + try { + $product = $productRepository->get($sku, true); + + $stockStatus = $objectManager->create(\Magento\CatalogInventory\Model\Stock\Status::class); + $stockStatus->load($product->getEntityId(), 'product_id'); + $stockStatus->delete(); + + $productRepository->delete($product); + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + //Product already removed + } +} + +Resolver::getInstance()->requireDataFixture( + 'Magento/ConfigurableProduct/_files/configurable_two_attributes_three_options_rollback.php' +); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_two_attributes_three_options.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_two_attributes_three_options.php new file mode 100644 index 000000000..e5d9e0743 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_two_attributes_three_options.php @@ -0,0 +1,105 @@ +create(AttributeRepositoryInterface::class); + + +$eavConfig = $objectManager->get(Config::class); +$colorAttribute = $eavConfig->getAttribute('catalog_product', 'color_test'); +$sizeAttribute = $eavConfig->getAttribute('catalog_product', 'size_test'); +$eavConfig->clear(); + + +/** @var CategorySetup $installer */ +$installer = $objectManager->create(CategorySetup::class); + + +if (!$sizeAttribute->getId()) { + /** @var Attribute $sizeAttribute */ + $sizeAttribute = $objectManager->create(Attribute::class); + $sizeAttribute->setData( + [ + 'attribute_code' => 'size_test', + 'entity_type_id' => $installer->getEntityTypeId('catalog_product'), + 'is_global' => 1, + 'is_user_defined' => 1, + 'frontend_input' => 'select', + 'is_unique' => 0, + 'is_required' => 0, + 'is_searchable' => 0, + 'is_visible_in_advanced_search' => 0, + 'is_comparable' => 0, + 'is_filterable' => 0, + 'is_filterable_in_search' => 0, + 'is_used_for_promo_rules' => 0, + 'is_html_allowed_on_front' => 1, + 'is_visible_on_front' => 0, + 'used_in_product_listing' => 0, + 'used_for_sort_by' => 0, + 'frontend_label' => ['Size Test'], + 'backend_type' => 'int', + 'option' => [ + 'value' => [ + 'small' => ['Small'], + 'medium' => ['Medium'], + 'large' => ['Large'] + ], + 'order' => ['small' => 0, 'medium' => 1, 'large' => 2], + ] + ] + ); + $attributeRepository->save($sizeAttribute); + $installer->addAttributeToGroup('catalog_product', 'Default', 'General', $sizeAttribute->getId()); +} + +if (!$colorAttribute->getId()) { + /** @var Attribute $colorAttribute */ + $colorAttribute = $objectManager->create(Attribute::class); + $colorAttribute->setData( + [ + 'attribute_code' => 'color_test', + 'entity_type_id' => $installer->getEntityTypeId('catalog_product'), + 'is_global' => 1, + 'is_user_defined' => 1, + 'frontend_input' => 'select', + 'is_unique' => 0, + 'is_required' => 0, + 'is_searchable' => 0, + 'is_visible_in_advanced_search' => 0, + 'is_comparable' => 0, + 'is_filterable' => 0, + 'is_filterable_in_search' => 0, + 'is_used_for_promo_rules' => 0, + 'is_html_allowed_on_front' => 1, + 'is_visible_on_front' => 0, + 'used_in_product_listing' => 0, + 'used_for_sort_by' => 0, + 'frontend_label' => ['Color Test'], + 'backend_type' => 'int', + 'option' => [ + 'value' => [ + 'red' => ['Red'], + 'blue' => ['Blue'], + 'green' => ['Green'], + ], + 'order' => ['red' => 0, 'blue' => 1, 'green' => 2], + ], + ] + ); + $attributeRepository->save($colorAttribute); + $installer->addAttributeToGroup('catalog_product', 'Default', 'General', $colorAttribute->getId()); +} + +$eavConfig->clear(); diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_two_attributes_three_options_rollback.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_two_attributes_three_options_rollback.php new file mode 100644 index 000000000..ce2180a3b --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_two_attributes_three_options_rollback.php @@ -0,0 +1,33 @@ +get(Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); +$attributeCodes = ['color_test', 'size_test']; +foreach ($attributeCodes as $attributeCode) { + try { + /** @var Attribute $attribute */ + $attribute = $objectManager->create(Attribute::class); + $attribute->load($attributeCode, 'attribute_code'); + if ($attribute->getId()) { + $attribute->delete(); + } + } catch (Exception $e) { + // Nothing to delete + } +} +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); From 546c3236eb012b4b6dbe98ebd3cacd82235a309e Mon Sep 17 00:00:00 2001 From: ruslankostiv Date: Tue, 10 Nov 2020 14:42:03 -0600 Subject: [PATCH 14/23] 27: Product variants --- .../Storage/Client/ElasticsearchQuery.php | 2 + .../Model/Storage/Client/QueryInterface.php | 7 +- .../Model/VariantService.php | 3 +- .../Api/InMemoryVariantService.php | 24 +++---- .../Api/VariantService.php | 64 ++++++++--------- .../Api/VariantServiceInterface.php | 16 ++--- .../Api/VariantServiceProxyServer.php | 72 +++++++++---------- .../Api/VariantServiceServerInterface.php | 16 ++--- .../CatalogStorefrontApi/Metadata/Catalog.php | 8 +-- .../Proto/VariantServiceClient.php | 16 ++--- .../Proto/VariantServiceInterface.php | 8 +-- .../Console/Command/ProtoMarshalCommand.php | 3 +- app/code/Magento/Grpc/README.md | 2 +- 13 files changed, 125 insertions(+), 116 deletions(-) diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchQuery.php b/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchQuery.php index 5c2464e40..3ca6ba0a7 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchQuery.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Client/ElasticsearchQuery.php @@ -120,6 +120,8 @@ public function searchFilteredEntries( } /** + * Searches entries into elastic search storage. + * * @param string $indexName * @param string $entityName * @param array $searchBody diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Client/QueryInterface.php b/app/code/Magento/CatalogStorefront/Model/Storage/Client/QueryInterface.php index 7663e1624..91d572ab2 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Client/QueryInterface.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Client/QueryInterface.php @@ -72,7 +72,12 @@ public function getEntries( * @throws NotFoundException * @throws RuntimeException */ - public function searchMatchedEntries(string $indexName, string $entityName, array $searchBody, ?string $queryContext = 'must'): EntryIteratorInterface; + public function searchMatchedEntries( + string $indexName, + string $entityName, + array $searchBody, + ?string $queryContext = 'must' + ): EntryIteratorInterface; /** * Search entries by specified search arguments using filter query context and supplied clause type. diff --git a/app/code/Magento/CatalogStorefront/Model/VariantService.php b/app/code/Magento/CatalogStorefront/Model/VariantService.php index 0d99b83c1..09e68d506 100644 --- a/app/code/Magento/CatalogStorefront/Model/VariantService.php +++ b/app/code/Magento/CatalogStorefront/Model/VariantService.php @@ -36,7 +36,8 @@ class VariantService implements VariantServiceServerInterface { /** * Temporary store placeholder - * TODO: Adapt to work without store code https://github.com/magento/catalog-storefront/issues/417 and remove this constant + * TODO: Adapt to work without store code + * https://github.com/magento/catalog-storefront/issues/417 and remove this constant */ public const EMPTY_STORE_CODE = ''; diff --git a/app/code/Magento/CatalogStorefrontApi/Api/InMemoryVariantService.php b/app/code/Magento/CatalogStorefrontApi/Api/InMemoryVariantService.php index e1fc92573..7dde8846a 100644 --- a/app/code/Magento/CatalogStorefrontApi/Api/InMemoryVariantService.php +++ b/app/code/Magento/CatalogStorefrontApi/Api/InMemoryVariantService.php @@ -40,46 +40,46 @@ public function __construct( } /** - * Autogenerated description for ImportProductVariants in memory client service method + * Autogenerated description for importProductVariants in memory client service method * * @param ImportVariantsRequestInterface $request * @return ImportVariantsResponseInterface */ - public function ImportProductVariants(ImportVariantsRequestInterface $request): ImportVariantsResponseInterface + public function importProductVariants(ImportVariantsRequestInterface $request): ImportVariantsResponseInterface { - return $this->service->ImportProductVariants($request); + return $this->service->importProductVariants($request); } /** - * Autogenerated description for DeleteProductVariants in memory client service method + * Autogenerated description for deleteProductVariants in memory client service method * * @param DeleteVariantsRequestInterface $request * @return DeleteVariantsResponseInterface */ - public function DeleteProductVariants(DeleteVariantsRequestInterface $request): DeleteVariantsResponseInterface + public function deleteProductVariants(DeleteVariantsRequestInterface $request): DeleteVariantsResponseInterface { - return $this->service->DeleteProductVariants($request); + return $this->service->deleteProductVariants($request); } /** - * Autogenerated description for GetProductVariants in memory client service method + * Autogenerated description for getProductVariants in memory client service method * * @param ProductVariantRequestInterface $request * @return ProductVariantResponseInterface */ - public function GetProductVariants(ProductVariantRequestInterface $request): ProductVariantResponseInterface + public function getProductVariants(ProductVariantRequestInterface $request): ProductVariantResponseInterface { - return $this->service->GetProductVariants($request); + return $this->service->getProductVariants($request); } /** - * Autogenerated description for GetVariantsMatch in memory client service method + * Autogenerated description for getVariantsMatch in memory client service method * * @param OptionSelectionRequestInterface $request * @return ProductVariantResponseInterface */ - public function GetVariantsMatch(OptionSelectionRequestInterface $request): ProductVariantResponseInterface + public function getVariantsMatch(OptionSelectionRequestInterface $request): ProductVariantResponseInterface { - return $this->service->GetVariantsMatch($request); + return $this->service->getVariantsMatch($request); } } diff --git a/app/code/Magento/CatalogStorefrontApi/Api/VariantService.php b/app/code/Magento/CatalogStorefrontApi/Api/VariantService.php index dbb7ec5ed..52e1ffd0f 100644 --- a/app/code/Magento/CatalogStorefrontApi/Api/VariantService.php +++ b/app/code/Magento/CatalogStorefrontApi/Api/VariantService.php @@ -58,23 +58,23 @@ public function __construct( * @return ImportVariantsResponseInterface * @throws \Throwable */ - public function ImportProductVariants(ImportVariantsRequestInterface $request): ImportVariantsResponseInterface + public function importProductVariants(ImportVariantsRequestInterface $request): ImportVariantsResponseInterface { - $protoRequest = $this->ImportProductVariantsToProto($request); - [$protoResult, $status] = $this->protoClient->ImportProductVariants($protoRequest)->wait(); + $protoRequest = $this->importProductVariantsToProto($request); + [$protoResult, $status] = $this->protoClient->importProductVariants($protoRequest)->wait(); if ($status->code !== 0) { throw new \RuntimeException($status->details, $status->code); } - return $this->ImportProductVariantsFromProto($protoResult); + return $this->importProductVariantsFromProto($protoResult); } /** - * Autogenerated description for ImportProductVariants method + * Autogenerated description for importProductVariants method * * @param ImportVariantsRequestInterface $value * @return ImportVariantsRequest */ - private function ImportProductVariantsToProto(ImportVariantsRequestInterface $value): ImportVariantsRequest + private function importProductVariantsToProto(ImportVariantsRequestInterface $value): ImportVariantsRequest { // convert data from \Magento\CatalogStorefrontApi\Api\Data\ImportVariantsRequest // to \Magento\CatalogStorefrontApi\Proto\ImportVariantsRequest @@ -108,13 +108,13 @@ private function ImportProductVariantsToProto(ImportVariantsRequestInterface $va } /** - * Autogenerated description for ImportProductVariants method + * Autogenerated description for importProductVariants method * * @param ImportVariantsResponse $value * @return ImportVariantsResponseInterface * phpcs:disable Generic.Metrics.NestingLevel.TooHigh */ - private function ImportProductVariantsFromProto(ImportVariantsResponse $value): ImportVariantsResponseInterface + private function importProductVariantsFromProto(ImportVariantsResponse $value): ImportVariantsResponseInterface { // convert data from \Magento\CatalogStorefrontApi\Proto\ImportVariantsResponse // to \Magento\CatalogStorefrontApi\Api\Data\ImportVariantsResponse @@ -137,23 +137,23 @@ private function ImportProductVariantsFromProto(ImportVariantsResponse $value): * @return DeleteVariantsResponseInterface * @throws \Throwable */ - public function DeleteProductVariants(DeleteVariantsRequestInterface $request): DeleteVariantsResponseInterface + public function deleteProductVariants(DeleteVariantsRequestInterface $request): DeleteVariantsResponseInterface { - $protoRequest = $this->DeleteProductVariantsToProto($request); - [$protoResult, $status] = $this->protoClient->DeleteProductVariants($protoRequest)->wait(); + $protoRequest = $this->deleteProductVariantsToProto($request); + [$protoResult, $status] = $this->protoClient->deleteProductVariants($protoRequest)->wait(); if ($status->code !== 0) { throw new \RuntimeException($status->details, $status->code); } - return $this->DeleteProductVariantsFromProto($protoResult); + return $this->deleteProductVariantsFromProto($protoResult); } /** - * Autogenerated description for DeleteProductVariants method + * Autogenerated description for deleteProductVariants method * * @param DeleteVariantsRequestInterface $value * @return DeleteVariantsRequest */ - private function DeleteProductVariantsToProto(DeleteVariantsRequestInterface $value): DeleteVariantsRequest + private function deleteProductVariantsToProto(DeleteVariantsRequestInterface $value): DeleteVariantsRequest { // convert data from \Magento\CatalogStorefrontApi\Api\Data\DeleteVariantsRequest // to \Magento\CatalogStorefrontApi\Proto\DeleteVariantsRequest @@ -173,13 +173,13 @@ private function DeleteProductVariantsToProto(DeleteVariantsRequestInterface $va } /** - * Autogenerated description for DeleteProductVariants method + * Autogenerated description for deleteProductVariants method * * @param DeleteVariantsResponse $value * @return DeleteVariantsResponseInterface * phpcs:disable Generic.Metrics.NestingLevel.TooHigh */ - private function DeleteProductVariantsFromProto(DeleteVariantsResponse $value): DeleteVariantsResponseInterface + private function deleteProductVariantsFromProto(DeleteVariantsResponse $value): DeleteVariantsResponseInterface { // convert data from \Magento\CatalogStorefrontApi\Proto\DeleteVariantsResponse // to \Magento\CatalogStorefrontApi\Api\Data\DeleteVariantsResponse @@ -202,23 +202,23 @@ private function DeleteProductVariantsFromProto(DeleteVariantsResponse $value): * @return ProductVariantResponseInterface * @throws \Throwable */ - public function GetProductVariants(ProductVariantRequestInterface $request): ProductVariantResponseInterface + public function getProductVariants(ProductVariantRequestInterface $request): ProductVariantResponseInterface { - $protoRequest = $this->GetProductVariantsToProto($request); - [$protoResult, $status] = $this->protoClient->GetProductVariants($protoRequest)->wait(); + $protoRequest = $this->getProductVariantsToProto($request); + [$protoResult, $status] = $this->protoClient->getProductVariants($protoRequest)->wait(); if ($status->code !== 0) { throw new \RuntimeException($status->details, $status->code); } - return $this->GetProductVariantsFromProto($protoResult); + return $this->getProductVariantsFromProto($protoResult); } /** - * Autogenerated description for GetProductVariants method + * Autogenerated description for getProductVariants method * * @param ProductVariantRequestInterface $value * @return ProductVariantRequest */ - private function GetProductVariantsToProto(ProductVariantRequestInterface $value): ProductVariantRequest + private function getProductVariantsToProto(ProductVariantRequestInterface $value): ProductVariantRequest { // convert data from \Magento\CatalogStorefrontApi\Api\Data\ProductVariantRequest // to \Magento\CatalogStorefrontApi\Proto\ProductVariantRequest @@ -235,13 +235,13 @@ private function GetProductVariantsToProto(ProductVariantRequestInterface $value } /** - * Autogenerated description for GetProductVariants method + * Autogenerated description for getProductVariants method * * @param ProductVariantResponse $value * @return ProductVariantResponseInterface * phpcs:disable Generic.Metrics.NestingLevel.TooHigh */ - private function GetProductVariantsFromProto(ProductVariantResponse $value): ProductVariantResponseInterface + private function getProductVariantsFromProto(ProductVariantResponse $value): ProductVariantResponseInterface { // convert data from \Magento\CatalogStorefrontApi\Proto\ProductVariantResponse // to \Magento\CatalogStorefrontApi\Api\Data\ProductVariantResponse @@ -282,23 +282,23 @@ private function GetProductVariantsFromProto(ProductVariantResponse $value): Pro * @return ProductVariantResponseInterface * @throws \Throwable */ - public function GetVariantsMatch(OptionSelectionRequestInterface $request): ProductVariantResponseInterface + public function getVariantsMatch(OptionSelectionRequestInterface $request): ProductVariantResponseInterface { - $protoRequest = $this->GetVariantsMatchToProto($request); - [$protoResult, $status] = $this->protoClient->GetVariantsMatch($protoRequest)->wait(); + $protoRequest = $this->getVariantsMatchToProto($request); + [$protoResult, $status] = $this->protoClient->getVariantsMatch($protoRequest)->wait(); if ($status->code !== 0) { throw new \RuntimeException($status->details, $status->code); } - return $this->GetVariantsMatchFromProto($protoResult); + return $this->getVariantsMatchFromProto($protoResult); } /** - * Autogenerated description for GetVariantsMatch method + * Autogenerated description for getVariantsMatch method * * @param OptionSelectionRequestInterface $value * @return OptionSelectionRequest */ - private function GetVariantsMatchToProto(OptionSelectionRequestInterface $value): OptionSelectionRequest + private function getVariantsMatchToProto(OptionSelectionRequestInterface $value): OptionSelectionRequest { // convert data from \Magento\CatalogStorefrontApi\Api\Data\OptionSelectionRequest // to \Magento\CatalogStorefrontApi\Proto\OptionSelectionRequest @@ -319,13 +319,13 @@ private function GetVariantsMatchToProto(OptionSelectionRequestInterface $value) } /** - * Autogenerated description for GetVariantsMatch method + * Autogenerated description for getVariantsMatch method * * @param ProductVariantResponse $value * @return ProductVariantResponseInterface * phpcs:disable Generic.Metrics.NestingLevel.TooHigh */ - private function GetVariantsMatchFromProto(ProductVariantResponse $value): ProductVariantResponseInterface + private function getVariantsMatchFromProto(ProductVariantResponse $value): ProductVariantResponseInterface { // convert data from \Magento\CatalogStorefrontApi\Proto\ProductVariantResponse // to \Magento\CatalogStorefrontApi\Api\Data\ProductVariantResponse diff --git a/app/code/Magento/CatalogStorefrontApi/Api/VariantServiceInterface.php b/app/code/Magento/CatalogStorefrontApi/Api/VariantServiceInterface.php index 47bcff6aa..d53e3a07e 100644 --- a/app/code/Magento/CatalogStorefrontApi/Api/VariantServiceInterface.php +++ b/app/code/Magento/CatalogStorefrontApi/Api/VariantServiceInterface.php @@ -24,38 +24,38 @@ interface VariantServiceInterface { /** - * Autogenerated description for ImportProductVariants interface method + * Autogenerated description for importProductVariants interface method * * @param ImportVariantsRequestInterface $request * @return ImportVariantsResponseInterface * @throws \Throwable */ - public function ImportProductVariants(ImportVariantsRequestInterface $request): ImportVariantsResponseInterface; + public function importProductVariants(ImportVariantsRequestInterface $request): ImportVariantsResponseInterface; /** - * Autogenerated description for DeleteProductVariants interface method + * Autogenerated description for deleteProductVariants interface method * * @param DeleteVariantsRequestInterface $request * @return DeleteVariantsResponseInterface * @throws \Throwable */ - public function DeleteProductVariants(DeleteVariantsRequestInterface $request): DeleteVariantsResponseInterface; + public function deleteProductVariants(DeleteVariantsRequestInterface $request): DeleteVariantsResponseInterface; /** - * Autogenerated description for GetProductVariants interface method + * Autogenerated description for getProductVariants interface method * * @param ProductVariantRequestInterface $request * @return ProductVariantResponseInterface * @throws \Throwable */ - public function GetProductVariants(ProductVariantRequestInterface $request): ProductVariantResponseInterface; + public function getProductVariants(ProductVariantRequestInterface $request): ProductVariantResponseInterface; /** - * Autogenerated description for GetVariantsMatch interface method + * Autogenerated description for getVariantsMatch interface method * * @param OptionSelectionRequestInterface $request * @return ProductVariantResponseInterface * @throws \Throwable */ - public function GetVariantsMatch(OptionSelectionRequestInterface $request): ProductVariantResponseInterface; + public function getVariantsMatch(OptionSelectionRequestInterface $request): ProductVariantResponseInterface; } diff --git a/app/code/Magento/CatalogStorefrontApi/Api/VariantServiceProxyServer.php b/app/code/Magento/CatalogStorefrontApi/Api/VariantServiceProxyServer.php index e79790288..2b1abe936 100644 --- a/app/code/Magento/CatalogStorefrontApi/Api/VariantServiceProxyServer.php +++ b/app/code/Magento/CatalogStorefrontApi/Api/VariantServiceProxyServer.php @@ -48,19 +48,19 @@ public function __construct( } /** - * Autogenerated description for ImportProductVariants method + * Autogenerated description for importProductVariants method * * @param \Spiral\GRPC\ContextInterface $ctx * @param ImportVariantsRequest $in * @return ImportVariantsResponse * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function ImportProductVariants(\Spiral\GRPC\ContextInterface $ctx, ImportVariantsRequest $in): ImportVariantsResponse + public function importProductVariants(\Spiral\GRPC\ContextInterface $ctx, ImportVariantsRequest $in): ImportVariantsResponse { try { - $magentoDtoRequest = $this->ImportProductVariantsFromProto($in); - $magentoDtoResponse = $this->service->ImportProductVariants($magentoDtoRequest); - return $this->ImportProductVariantsToProto($magentoDtoResponse); + $magentoDtoRequest = $this->importProductVariantsFromProto($in); + $magentoDtoResponse = $this->service->importProductVariants($magentoDtoRequest); + return $this->importProductVariantsToProto($magentoDtoResponse); } catch (\Exception $e) { throw new \Spiral\GRPC\Exception\InvokeException( $e->getMessage(), @@ -72,12 +72,12 @@ public function ImportProductVariants(\Spiral\GRPC\ContextInterface $ctx, Import } /** - * Autogenerated description for ImportProductVariants method + * Autogenerated description for importProductVariants method * * @param ImportVariantsRequest $value * @return ImportVariantsRequestInterface */ - private function ImportProductVariantsFromProto(ImportVariantsRequest $value): ImportVariantsRequestInterface + private function importProductVariantsFromProto(ImportVariantsRequest $value): ImportVariantsRequestInterface { // convert data from \Magento\CatalogStorefrontApi\Proto\ImportVariantsRequest // to \Magento\CatalogStorefrontApi\Api\Data\ImportVariantsRequest @@ -111,13 +111,13 @@ private function ImportProductVariantsFromProto(ImportVariantsRequest $value): I } /** - * Autogenerated description for ImportProductVariants method + * Autogenerated description for importProductVariants method * * @param ImportVariantsResponseInterface $value * @return ImportVariantsResponse * phpcs:disable Generic.Metrics.NestingLevel.TooHigh */ - private function ImportProductVariantsToProto(ImportVariantsResponseInterface $value): ImportVariantsResponse + private function importProductVariantsToProto(ImportVariantsResponseInterface $value): ImportVariantsResponse { // convert data from \Magento\CatalogStorefrontApi\Api\Data\ImportVariantsResponse // to \Magento\CatalogStorefrontApi\Proto\ImportVariantsResponse @@ -134,19 +134,19 @@ private function ImportProductVariantsToProto(ImportVariantsResponseInterface $v } /** - * Autogenerated description for DeleteProductVariants method + * Autogenerated description for deleteProductVariants method * * @param \Spiral\GRPC\ContextInterface $ctx * @param DeleteVariantsRequest $in * @return DeleteVariantsResponse * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function DeleteProductVariants(\Spiral\GRPC\ContextInterface $ctx, DeleteVariantsRequest $in): DeleteVariantsResponse + public function deleteProductVariants(\Spiral\GRPC\ContextInterface $ctx, DeleteVariantsRequest $in): DeleteVariantsResponse { try { - $magentoDtoRequest = $this->DeleteProductVariantsFromProto($in); - $magentoDtoResponse = $this->service->DeleteProductVariants($magentoDtoRequest); - return $this->DeleteProductVariantsToProto($magentoDtoResponse); + $magentoDtoRequest = $this->deleteProductVariantsFromProto($in); + $magentoDtoResponse = $this->service->deleteProductVariants($magentoDtoRequest); + return $this->deleteProductVariantsToProto($magentoDtoResponse); } catch (\Exception $e) { throw new \Spiral\GRPC\Exception\InvokeException( $e->getMessage(), @@ -158,12 +158,12 @@ public function DeleteProductVariants(\Spiral\GRPC\ContextInterface $ctx, Delete } /** - * Autogenerated description for DeleteProductVariants method + * Autogenerated description for deleteProductVariants method * * @param DeleteVariantsRequest $value * @return DeleteVariantsRequestInterface */ - private function DeleteProductVariantsFromProto(DeleteVariantsRequest $value): DeleteVariantsRequestInterface + private function deleteProductVariantsFromProto(DeleteVariantsRequest $value): DeleteVariantsRequestInterface { // convert data from \Magento\CatalogStorefrontApi\Proto\DeleteVariantsRequest // to \Magento\CatalogStorefrontApi\Api\Data\DeleteVariantsRequest @@ -183,13 +183,13 @@ private function DeleteProductVariantsFromProto(DeleteVariantsRequest $value): D } /** - * Autogenerated description for DeleteProductVariants method + * Autogenerated description for deleteProductVariants method * * @param DeleteVariantsResponseInterface $value * @return DeleteVariantsResponse * phpcs:disable Generic.Metrics.NestingLevel.TooHigh */ - private function DeleteProductVariantsToProto(DeleteVariantsResponseInterface $value): DeleteVariantsResponse + private function deleteProductVariantsToProto(DeleteVariantsResponseInterface $value): DeleteVariantsResponse { // convert data from \Magento\CatalogStorefrontApi\Api\Data\DeleteVariantsResponse // to \Magento\CatalogStorefrontApi\Proto\DeleteVariantsResponse @@ -206,19 +206,19 @@ private function DeleteProductVariantsToProto(DeleteVariantsResponseInterface $v } /** - * Autogenerated description for GetProductVariants method + * Autogenerated description for getProductVariants method * * @param \Spiral\GRPC\ContextInterface $ctx * @param ProductVariantRequest $in * @return ProductVariantResponse * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function GetProductVariants(\Spiral\GRPC\ContextInterface $ctx, ProductVariantRequest $in): ProductVariantResponse + public function getProductVariants(\Spiral\GRPC\ContextInterface $ctx, ProductVariantRequest $in): ProductVariantResponse { try { - $magentoDtoRequest = $this->GetProductVariantsFromProto($in); - $magentoDtoResponse = $this->service->GetProductVariants($magentoDtoRequest); - return $this->GetProductVariantsToProto($magentoDtoResponse); + $magentoDtoRequest = $this->getProductVariantsFromProto($in); + $magentoDtoResponse = $this->service->getProductVariants($magentoDtoRequest); + return $this->getProductVariantsToProto($magentoDtoResponse); } catch (\Exception $e) { throw new \Spiral\GRPC\Exception\InvokeException( $e->getMessage(), @@ -230,12 +230,12 @@ public function GetProductVariants(\Spiral\GRPC\ContextInterface $ctx, ProductVa } /** - * Autogenerated description for GetProductVariants method + * Autogenerated description for getProductVariants method * * @param ProductVariantRequest $value * @return ProductVariantRequestInterface */ - private function GetProductVariantsFromProto(ProductVariantRequest $value): ProductVariantRequestInterface + private function getProductVariantsFromProto(ProductVariantRequest $value): ProductVariantRequestInterface { // convert data from \Magento\CatalogStorefrontApi\Proto\ProductVariantRequest // to \Magento\CatalogStorefrontApi\Api\Data\ProductVariantRequest @@ -252,13 +252,13 @@ private function GetProductVariantsFromProto(ProductVariantRequest $value): Prod } /** - * Autogenerated description for GetProductVariants method + * Autogenerated description for getProductVariants method * * @param ProductVariantResponseInterface $value * @return ProductVariantResponse * phpcs:disable Generic.Metrics.NestingLevel.TooHigh */ - private function GetProductVariantsToProto(ProductVariantResponseInterface $value): ProductVariantResponse + private function getProductVariantsToProto(ProductVariantResponseInterface $value): ProductVariantResponse { // convert data from \Magento\CatalogStorefrontApi\Api\Data\ProductVariantResponse // to \Magento\CatalogStorefrontApi\Proto\ProductVariantResponse @@ -293,19 +293,19 @@ private function GetProductVariantsToProto(ProductVariantResponseInterface $valu } /** - * Autogenerated description for GetVariantsMatch method + * Autogenerated description for getVariantsMatch method * * @param \Spiral\GRPC\ContextInterface $ctx * @param OptionSelectionRequest $in * @return ProductVariantResponse * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function GetVariantsMatch(\Spiral\GRPC\ContextInterface $ctx, OptionSelectionRequest $in): ProductVariantResponse + public function getVariantsMatch(\Spiral\GRPC\ContextInterface $ctx, OptionSelectionRequest $in): ProductVariantResponse { try { - $magentoDtoRequest = $this->GetVariantsMatchFromProto($in); - $magentoDtoResponse = $this->service->GetVariantsMatch($magentoDtoRequest); - return $this->GetVariantsMatchToProto($magentoDtoResponse); + $magentoDtoRequest = $this->getVariantsMatchFromProto($in); + $magentoDtoResponse = $this->service->getVariantsMatch($magentoDtoRequest); + return $this->getVariantsMatchToProto($magentoDtoResponse); } catch (\Exception $e) { throw new \Spiral\GRPC\Exception\InvokeException( $e->getMessage(), @@ -317,12 +317,12 @@ public function GetVariantsMatch(\Spiral\GRPC\ContextInterface $ctx, OptionSelec } /** - * Autogenerated description for GetVariantsMatch method + * Autogenerated description for getVariantsMatch method * * @param OptionSelectionRequest $value * @return OptionSelectionRequestInterface */ - private function GetVariantsMatchFromProto(OptionSelectionRequest $value): OptionSelectionRequestInterface + private function getVariantsMatchFromProto(OptionSelectionRequest $value): OptionSelectionRequestInterface { // convert data from \Magento\CatalogStorefrontApi\Proto\OptionSelectionRequest // to \Magento\CatalogStorefrontApi\Api\Data\OptionSelectionRequest @@ -343,13 +343,13 @@ private function GetVariantsMatchFromProto(OptionSelectionRequest $value): Optio } /** - * Autogenerated description for GetVariantsMatch method + * Autogenerated description for getVariantsMatch method * * @param ProductVariantResponseInterface $value * @return ProductVariantResponse * phpcs:disable Generic.Metrics.NestingLevel.TooHigh */ - private function GetVariantsMatchToProto(ProductVariantResponseInterface $value): ProductVariantResponse + private function getVariantsMatchToProto(ProductVariantResponseInterface $value): ProductVariantResponse { // convert data from \Magento\CatalogStorefrontApi\Api\Data\ProductVariantResponse // to \Magento\CatalogStorefrontApi\Proto\ProductVariantResponse diff --git a/app/code/Magento/CatalogStorefrontApi/Api/VariantServiceServerInterface.php b/app/code/Magento/CatalogStorefrontApi/Api/VariantServiceServerInterface.php index f40d1cf16..e3cf0d378 100644 --- a/app/code/Magento/CatalogStorefrontApi/Api/VariantServiceServerInterface.php +++ b/app/code/Magento/CatalogStorefrontApi/Api/VariantServiceServerInterface.php @@ -24,38 +24,38 @@ interface VariantServiceServerInterface { /** - * Autogenerated description for ImportProductVariants interface method + * Autogenerated description for importProductVariants interface method * * @param ImportVariantsRequestInterface $request * @return ImportVariantsResponseInterface * @throws \Throwable */ - public function ImportProductVariants(ImportVariantsRequestInterface $request): ImportVariantsResponseInterface; + public function importProductVariants(ImportVariantsRequestInterface $request): ImportVariantsResponseInterface; /** - * Autogenerated description for DeleteProductVariants interface method + * Autogenerated description for deleteProductVariants interface method * * @param DeleteVariantsRequestInterface $request * @return DeleteVariantsResponseInterface * @throws \Throwable */ - public function DeleteProductVariants(DeleteVariantsRequestInterface $request): DeleteVariantsResponseInterface; + public function deleteProductVariants(DeleteVariantsRequestInterface $request): DeleteVariantsResponseInterface; /** - * Autogenerated description for GetProductVariants interface method + * Autogenerated description for getProductVariants interface method * * @param ProductVariantRequestInterface $request * @return ProductVariantResponseInterface * @throws \Throwable */ - public function GetProductVariants(ProductVariantRequestInterface $request): ProductVariantResponseInterface; + public function getProductVariants(ProductVariantRequestInterface $request): ProductVariantResponseInterface; /** - * Autogenerated description for GetVariantsMatch interface method + * Autogenerated description for getVariantsMatch interface method * * @param OptionSelectionRequestInterface $request * @return ProductVariantResponseInterface * @throws \Throwable */ - public function GetVariantsMatch(OptionSelectionRequestInterface $request): ProductVariantResponseInterface; + public function getVariantsMatch(OptionSelectionRequestInterface $request): ProductVariantResponseInterface; } diff --git a/app/code/Magento/CatalogStorefrontApi/Metadata/Catalog.php b/app/code/Magento/CatalogStorefrontApi/Metadata/Catalog.php index 90c78c896..38ecb95e0 100644 --- a/app/code/Magento/CatalogStorefrontApi/Metadata/Catalog.php +++ b/app/code/Magento/CatalogStorefrontApi/Metadata/Catalog.php @@ -270,22 +270,22 @@ public static function initOnce() "6e744170692e70726f746f2e43617465676f726965734765745265717565" . "73741a392e6d6167656e746f2e636174616c6f6753746f726566726f6e74" . "4170692e70726f746f2e43617465676f72696573476574526573706f6e73" . - "65220032d5040a0e56617269616e74536572766963651290010a15496d70" . + "65220032d5040a0e56617269616e74536572766963651290010a15696d70" . "6f727450726f6475637456617269616e747312392e6d6167656e746f2e63" . "6174616c6f6753746f726566726f6e744170692e70726f746f2e496d706f" . "727456617269616e7473526571756573741a3a2e6d6167656e746f2e6361" . "74616c6f6753746f726566726f6e744170692e70726f746f2e496d706f72" . - "7456617269616e7473526573706f6e736522001290010a1544656c657465" . + "7456617269616e7473526573706f6e736522001290010a1564656c657465" . "50726f6475637456617269616e747312392e6d6167656e746f2e63617461" . "6c6f6753746f726566726f6e744170692e70726f746f2e44656c65746556" . "617269616e7473526571756573741a3a2e6d6167656e746f2e636174616c" . "6f6753746f726566726f6e744170692e70726f746f2e44656c6574655661" . - "7269616e7473526573706f6e73652200128d010a1247657450726f647563" . + "7269616e7473526573706f6e73652200128d010a1267657450726f647563" . "7456617269616e747312392e6d6167656e746f2e636174616c6f6753746f" . "726566726f6e744170692e70726f746f2e50726f6475637456617269616e" . "74526571756573741a3a2e6d6167656e746f2e636174616c6f6753746f72" . "6566726f6e744170692e70726f746f2e50726f6475637456617269616e74" . - "526573706f6e73652200128c010a1047657456617269616e74734d617463" . + "526573706f6e73652200128c010a1067657456617269616e74734d617463" . "68123a2e6d6167656e746f2e636174616c6f6753746f726566726f6e7441" . "70692e70726f746f2e4f7074696f6e53656c656374696f6e526571756573" . "741a3a2e6d6167656e746f2e636174616c6f6753746f726566726f6e7441" . diff --git a/app/code/Magento/CatalogStorefrontApi/Proto/VariantServiceClient.php b/app/code/Magento/CatalogStorefrontApi/Proto/VariantServiceClient.php index ca9a76934..5d9d3e6ab 100644 --- a/app/code/Magento/CatalogStorefrontApi/Proto/VariantServiceClient.php +++ b/app/code/Magento/CatalogStorefrontApi/Proto/VariantServiceClient.php @@ -28,14 +28,14 @@ public function __construct($hostname, $opts, $channel = null) * @param array $options call options * @return \Magento\CatalogStorefrontApi\Proto\ImportVariantsResponse */ - public function ImportProductVariants( + public function importProductVariants( \Magento\CatalogStorefrontApi\Proto\ImportVariantsRequest $argument, $metadata = [], $options = [] ) { return $this->_simpleRequest( - '/magento.catalogStorefrontApi.proto.VariantService/ImportProductVariants', + '/magento.catalogStorefrontApi.proto.VariantService/importProductVariants', $argument, ['\Magento\CatalogStorefrontApi\Proto\ImportVariantsResponse', 'decode'], $metadata, @@ -49,14 +49,14 @@ public function ImportProductVariants( * @param array $options call options * @return \Magento\CatalogStorefrontApi\Proto\DeleteVariantsResponse */ - public function DeleteProductVariants( + public function deleteProductVariants( \Magento\CatalogStorefrontApi\Proto\DeleteVariantsRequest $argument, $metadata = [], $options = [] ) { return $this->_simpleRequest( - '/magento.catalogStorefrontApi.proto.VariantService/DeleteProductVariants', + '/magento.catalogStorefrontApi.proto.VariantService/deleteProductVariants', $argument, ['\Magento\CatalogStorefrontApi\Proto\DeleteVariantsResponse', 'decode'], $metadata, @@ -71,14 +71,14 @@ public function DeleteProductVariants( * @param array $options call options * @return \Magento\CatalogStorefrontApi\Proto\ProductVariantResponse */ - public function GetProductVariants( + public function getProductVariants( \Magento\CatalogStorefrontApi\Proto\ProductVariantRequest $argument, $metadata = [], $options = [] ) { return $this->_simpleRequest( - '/magento.catalogStorefrontApi.proto.VariantService/GetProductVariants', + '/magento.catalogStorefrontApi.proto.VariantService/getProductVariants', $argument, ['\Magento\CatalogStorefrontApi\Proto\ProductVariantResponse', 'decode'], $metadata, @@ -93,14 +93,14 @@ public function GetProductVariants( * @param array $options call options * @return \Magento\CatalogStorefrontApi\Proto\ProductVariantResponse */ - public function GetVariantsMatch( + public function getVariantsMatch( \Magento\CatalogStorefrontApi\Proto\OptionSelectionRequest $argument, $metadata = [], $options = [] ) { return $this->_simpleRequest( - '/magento.catalogStorefrontApi.proto.VariantService/GetVariantsMatch', + '/magento.catalogStorefrontApi.proto.VariantService/getVariantsMatch', $argument, ['\Magento\CatalogStorefrontApi\Proto\ProductVariantResponse', 'decode'], $metadata, diff --git a/app/code/Magento/CatalogStorefrontApi/Proto/VariantServiceInterface.php b/app/code/Magento/CatalogStorefrontApi/Proto/VariantServiceInterface.php index b26932ba1..d149f308d 100644 --- a/app/code/Magento/CatalogStorefrontApi/Proto/VariantServiceInterface.php +++ b/app/code/Magento/CatalogStorefrontApi/Proto/VariantServiceInterface.php @@ -18,7 +18,7 @@ interface VariantServiceInterface extends GRPC\ServiceInterface * * @throws GRPC\Exception\InvokeException */ - public function ImportProductVariants(GRPC\ContextInterface $ctx, ImportVariantsRequest $in): ImportVariantsResponse; + public function importProductVariants(GRPC\ContextInterface $ctx, ImportVariantsRequest $in): ImportVariantsResponse; /** * @param GRPC\ContextInterface $ctx @@ -27,7 +27,7 @@ public function ImportProductVariants(GRPC\ContextInterface $ctx, ImportVariants * * @throws GRPC\Exception\InvokeException */ - public function DeleteProductVariants(GRPC\ContextInterface $ctx, DeleteVariantsRequest $in): DeleteVariantsResponse; + public function deleteProductVariants(GRPC\ContextInterface $ctx, DeleteVariantsRequest $in): DeleteVariantsResponse; /** * @param GRPC\ContextInterface $ctx @@ -36,7 +36,7 @@ public function DeleteProductVariants(GRPC\ContextInterface $ctx, DeleteVariants * * @throws GRPC\Exception\InvokeException */ - public function GetProductVariants(GRPC\ContextInterface $ctx, ProductVariantRequest $in): ProductVariantResponse; + public function getProductVariants(GRPC\ContextInterface $ctx, ProductVariantRequest $in): ProductVariantResponse; /** * @param GRPC\ContextInterface $ctx @@ -45,5 +45,5 @@ public function GetProductVariants(GRPC\ContextInterface $ctx, ProductVariantReq * * @throws GRPC\Exception\InvokeException */ - public function GetVariantsMatch(GRPC\ContextInterface $ctx, OptionSelectionRequest $in): ProductVariantResponse; + public function getVariantsMatch(GRPC\ContextInterface $ctx, OptionSelectionRequest $in): ProductVariantResponse; } diff --git a/app/code/Magento/Grpc/Console/Command/ProtoMarshalCommand.php b/app/code/Magento/Grpc/Console/Command/ProtoMarshalCommand.php index d46a98b13..522c53095 100644 --- a/app/code/Magento/Grpc/Console/Command/ProtoMarshalCommand.php +++ b/app/code/Magento/Grpc/Console/Command/ProtoMarshalCommand.php @@ -67,7 +67,8 @@ public function __construct( * TODO: probably we need to have a dedicated extension point in setup:di:compile for code generation * * Currently is not used, use cli command - * `bin/magento storefront:grpc:init \\Magento\\CatalogStorefrontApi\\Api\\CatalogProxyServer` instead + * `bin/magento storefront:grpc:init \\Magento\\CatalogStorefrontApi\\Api\\CatalogProxyServer + * \\Magento\\CatalogStorefrontApi\\Api\\VariantServiceProxyServer` instead */ // if (\Magento\Setup\Console\Command\DiCompileCommand::NAME == $input->getFirstArgument()) { diff --git a/app/code/Magento/Grpc/README.md b/app/code/Magento/Grpc/README.md index 2000151f4..4d7b78f8c 100644 --- a/app/code/Magento/Grpc/README.md +++ b/app/code/Magento/Grpc/README.md @@ -3,7 +3,7 @@ This module provides gRPC entry point for Magento. Additionally, it provides possibility to expose gRPC APIs for other Magento modules # Installation -* Run `bin/magento storefront:grpc:init \\Magento\\CatalogStorefrontApi\\Api\\CatalogProxyServer` CLI command. The command does the following actions: +* Run `bin/magento storefront:grpc:init \\Magento\\CatalogStorefrontApi\\Api\\CatalogProxyServer \\Magento\\CatalogStorefrontApi\\Api\\VariantServiceProxyServer` CLI command. The command does the following actions: * Copies certain bin files to `vendor/bin` directory * Register services for later use in gRPC sever * Install `rr-grpc` server - https://github.com/spiral/php-grpc. Put the binary in some directory registered in PATH system variable From cf845cdb95610c5607d15e5ac9a7c95f728e8e0d Mon Sep 17 00:00:00 2001 From: ruslankostiv Date: Tue, 10 Nov 2020 14:54:59 -0600 Subject: [PATCH 15/23] 27: Product variants --- .../DeleteProductVariantsConsumer.php | 2 +- .../PublishProductVariantsConsumer.php | 2 +- .../CatalogStorefront/Model/VariantService.php | 10 +++++----- .../Api/ProductVariants/ConfigurableVariantsTest.php | 4 ++-- .../Configurable-products-option-variants.md | 12 ++++++------ .../designDocuments/Product-Variants-services.md | 8 ++++---- .../Model/MessageBus/ProductVariantsTest.php | 4 ++-- magento.proto | 12 ++++++------ 8 files changed, 27 insertions(+), 27 deletions(-) diff --git a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/DeleteProductVariantsConsumer.php b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/DeleteProductVariantsConsumer.php index ce88737c1..7b041d511 100644 --- a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/DeleteProductVariantsConsumer.php +++ b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/DeleteProductVariantsConsumer.php @@ -59,7 +59,7 @@ public function execute(array $entities, ?string $scope = null): void $deleteVariantsRequest->setId($ids); try { - $importResult = $this->variantsServer->DeleteProductVariants($deleteVariantsRequest); + $importResult = $this->variantsServer->deleteProductVariants($deleteVariantsRequest); if ($importResult->getStatus() === false) { $this->logger->error( sprintf('Product variants deletion has failed: "%s"', $importResult->getMessage()) diff --git a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/PublishProductVariantsConsumer.php b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/PublishProductVariantsConsumer.php index 198b1e341..4bf68dc96 100644 --- a/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/PublishProductVariantsConsumer.php +++ b/app/code/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariants/PublishProductVariantsConsumer.php @@ -108,7 +108,7 @@ private function importVariants(array $variants): void $importVariantsRequest->setVariants($variants); try { - $importResult = $this->variantService->ImportProductVariants($importVariantsRequest); + $importResult = $this->variantService->importProductVariants($importVariantsRequest); if ($importResult->getStatus() === false) { $this->logger->error(sprintf('Product variants import failed: "%s"', $importResult->getMessage())); } diff --git a/app/code/Magento/CatalogStorefront/Model/VariantService.php b/app/code/Magento/CatalogStorefront/Model/VariantService.php index 09e68d506..d93fcff16 100644 --- a/app/code/Magento/CatalogStorefront/Model/VariantService.php +++ b/app/code/Magento/CatalogStorefront/Model/VariantService.php @@ -122,7 +122,7 @@ public function __construct( * @param ImportVariantsRequestInterface $request * @return ImportVariantsResponseInterface */ - public function ImportProductVariants(ImportVariantsRequestInterface $request): ImportVariantsResponseInterface + public function importProductVariants(ImportVariantsRequestInterface $request): ImportVariantsResponseInterface { try { $variantsInElasticFormat = []; @@ -170,7 +170,7 @@ public function ImportProductVariants(ImportVariantsRequestInterface $request): * @param DeleteVariantsRequestInterface $request * @return DeleteVariantsResponseInterface */ - public function DeleteProductVariants(DeleteVariantsRequestInterface $request): DeleteVariantsResponseInterface + public function deleteProductVariants(DeleteVariantsRequestInterface $request): DeleteVariantsResponseInterface { $deleteFields = \array_map(function ($id) { return ['id' => $id]; @@ -212,7 +212,7 @@ public function DeleteProductVariants(DeleteVariantsRequestInterface $request): * @throws RuntimeException * @throws \Throwable */ - public function GetProductVariants(ProductVariantRequestInterface $request): ProductVariantResponseInterface + public function getProductVariants(ProductVariantRequestInterface $request): ProductVariantResponseInterface { $productId = $request->getProductId(); $store = $request->getStore(); @@ -269,13 +269,13 @@ public function GetProductVariants(ProductVariantRequestInterface $request): Pro } /** - * TODO: Implement GetVariantsMatch() method and remove the warning suppression. + * TODO: Implement getVariantsMatch() method and remove the warning suppression. * * @param OptionSelectionRequestInterface $request * @return ProductVariantResponseInterface * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function GetVariantsMatch(OptionSelectionRequestInterface $request): ProductVariantResponseInterface + public function getVariantsMatch(OptionSelectionRequestInterface $request): ProductVariantResponseInterface { return new ProductVariantResponse(); } diff --git a/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php b/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php index c43b73929..01ce45853 100644 --- a/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php +++ b/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php @@ -91,7 +91,7 @@ public function testConfigurableProductVariants(): void //See https://www.elastic.co/guide/en/elasticsearch/reference/6.8/docs-refresh.html#docs-refresh sleep(1); /** @var $variantServiceItem ProductVariantResponse */ - $variantServiceItem = $this->variantService->GetProductVariants($this->variantsRequestInterface); + $variantServiceItem = $this->variantService->getProductVariants($this->variantsRequestInterface); $actual = $this->responseArrayMapper->convertToArray($variantServiceItem)['matched_variants']; $expected = $this->getExpectedProductVariants($configurable, $simples); @@ -119,7 +119,7 @@ public function testProductVariantsDisabledProduct(): void //See https://www.elastic.co/guide/en/elasticsearch/reference/6.8/docs-refresh.html#docs-refresh sleep(1); /** @var $variantServiceItem ProductVariantResponse */ - $variantServiceItem = $this->variantService->GetProductVariants($this->variantsRequestInterface); + $variantServiceItem = $this->variantService->getProductVariants($this->variantsRequestInterface); $actual = $this->responseArrayMapper->convertToArray($variantServiceItem)['matched_variants']; self::assertCount(1, $actual); } diff --git a/dev/docs/designDocuments/Configurable-products-option-variants.md b/dev/docs/designDocuments/Configurable-products-option-variants.md index 9bad33ac6..2b83fd7f4 100644 --- a/dev/docs/designDocuments/Configurable-products-option-variants.md +++ b/dev/docs/designDocuments/Configurable-products-option-variants.md @@ -112,7 +112,7 @@ so exported `ProductVariants` will look like this: ## Storefront Application part -Import API (`ImportProductVariants`) should split `option_values` and save them as separate records into SF App storage. +Import API (`importProductVariants`) should split `option_values` and save them as separate records into SF App storage. Parent id can be parsed from `option_values` too | product_id | id | feed_data | @@ -151,18 +151,18 @@ message ProductVariantResponse { } service VariantSearchService { // get all variants that belong to a product - rpc GetProductVariants (ProductVariantRequest) returns (ProductVariantResponse); + rpc getProductVariants (ProductVariantRequest) returns (ProductVariantResponse); // match the variants which correspond, and do not contradict, the merchant selection (%like operation) - rpc GetVariantsMatch (OptionSelectionRequest) returns (ProductVariantResponse); + rpc getVariantsMatch (OptionSelectionRequest) returns (ProductVariantResponse); // match the variants which exactly matched with merchant selection (&& operation) - rpc GetVariantsExactlyMatch (OptionSelectionRequest) returns (ProductVariantResponse); + rpc getVariantsExactlyMatch (OptionSelectionRequest) returns (ProductVariantResponse); // get all variants which contain at least one of merchant selection (|| operation) - rpc GetVariantsInclude (OptionSelectionRequest) returns (ProductVariantResponse); + rpc getVariantsInclude (OptionSelectionRequest) returns (ProductVariantResponse); } ``` ### Get all variants for a configurable product with id `42` -`rpc GetProductVariants (ProductVariantRequest) returns (ProductVariantResponse)` +`rpc getProductVariants (ProductVariantRequest) returns (ProductVariantResponse)` 1. internal Request to get variants data for by parent id: `getVariants(parent_id, ...)` diff --git a/dev/docs/designDocuments/Product-Variants-services.md b/dev/docs/designDocuments/Product-Variants-services.md index f8adbdfb1..98d1d3a59 100644 --- a/dev/docs/designDocuments/Product-Variants-services.md +++ b/dev/docs/designDocuments/Product-Variants-services.md @@ -35,7 +35,7 @@ message ProductVariantResponse { } ``` ------------------------------------------------------ -rpc GetVariantsExactlyMatch (OptionSelectionRequest) returns (ProductVariantResponse) {} +rpc getVariantsExactlyMatch (OptionSelectionRequest) returns (ProductVariantResponse) {} REQUEST #1.1: ``` @@ -76,12 +76,12 @@ Response #1.2: [ ] ``` -`GetVariantsExactlyMatch` should return only fully matched records. +`getVariantsExactlyMatch` should return only fully matched records. `42:size/Y29uZmlndXJhYmxlLzpzaXplLWlkOi86eGwtaWQ6` option value is present in `configurable/42/1` and `configurable/42/2` variants, but matched variants partially, because each variant has 2 option values, requested values should match both records as into Request 1.1 ------------------------------------------------------ -rpc GetVariantsInclude (OptionSelectionRequest) returns (ProductVariantResponse) {} +rpc getVariantsInclude (OptionSelectionRequest) returns (ProductVariantResponse) {} REQUEST #2.1: ``` @@ -142,7 +142,7 @@ Response #2.2 (2 variants matches with 3 option_values): ``` ------------------------------------------------------ -rpc GetVariantsMatch (OptionSelectionRequest) returns (ProductVariantResponse) {} +rpc getVariantsMatch (OptionSelectionRequest) returns (ProductVariantResponse) {} REQUEST #3.1: ``` diff --git a/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php b/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php index c9b07657e..c206216bd 100644 --- a/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php +++ b/dev/tests/api-functional/testsuite/Magento/CatalogMessageBroker/Model/MessageBus/ProductVariantsTest.php @@ -133,7 +133,7 @@ public function testSaveAndDeleteProductVariant(): void //This sleep ensures that the elastic index has sufficient time to refresh //See https://www.elastic.co/guide/en/elasticsearch/reference/6.8/docs-refresh.html#docs-refresh sleep(1); - $response = $this->variantService->GetProductVariants($this->variantsGetRequestInterface); + $response = $this->variantService->getProductVariants($this->variantsGetRequestInterface); $variants = $this->responseArrayMapper->convertToArray($response); $this->assertNotEmpty($variants); @@ -154,7 +154,7 @@ public function testSaveAndDeleteProductVariant(): void $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage(sprintf(self::ERROR_MESSAGE, $configurableId)); - $this->variantService->GetProductVariants($this->variantsGetRequestInterface); + $this->variantService->getProductVariants($this->variantsGetRequestInterface); } /** diff --git a/magento.proto b/magento.proto index 3b5a80867..76779c91f 100755 --- a/magento.proto +++ b/magento.proto @@ -456,17 +456,17 @@ message OptionSelectionRequest } service VariantService { - rpc ImportProductVariants (ImportVariantsRequest) returns (ImportVariantsResponse) {} - rpc DeleteProductVariants (DeleteVariantsRequest) returns (DeleteVariantsResponse) {} + rpc importProductVariants (ImportVariantsRequest) returns (ImportVariantsResponse) {} + rpc deleteProductVariants (DeleteVariantsRequest) returns (DeleteVariantsResponse) {} // get all variants that belong to a product - rpc GetProductVariants (ProductVariantRequest) returns (ProductVariantResponse) {} + rpc getProductVariants (ProductVariantRequest) returns (ProductVariantResponse) {} // match the variants which correspond, and do not contradict, the merchant selection (%like operation) - rpc GetVariantsMatch (OptionSelectionRequest) returns (ProductVariantResponse) {} + rpc getVariantsMatch (OptionSelectionRequest) returns (ProductVariantResponse) {} // will be implemented in future // match the variants which exactly matched with merchant selection (&& operation) - //rpc GetVariantsExactlyMatch (OptionSelectionRequest) returns (ProductVariantResponse) {} + //rpc getVariantsExactlyMatch (OptionSelectionRequest) returns (ProductVariantResponse) {} // get all variants which contain at least one of merchant selection (|| operation) - //rpc GetVariantsInclude (OptionSelectionRequest) returns (ProductVariantResponse) {} + //rpc getVariantsInclude (OptionSelectionRequest) returns (ProductVariantResponse) {} } From 8b7b8b30027ee944b9412691285da1059395c859 Mon Sep 17 00:00:00 2001 From: ruslankostiv Date: Tue, 10 Nov 2020 16:30:00 -0600 Subject: [PATCH 16/23] 27: Product variants --- .../Model/Storage/Client/QueryInterface.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogStorefront/Model/Storage/Client/QueryInterface.php b/app/code/Magento/CatalogStorefront/Model/Storage/Client/QueryInterface.php index 91d572ab2..e0f0ede6b 100644 --- a/app/code/Magento/CatalogStorefront/Model/Storage/Client/QueryInterface.php +++ b/app/code/Magento/CatalogStorefront/Model/Storage/Client/QueryInterface.php @@ -93,5 +93,10 @@ public function searchMatchedEntries( * @throws NotFoundException * @throws RuntimeException */ - public function searchFilteredEntries(string $indexName, string $entityName, array $searchBody, ?string $clauseType = 'term'): EntryIteratorInterface; + public function searchFilteredEntries( + string $indexName, + string $entityName, + array $searchBody, + ?string $clauseType = 'term' + ): EntryIteratorInterface; } From 798fac468cb69def9306f8da9fa88311a39ef43e Mon Sep 17 00:00:00 2001 From: ruslankostiv Date: Wed, 11 Nov 2020 18:55:31 -0600 Subject: [PATCH 17/23] 27: Product variants --- app/code/Magento/CatalogStorefront/Model/VariantService.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/CatalogStorefront/Model/VariantService.php b/app/code/Magento/CatalogStorefront/Model/VariantService.php index d93fcff16..21436a24e 100644 --- a/app/code/Magento/CatalogStorefront/Model/VariantService.php +++ b/app/code/Magento/CatalogStorefront/Model/VariantService.php @@ -218,6 +218,7 @@ public function getProductVariants(ProductVariantRequestInterface $request): Pro $store = $request->getStore(); $rawVariants = $this->productVariantsDataProvider->fetchByProductId((int)$productId); + \ksort($rawVariants); if (empty($rawVariants)) { throw new \InvalidArgumentException( sprintf( From 3ab881547529f9c8d2de400c5a9fb8e32d646d27 Mon Sep 17 00:00:00 2001 From: jekabs Date: Fri, 13 Nov 2020 11:28:52 +0200 Subject: [PATCH 18/23] Product variants -Added debug statement to a test --- .../ProductVariants/ConfigurableVariantsTest.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php b/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php index 01ce45853..58d3d772a 100644 --- a/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php +++ b/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php @@ -56,6 +56,20 @@ protected function setUp(): void ); } + /** + * Temporary debug function + * @throws \Exception + */ + private function debug() + { + $indexerRegistry = Bootstrap::getObjectManager()->create(\Magento\Framework\Indexer\IndexerRegistry::class); + $indexer = $indexerRegistry->get( + \Magento\ProductVariantDataExporter\Model\Indexer\ProductVariantFeedIndexer::INDEXER_ID + ); + $debugMessage = $indexer->isScheduled() ? 'Indexer is on Schedule' : 'Indexer is on Save'; + throw new \Exception($debugMessage); + } + /** * Validate configurable product variants data * @@ -66,6 +80,7 @@ protected function setUp(): void */ public function testConfigurableProductVariants(): void { + $this->debug(); $simpleSkus = [ 'simple_0', 'simple_1', From 077343c6472b7024231bdb155114e45cdfd62ac5 Mon Sep 17 00:00:00 2001 From: jekabs Date: Fri, 13 Nov 2020 11:32:36 +0200 Subject: [PATCH 19/23] Revert "Product variants" This reverts commit 3ab881547529f9c8d2de400c5a9fb8e32d646d27. --- .../ProductVariants/ConfigurableVariantsTest.php | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php b/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php index 58d3d772a..01ce45853 100644 --- a/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php +++ b/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php @@ -56,20 +56,6 @@ protected function setUp(): void ); } - /** - * Temporary debug function - * @throws \Exception - */ - private function debug() - { - $indexerRegistry = Bootstrap::getObjectManager()->create(\Magento\Framework\Indexer\IndexerRegistry::class); - $indexer = $indexerRegistry->get( - \Magento\ProductVariantDataExporter\Model\Indexer\ProductVariantFeedIndexer::INDEXER_ID - ); - $debugMessage = $indexer->isScheduled() ? 'Indexer is on Schedule' : 'Indexer is on Save'; - throw new \Exception($debugMessage); - } - /** * Validate configurable product variants data * @@ -80,7 +66,6 @@ private function debug() */ public function testConfigurableProductVariants(): void { - $this->debug(); $simpleSkus = [ 'simple_0', 'simple_1', From 0c0fa112fe64fe3aac959296d3a5c98dfd9eff20 Mon Sep 17 00:00:00 2001 From: jekabs Date: Fri, 13 Nov 2020 12:44:07 +0200 Subject: [PATCH 20/23] Product variants -Added temp code for testing --- .../CatalogStorefront/Test/Api/StorefrontTestsAbstract.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogStorefront/Test/Api/StorefrontTestsAbstract.php b/app/code/Magento/CatalogStorefront/Test/Api/StorefrontTestsAbstract.php index eb5419987..65dc14dd2 100644 --- a/app/code/Magento/CatalogStorefront/Test/Api/StorefrontTestsAbstract.php +++ b/app/code/Magento/CatalogStorefront/Test/Api/StorefrontTestsAbstract.php @@ -167,6 +167,10 @@ private function cleanOldMessages(): void */ public function run(TestResult $result = null): TestResult { + //TODO: remove this temporary code + if (!$this instanceof \Magento\CatalogStorefront\Test\Api\ProductVariants\ConfigurableVariantsTest) { + return new TestResult(); + } $this->cleanOldMessages(); $this->resetIndexerToOnSave(); return parent::run($result); @@ -200,7 +204,7 @@ private function isSoap(): bool * * @param array $consumers */ - public function runConsumers(array $consumers = []) : void + public function runConsumers(array $consumers = []): void { $consumerInvoker = Bootstrap::getObjectManager()->create(ConsumerInvoker::class); $consumerInvoker->invoke($consumers); From b7c204f710fa3be4ababd1415fd7d3d9d8f5ae7e Mon Sep 17 00:00:00 2001 From: jekabs Date: Fri, 13 Nov 2020 13:54:56 +0200 Subject: [PATCH 21/23] Revert "Product variants" This reverts commit 0c0fa112fe64fe3aac959296d3a5c98dfd9eff20. --- .../CatalogStorefront/Test/Api/StorefrontTestsAbstract.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/code/Magento/CatalogStorefront/Test/Api/StorefrontTestsAbstract.php b/app/code/Magento/CatalogStorefront/Test/Api/StorefrontTestsAbstract.php index 65dc14dd2..eb5419987 100644 --- a/app/code/Magento/CatalogStorefront/Test/Api/StorefrontTestsAbstract.php +++ b/app/code/Magento/CatalogStorefront/Test/Api/StorefrontTestsAbstract.php @@ -167,10 +167,6 @@ private function cleanOldMessages(): void */ public function run(TestResult $result = null): TestResult { - //TODO: remove this temporary code - if (!$this instanceof \Magento\CatalogStorefront\Test\Api\ProductVariants\ConfigurableVariantsTest) { - return new TestResult(); - } $this->cleanOldMessages(); $this->resetIndexerToOnSave(); return parent::run($result); @@ -204,7 +200,7 @@ private function isSoap(): bool * * @param array $consumers */ - public function runConsumers(array $consumers = []): void + public function runConsumers(array $consumers = []) : void { $consumerInvoker = Bootstrap::getObjectManager()->create(ConsumerInvoker::class); $consumerInvoker->invoke($consumers); From 77755635c99e7d68ad17f547e0ec4afc6bc765e1 Mon Sep 17 00:00:00 2001 From: jekabs Date: Fri, 13 Nov 2020 14:38:59 +0200 Subject: [PATCH 22/23] Product Variants -Added debug code --- .../Test/Api/ProductVariants/ConfigurableVariantsTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php b/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php index 01ce45853..2970a3c60 100644 --- a/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php +++ b/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php @@ -66,6 +66,8 @@ protected function setUp(): void */ public function testConfigurableProductVariants(): void { + $this->runConsumers(); + sleep(15); $simpleSkus = [ 'simple_0', 'simple_1', From c5dba4b2bc4a401d29de569e5db6ff5f0a6c6323 Mon Sep 17 00:00:00 2001 From: jekabs Date: Fri, 13 Nov 2020 14:46:35 +0200 Subject: [PATCH 23/23] Revert "Product Variants" This reverts commit 77755635c99e7d68ad17f547e0ec4afc6bc765e1. --- .../Test/Api/ProductVariants/ConfigurableVariantsTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php b/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php index 2970a3c60..01ce45853 100644 --- a/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php +++ b/app/code/Magento/CatalogStorefront/Test/Api/ProductVariants/ConfigurableVariantsTest.php @@ -66,8 +66,6 @@ protected function setUp(): void */ public function testConfigurableProductVariants(): void { - $this->runConsumers(); - sleep(15); $simpleSkus = [ 'simple_0', 'simple_1',