diff --git a/vendor/magento/module-downloadable-staging/Model/ResourceModel/UpdateStagingQuoteItemOptions.php b/vendor/magento/module-downloadable-staging/Model/ResourceModel/UpdateStagingQuoteItemOptions.php new file mode 100644 index 00000000000..b26e3eeb3e8 --- /dev/null +++ b/vendor/magento/module-downloadable-staging/Model/ResourceModel/UpdateStagingQuoteItemOptions.php @@ -0,0 +1,162 @@ +resourceConnection = $resourceConnection; + $this->batchQueryGenerator = $batchQueryGenerator; + $this->connection = $this->resourceConnection->getConnection(); + } + + /** + * Main method to get and update quote item options + * + * @param ProductInterface $entity + * @param array $newLinkIds + * @param array $linksByFile + * @return void + * @throws LocalizedException + */ + public function execute(ProductInterface $entity, array $newLinkIds, array $linksByFile): void + { + foreach ($this->getQuoteItemOptionsToUpdate($entity, $newLinkIds) as $quoteItemOptions) { + $linksForQuery = $this->getQuoteItemOptionLinks($quoteItemOptions, $linksByFile); + $this->updateQuoteItemOptionLinks($linksForQuery); + } + } + + /** + * Retrieve quote item options that need updated + * + * @param ProductInterface $product + * @param array $newLinkIds + * @return \Generator + * @throws LocalizedException + */ + private function getQuoteItemOptionsToUpdate(ProductInterface $product, array $newLinkIds): \Generator + { + $batchSelectIterator = $this->batchQueryGenerator->generate( + 'option_id', + $this->connection->select()->from( + ['qio' => $this->connection->getTableName('quote_item_option')], + ['*'] + )->join( + ['qi' => $this->connection->getTableName('quote_item')], + 'qi.item_id = qio.item_id and qio.code = \'downloadable_link_ids\'', + [] + )->join( + ['cpe' => $this->connection->getTableName('catalog_product_entity')], + 'qi.product_id = cpe.entity_id', + [] + )->join( + ['links' => $this->connection->getTableName('downloadable_link')], + 'links.product_id = cpe.row_id', + [ + 'links.link_id as old_link_id', + 'sort_order', + 'link_url', + 'link_file', + 'link_type', + 'links.product_id as links_row_id' + ] + ) + ->where('qi.product_id = ?', $product->getId()) + ->where('qio.value not in (?)', array_map('intval', $newLinkIds)) + ); + + foreach ($batchSelectIterator as $select) { + yield $this->connection->fetchAll($select); + } + } + + /** + * Get prepared data to update + * + * @param array $quoteItemOptions + * @param array $links + * @return array + */ + private function getQuoteItemOptionLinks(array $quoteItemOptions, array $links): array + { + $updatedLinkIds = []; + foreach ($quoteItemOptions as $itemOption) { + $downloadableLinkIds = explode(',', $itemOption['value']); + foreach ($downloadableLinkIds as $downloadableLinkId) { + $key = json_encode( + $itemOption['links_row_id'] . + $itemOption['sort_order'] . + $itemOption['link_type'] . + $itemOption['link_file'] . + $itemOption['link_url'] + ); + $downloadableLinkId = $links[$key] ?? $downloadableLinkId; + $updatedLinkIds[$itemOption['option_id']][$downloadableLinkId] = $downloadableLinkId; + } + } + $linkIdsForQuery = []; + foreach ($updatedLinkIds as $optionId => $updatedLinkId) { + sort($updatedLinkId); + $linkIds = implode(',', array_unique($updatedLinkId)); + if ($linkIds) { + $linkIdsForQuery[$linkIds][] = $optionId; + } + } + return $linkIdsForQuery; + } + + /** + * Update downloadable_link_ids in quote_item_option + * + * @param array $linkIdsForQuery + * @return void + */ + private function updateQuoteItemOptionLinks(array $linkIdsForQuery) + { + foreach ($linkIdsForQuery as $value => $optionIds) { + $data = [ + 'value' => $value + ]; + $where = $this->connection->quoteInto( + 'code = \'downloadable_link_ids\' and option_id IN (?)', + $optionIds, + 'INT' + ); + $this->connection->update($this->connection->getTableName('quote_item_option'), $data, $where); + } + } +} diff --git a/vendor/magento/module-downloadable-staging/Model/UpdateStagingQuoteItemOptions.php b/vendor/magento/module-downloadable-staging/Model/UpdateStagingQuoteItemOptions.php new file mode 100644 index 00000000000..ec331beb9ad --- /dev/null +++ b/vendor/magento/module-downloadable-staging/Model/UpdateStagingQuoteItemOptions.php @@ -0,0 +1,148 @@ +productRepository = $productRepository; + $this->retrieverPool = $retrieverPool; + $this->downloadableType = $downloadableType; + $this->updateStagingQuoteItemOptions = $updateStagingQuoteItemOptions; + } + + /** + * Update quote item options with new Downloadable Links data for products updated during staging update + * + * @param int $oldVersionId + * @param int $currentVersionId + * @param array $entityIds + * @param string $entityType + * @throws NoSuchEntityException|LocalizedException + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function execute( + int $oldVersionId, + int $currentVersionId, + array $entityIds, + string $entityType + ): void { + if ($this->retrieverPool->getRetriever($entityType) instanceof ProductRetriever) { + foreach ($entityIds as $entityId) { + $newProduct = $this->productRepository->getById($entityId, false, null, true); + $this->update($newProduct); + } + } + } + + /** + * Update quote item option with new Downloadable Links Ids. + * + * @param ProductInterface $entity + * @return void + * @throws LocalizedException + */ + private function update(ProductInterface $entity): void + { + $extensionAttributes = $entity->getExtensionAttributes(); + $links = $extensionAttributes->getDownloadableProductLinks() ?? []; + + if ($links && $entity->getTypeId() === ProductType::TYPE_DOWNLOADABLE) { + $newLinkIds = $this->getLinksIds($entity); + $linksByFile = $this->getLinksByFile($entity); + + $this->updateStagingQuoteItemOptions->execute($entity, $newLinkIds, $linksByFile); + } + } + + /** + * Retrieve Downloadable Links ids by files from the provided entity. + * + * @param ProductInterface $entity + * @return int[] + */ + private function getLinksIds(ProductInterface $entity): array + { + $linksIds = []; + $entity->unsDownloadableLinks(); + $links = $this->downloadableType->getLinks($entity); + + foreach ($links as $link) { + $linksIds[] = (int) $link->getId(); + } + + return $linksIds; + } + + /** + * Retrieve Downloadable Links ids from the provided entity. + * + * @param ProductInterface $entity + * @return int[] + */ + private function getLinksByFile(ProductInterface $entity): array + { + $linksByFile = []; + $links = $this->downloadableType->getLinks($entity); + + foreach ($links as $link) { + $key = json_encode( + $link->getProductId() + . $link->getSortOrder() + . $link->getLinkType() + . $link->getLinkFile() + . $link->getLinkUrl() + ); + $linksByFile[$key] = (int) $link->getId(); + } + + return $linksByFile; + } +} diff --git a/vendor/magento/module-downloadable-staging/etc/di.xml b/vendor/magento/module-downloadable-staging/etc/di.xml index ea4b82a7deb..8d1eff1b35f 100644 --- a/vendor/magento/module-downloadable-staging/etc/di.xml +++ b/vendor/magento/module-downloadable-staging/etc/di.xml @@ -12,4 +12,11 @@ + + + + Magento\DownloadableStaging\Model\UpdateStagingQuoteItemOptions + + +