Skip to content

Commit

Permalink
Merge pull request #6325 from magento-l3/TANGO-PR-11-05-2020_24
Browse files Browse the repository at this point in the history
TANGO PR 11-05-2020 v24
  • Loading branch information
dhorytskyi authored Nov 13, 2020
2 parents 884d148 + 6a5a1b6 commit 252dd90
Show file tree
Hide file tree
Showing 30 changed files with 1,918 additions and 181 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,17 @@
use Magento\Store\Model\StoreManagerInterface;
use Magento\Framework\DB\Query\Generator as QueryGenerator;
use Magento\Framework\EntityManager\MetadataPool;
use Magento\Framework\Indexer\IndexerRegistry;
use Magento\Catalog\Model\Config;
use Magento\Catalog\Model\Category;
use Magento\Framework\Indexer\IndexerRegistry;
use Magento\Catalog\Model\Indexer\Product\Category as ProductCategoryIndexer;
use Magento\Catalog\Model\Indexer\Category\Product as CategoryProductIndexer;
use Magento\Catalog\Model\Indexer\Category\Product\TableMaintainer;
use Magento\Indexer\Model\WorkingStateProvider;

/**
* Reindex multiple rows action.
*
* @package Magento\Catalog\Model\Indexer\Category\Product\Action
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class Rows extends \Magento\Catalog\Model\Indexer\Category\Product\AbstractAction
Expand All @@ -48,30 +50,42 @@ class Rows extends \Magento\Catalog\Model\Indexer\Category\Product\AbstractActio
*/
private $indexerRegistry;

/**
* @var WorkingStateProvider
*/
private $workingStateProvider;

/**
* @param ResourceConnection $resource
* @param StoreManagerInterface $storeManager
* @param Config $config
* @param QueryGenerator|null $queryGenerator
* @param MetadataPool|null $metadataPool
* @param TableMaintainer|null $tableMaintainer
* @param CacheContext|null $cacheContext
* @param EventManagerInterface|null $eventManager
* @param IndexerRegistry|null $indexerRegistry
* @param WorkingStateProvider|null $workingStateProvider
* @SuppressWarnings(PHPMD.ExcessiveParameterList) Preserve compatibility with the parent class
*/
public function __construct(
ResourceConnection $resource,
StoreManagerInterface $storeManager,
Config $config,
QueryGenerator $queryGenerator = null,
MetadataPool $metadataPool = null,
?TableMaintainer $tableMaintainer = null,
CacheContext $cacheContext = null,
EventManagerInterface $eventManager = null,
IndexerRegistry $indexerRegistry = null
IndexerRegistry $indexerRegistry = null,
?WorkingStateProvider $workingStateProvider = null
) {
parent::__construct($resource, $storeManager, $config, $queryGenerator, $metadataPool);
parent::__construct($resource, $storeManager, $config, $queryGenerator, $metadataPool, $tableMaintainer);
$this->cacheContext = $cacheContext ?: ObjectManager::getInstance()->get(CacheContext::class);
$this->eventManager = $eventManager ?: ObjectManager::getInstance()->get(EventManagerInterface::class);
$this->indexerRegistry = $indexerRegistry ?: ObjectManager::getInstance()->get(IndexerRegistry::class);
$this->workingStateProvider = $workingStateProvider ?:
ObjectManager::getInstance()->get(WorkingStateProvider::class);
}

/**
Expand All @@ -97,44 +111,64 @@ public function execute(array $entityIds = [], $useTempTable = false)
$this->limitationByCategories = array_unique($this->limitationByCategories);
$this->useTempTable = $useTempTable;
$indexer = $this->indexerRegistry->get(ProductCategoryIndexer::INDEXER_ID);
$workingState = $indexer->isWorking();
$workingState = $this->isWorkingState();

if ($useTempTable && !$workingState && $indexer->isScheduled()) {
foreach ($this->storeManager->getStores() as $store) {
$this->connection->truncateTable($this->getIndexTable($store->getId()));
if (!$indexer->isScheduled()
|| ($indexer->isScheduled() && !$useTempTable)
|| ($indexer->isScheduled() && $useTempTable && !$workingState)) {
if ($useTempTable && !$workingState && $indexer->isScheduled()) {
foreach ($this->storeManager->getStores() as $store) {
$this->connection->truncateTable($this->getIndexTable($store->getId()));
}
} else {
$this->removeEntries();
}
} else {
$this->removeEntries();
}

$this->reindex();

if ($useTempTable && !$workingState && $indexer->isScheduled()) {
foreach ($this->storeManager->getStores() as $store) {
$removalCategoryIds = array_diff($this->limitationByCategories, [$this->getRootCategoryId($store)]);
$this->connection->delete(
$this->tableMaintainer->getMainTable($store->getId()),
['category_id IN (?)' => $removalCategoryIds]
);
$select = $this->connection->select()
->from($this->tableMaintainer->getMainReplicaTable($store->getId()));
$this->connection->query(
$this->connection->insertFromSelect(
$select,
$this->reindex();

// get actual state
$workingState = $this->isWorkingState();

if ($useTempTable && !$workingState && $indexer->isScheduled()) {
foreach ($this->storeManager->getStores() as $store) {
$removalCategoryIds = array_diff($this->limitationByCategories, [$this->getRootCategoryId($store)]);
$this->connection->delete(
$this->tableMaintainer->getMainTable($store->getId()),
[],
AdapterInterface::INSERT_ON_DUPLICATE
)
);
['category_id IN (?)' => $removalCategoryIds]
);
$select = $this->connection->select()
->from($this->tableMaintainer->getMainReplicaTable($store->getId()));
$this->connection->query(
$this->connection->insertFromSelect(
$select,
$this->tableMaintainer->getMainTable($store->getId()),
[],
AdapterInterface::INSERT_ON_DUPLICATE
)
);
}
}
}

$this->registerCategories($entityIds);
$this->eventManager->dispatch('clean_cache_by_tags', ['object' => $this->cacheContext]);
$this->registerCategories($entityIds);
$this->eventManager->dispatch('clean_cache_by_tags', ['object' => $this->cacheContext]);
}

return $this;
}

/**
* Get state for current and shared indexer
*
* @return bool
*/
private function isWorkingState() : bool
{
$indexer = $this->indexerRegistry->get(ProductCategoryIndexer::INDEXER_ID);
$sharedIndexer = $this->indexerRegistry->get(CategoryProductIndexer::INDEXER_ID);
return $this->workingStateProvider->isWorking($indexer->getId())
|| $this->workingStateProvider->isWorking($sharedIndexer->getId());
}

/**
* Register categories assigned to products
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
use Magento\Store\Model\StoreManagerInterface;
use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\Indexer\IndexerRegistry;
use Magento\Catalog\Model\Indexer\Product\Category as ProductCategoryIndexer;
use Magento\Catalog\Model\Indexer\Category\Product as CategoryProductIndexer;
use Magento\Catalog\Model\Indexer\Category\Product\TableMaintainer;
use Magento\Indexer\Model\WorkingStateProvider;

/**
* Category rows indexer.
Expand Down Expand Up @@ -48,30 +51,42 @@ class Rows extends \Magento\Catalog\Model\Indexer\Category\Product\AbstractActio
*/
private $indexerRegistry;

/**
* @var WorkingStateProvider
*/
private $workingStateProvider;

/**
* @param ResourceConnection $resource
* @param StoreManagerInterface $storeManager
* @param Config $config
* @param QueryGenerator|null $queryGenerator
* @param MetadataPool|null $metadataPool
* @param TableMaintainer|null $tableMaintainer
* @param CacheContext|null $cacheContext
* @param EventManagerInterface|null $eventManager
* @param IndexerRegistry|null $indexerRegistry
* @param WorkingStateProvider|null $workingStateProvider
* @SuppressWarnings(PHPMD.ExcessiveParameterList) Preserve compatibility with the parent class
*/
public function __construct(
ResourceConnection $resource,
StoreManagerInterface $storeManager,
Config $config,
QueryGenerator $queryGenerator = null,
MetadataPool $metadataPool = null,
?TableMaintainer $tableMaintainer = null,
CacheContext $cacheContext = null,
EventManagerInterface $eventManager = null,
IndexerRegistry $indexerRegistry = null
IndexerRegistry $indexerRegistry = null,
?WorkingStateProvider $workingStateProvider = null
) {
parent::__construct($resource, $storeManager, $config, $queryGenerator, $metadataPool);
parent::__construct($resource, $storeManager, $config, $queryGenerator, $metadataPool, $tableMaintainer);
$this->cacheContext = $cacheContext ?: ObjectManager::getInstance()->get(CacheContext::class);
$this->eventManager = $eventManager ?: ObjectManager::getInstance()->get(EventManagerInterface::class);
$this->indexerRegistry = $indexerRegistry ?: ObjectManager::getInstance()->get(IndexerRegistry::class);
$this->workingStateProvider = $workingStateProvider ?:
ObjectManager::getInstance()->get(WorkingStateProvider::class);
}

/**
Expand All @@ -82,6 +97,7 @@ public function __construct(
* @return $this
* @throws \Exception if metadataPool doesn't contain metadata for ProductInterface
* @throws \DomainException
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function execute(array $entityIds = [], $useTempTable = false)
{
Expand All @@ -90,46 +106,68 @@ public function execute(array $entityIds = [], $useTempTable = false)
$this->limitationByProducts = $idsToBeReIndexed;
$this->useTempTable = $useTempTable;
$indexer = $this->indexerRegistry->get(CategoryProductIndexer::INDEXER_ID);
$workingState = $indexer->isWorking();
$workingState = $this->isWorkingState();

$affectedCategories = $this->getCategoryIdsFromIndex($idsToBeReIndexed);
if (!$indexer->isScheduled()
|| ($indexer->isScheduled() && !$useTempTable)
|| ($indexer->isScheduled() && $useTempTable && !$workingState)) {

if ($useTempTable && !$workingState && $indexer->isScheduled()) {
foreach ($this->storeManager->getStores() as $store) {
$this->connection->truncateTable($this->getIndexTable($store->getId()));
$affectedCategories = $this->getCategoryIdsFromIndex($idsToBeReIndexed);

if ($useTempTable && !$workingState && $indexer->isScheduled()) {
foreach ($this->storeManager->getStores() as $store) {
$this->connection->truncateTable($this->getIndexTable($store->getId()));
}
} else {
$this->removeEntries();
}
} else {
$this->removeEntries();
}
$this->reindex();
if ($useTempTable && !$workingState && $indexer->isScheduled()) {
foreach ($this->storeManager->getStores() as $store) {
$this->connection->delete(
$this->tableMaintainer->getMainTable($store->getId()),
['product_id IN (?)' => $this->limitationByProducts]
);
$select = $this->connection->select()
->from($this->tableMaintainer->getMainReplicaTable($store->getId()));
$this->connection->query(
$this->connection->insertFromSelect(
$select,
$this->reindex();

// get actual state
$workingState = $this->isWorkingState();

if ($useTempTable && !$workingState && $indexer->isScheduled()) {
foreach ($this->storeManager->getStores() as $store) {
$this->connection->delete(
$this->tableMaintainer->getMainTable($store->getId()),
[],
AdapterInterface::INSERT_ON_DUPLICATE
)
);
['product_id IN (?)' => $this->limitationByProducts]
);
$select = $this->connection->select()
->from($this->tableMaintainer->getMainReplicaTable($store->getId()));
$this->connection->query(
$this->connection->insertFromSelect(
$select,
$this->tableMaintainer->getMainTable($store->getId()),
[],
AdapterInterface::INSERT_ON_DUPLICATE
)
);
}
}
}

$affectedCategories = array_merge($affectedCategories, $this->getCategoryIdsFromIndex($idsToBeReIndexed));
$affectedCategories = array_merge($affectedCategories, $this->getCategoryIdsFromIndex($idsToBeReIndexed));

$this->registerProducts($idsToBeReIndexed);
$this->registerCategories($affectedCategories);
$this->eventManager->dispatch('clean_cache_by_tags', ['object' => $this->cacheContext]);
$this->registerProducts($idsToBeReIndexed);
$this->registerCategories($affectedCategories);
$this->eventManager->dispatch('clean_cache_by_tags', ['object' => $this->cacheContext]);
}

return $this;
}

/**
* Get state for current and shared indexer
*
* @return bool
*/
private function isWorkingState() : bool
{
$indexer = $this->indexerRegistry->get(CategoryProductIndexer::INDEXER_ID);
$sharedIndexer = $this->indexerRegistry->get(ProductCategoryIndexer::INDEXER_ID);
return $this->workingStateProvider->isWorking($indexer->getId())
|| $this->workingStateProvider->isWorking($sharedIndexer->getId());
}

/**
* Get IDs of parent products by their child IDs.
*
Expand Down
35 changes: 24 additions & 11 deletions app/code/Magento/Catalog/Model/Product/Gallery/UpdateHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,26 +77,26 @@ protected function processDeletedImages($product, array &$images)
{
$filesToDelete = [];
$recordsToDelete = [];
$picturesInOtherStores = [];
$imagesToDelete = [];

foreach ($this->resourceModel->getProductImages($product, $this->extractStoreIds($product)) as $image) {
$picturesInOtherStores[$image['filepath']] = true;
$imagesToNotDelete = [];
foreach ($images as $image) {
if (empty($image['removed'])) {
$imagesToNotDelete[] = $image['file'];
}
}

foreach ($images as &$image) {
foreach ($images as $image) {
if (!empty($image['removed'])) {
if (!empty($image['value_id'])) {
if (preg_match('/\.\.(\\\|\/)/', $image['file'])) {
continue;
}
$recordsToDelete[] = $image['value_id'];
$imagesToDelete[] = $image['file'];
$catalogPath = $this->mediaConfig->getBaseMediaPath();
$isFile = $this->mediaDirectory->isFile($catalogPath . $image['file']);
// only delete physical files if they are not used by any other products and if this file exist
if ($isFile && !($this->resourceModel->countImageUses($image['file']) > 1)) {
$filesToDelete[] = ltrim($image['file'], '/');
if (!in_array($image['file'], $imagesToNotDelete)) {
$imagesToDelete[] = $image['file'];
if ($this->canDeleteImage($image['file'])) {
$filesToDelete[] = ltrim($image['file'], '/');
}
}
}
}
Expand All @@ -107,6 +107,19 @@ protected function processDeletedImages($product, array &$images)
$this->removeDeletedImages($filesToDelete);
}

/**
* Check if image exists and is not used by any other products
*
* @param string $file
* @return bool
*/
private function canDeleteImage(string $file): bool
{
$catalogPath = $this->mediaConfig->getBaseMediaPath();
return $this->mediaDirectory->isFile($catalogPath . $file)
&& $this->resourceModel->countImageUses($file) <= 1;
}

/**
* @inheritdoc
*
Expand Down
Loading

0 comments on commit 252dd90

Please sign in to comment.