Skip to content

Commit

Permalink
Merge pull request #8874 from adobe-commerce-tier-4/T4-PR-04-08-2024
Browse files Browse the repository at this point in the history
[Support Tier-4 chittima] 04-08-2024 Regular delivery of bugfixes and improvements
  • Loading branch information
dhorytskyi committed May 20, 2024
2 parents c6bc830 + e267eaa commit c893121
Show file tree
Hide file tree
Showing 15 changed files with 745 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
<?php
/************************************************************************
*
* Copyright 2024 Adobe
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe and its suppliers, if any. The intellectual
* and technical concepts contained herein are proprietary to Adobe
* and its suppliers and are protected by all applicable intellectual
* property laws, including trade secret and copyright laws.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe.
* ************************************************************************
*/
declare(strict_types=1);

namespace Magento\Catalog\Model\ResourceModel;

use Exception;
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Eav\Api\Data\AttributeInterface;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\EntityManager\MetadataPool;
use Magento\Framework\Exception\CouldNotSaveException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Store\Model\Store;

/**
* Migrate related catalog category and product tables for single store view mode
*/
class CatalogCategoryAndProductResolverOnSingleStoreMode
{
/**
* @param ResourceConnection $resourceConnection
* @param MetadataPool $metadataPool
*/
public function __construct(
private readonly ResourceConnection $resourceConnection,
private readonly MetadataPool $metadataPool
) {
}

/**
* Process the Catalog and Product tables and migrate to single store view mode
*
* @param int $storeId
* @param string $table
* @return void
* @throws CouldNotSaveException
*/
private function process(int $storeId, string $table): void
{
$metadata = $this->metadataPool->getMetadata(ProductInterface::class);
$linkField = $metadata->getLinkField();
$catalogProductTable = $this->resourceConnection->getTableName($table);

$catalogProducts = $this->getCatalogProducts($table, $linkField, $storeId);
$linkFieldIds = [];
$attributeIds = [];
$valueIds = [];
try {
if ($catalogProducts) {
foreach ($catalogProducts as $catalogProduct) {
$linkFieldIds[] = $catalogProduct[$linkField];
$attributeIds[] = $catalogProduct[AttributeInterface::ATTRIBUTE_ID];
$valueIds[] = $catalogProduct['value_id'];
}
$this->massDelete($catalogProductTable, $linkField, $attributeIds, $linkFieldIds);
$this->massUpdate($catalogProductTable, $valueIds);
}
} catch (LocalizedException $e) {
throw new CouldNotSaveException(
__($e->getMessage()),
$e
);
}
}

/**
* Migrate catalog category and product tables
*
* @param int $storeId
* @throws Exception
*/
public function migrateCatalogCategoryAndProductTables(int $storeId): void
{
$connection = $this->resourceConnection->getConnection();
$tables = [
'catalog_category_entity_datetime',
'catalog_category_entity_decimal',
'catalog_category_entity_int',
'catalog_category_entity_text',
'catalog_category_entity_varchar',
'catalog_product_entity_datetime',
'catalog_product_entity_decimal',
'catalog_product_entity_gallery',
'catalog_product_entity_int',
'catalog_product_entity_text',
'catalog_product_entity_varchar',
];
try {
$connection->beginTransaction();
foreach ($tables as $table) {
$this->process($storeId, $table);
}
$connection->commit();
} catch (Exception $exception) {
$connection->rollBack();
}
}

/**
* Delete default store related products
*
* @param string $catalogProductTable
* @param string $linkField
* @param array $attributeIds
* @param array $linkFieldIds
* @return void
*/
private function massDelete(
string $catalogProductTable,
string $linkField,
array $attributeIds,
array $linkFieldIds
): void {
$connection = $this->resourceConnection->getConnection();

$connection->delete(
$catalogProductTable,
[
'store_id = ?' => Store::DEFAULT_STORE_ID,
AttributeInterface::ATTRIBUTE_ID. ' IN(?)' => $attributeIds,
$linkField.' IN(?)' => $linkFieldIds
]
);
}

/**
* Update default store related products
*
* @param string $catalogProductTable
* @param array $valueIds
* @return void
*/
private function massUpdate(string $catalogProductTable, array $valueIds): void
{
$connection = $this->resourceConnection->getConnection();

$connection->update(
$catalogProductTable,
['store_id' => Store::DEFAULT_STORE_ID],
['value_id IN(?)' => $valueIds]
);
}

/**
* Get list of products
*
* @param string $table
* @param string $linkField
* @param int $storeId
* @return array
*/
private function getCatalogProducts(string $table, string $linkField, int $storeId): array
{
$connection = $this->resourceConnection->getConnection();
$catalogProductTable = $this->resourceConnection->getTableName($table);
$select = $connection->select()
->from($catalogProductTable, ['value_id', AttributeInterface::ATTRIBUTE_ID, $linkField])
->where('store_id = ?', $storeId);
return $connection->fetchAll($select);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public function execute(DataObject $product): void
*/
private function canDeleteImage(string $file): bool
{
return $this->productGallery->countImageUses($file) <= 1;
return $this->productGallery->countImageUses($file) < 1;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php
/************************************************************************
*
* Copyright 2024 Adobe
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe and its suppliers, if any. The intellectual
* and technical concepts contained herein are proprietary to Adobe
* and its suppliers and are protected by all applicable intellectual
* property laws, including trade secret and copyright laws.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe.
* ************************************************************************
*/
declare(strict_types=1);

namespace Magento\Catalog\Observer;

use Magento\Catalog\Model\Indexer\Category\Product;
use Magento\Catalog\Model\Indexer\Product\Category as ProductCategoryIndexer;
use Magento\Catalog\Model\Indexer\Product\Price\Processor as PriceIndexProcessor;
use Magento\Catalog\Model\ResourceModel\CatalogCategoryAndProductResolverOnSingleStoreMode as Resolver;
use Magento\CatalogRule\Model\Indexer\Rule\RuleProductProcessor;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Indexer\IndexerRegistry;
use Magento\Store\Model\StoreManager;
use Magento\Store\Model\StoreManagerInterface;

/**
* Move and migrate store level catalog product and category to website level
*/
class MoveStoreLevelCatalogDataToWebsiteScopeOnSingleStoreMode implements ObserverInterface
{
/**
* @param IndexerRegistry $indexerRegistry
* @param ScopeConfigInterface $scopeConfig
* @param StoreManagerInterface $storeManager
* @param Resolver $categoryAndProductResolver
*/
public function __construct(
private readonly IndexerRegistry $indexerRegistry,
private readonly ScopeConfigInterface $scopeConfig,
private readonly StoreManagerInterface $storeManager,
private readonly Resolver $categoryAndProductResolver
) {
}

/**
* @inheritDoc
*/
public function execute(Observer $observer)
{
$changedPaths = (array)$observer->getEvent()->getChangedPaths();
if (in_array(StoreManager::XML_PATH_SINGLE_STORE_MODE_ENABLED, $changedPaths, true)
&& $this->scopeConfig->getValue(StoreManager::XML_PATH_SINGLE_STORE_MODE_ENABLED)
&& $this->storeManager->hasSingleStore()
) {
$store = $this->storeManager->getDefaultStoreView();
if ($store) {
$storeId = $store->getId();
$this->categoryAndProductResolver->migrateCatalogCategoryAndProductTables((int) $storeId);
$this->invalidateIndexer();
}
}
}

/**
* Invalidate related indexer
*/
private function invalidateIndexer(): void
{
$productIndexer = $this->indexerRegistry->get(Product::INDEXER_ID);
$categoryProductIndexer = $this->indexerRegistry->get(ProductCategoryIndexer::INDEXER_ID);
$priceIndexer = $this->indexerRegistry->get(PriceIndexProcessor::INDEXER_ID);
$ruleIndexer = $this->indexerRegistry->get(RuleProductProcessor::INDEXER_ID);
$productIndexer->invalidate();
$categoryProductIndexer->invalidate();
$priceIndexer->invalidate();
$ruleIndexer->invalidate();
}
}

0 comments on commit c893121

Please sign in to comment.