Skip to content

Commit 789be04

Browse files
committed
Merge remote-tracking branch 'origin/2.4-develop' into MQE-2538
2 parents 46216bf + 69f3cd0 commit 789be04

File tree

149 files changed

+10362
-561
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

149 files changed

+10362
-561
lines changed

app/code/Magento/Catalog/Controller/Adminhtml/Product/MassDelete.php

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@
99
namespace Magento\Catalog\Controller\Adminhtml\Product;
1010

1111
use Magento\Backend\App\Action\Context;
12+
use Magento\Backend\Model\View\Result\Redirect;
1213
use Magento\Catalog\Api\ProductRepositoryInterface;
14+
use Magento\Catalog\Controller\Adminhtml\Product;
1315
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
1416
use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
17+
use Magento\Framework\App\ObjectManager;
1518
use Magento\Framework\Controller\ResultFactory;
1619
use Magento\Framework\Exception\LocalizedException;
1720
use Magento\Ui\Component\MassAction\Filter;
@@ -20,7 +23,7 @@
2023
/**
2124
* Class \Magento\Catalog\Controller\Adminhtml\Product\MassDelete
2225
*/
23-
class MassDelete extends \Magento\Catalog\Controller\Adminhtml\Product implements HttpPostActionInterface
26+
class MassDelete extends Product implements HttpPostActionInterface
2427
{
2528
/**
2629
* Massactions filter
@@ -49,8 +52,8 @@ class MassDelete extends \Magento\Catalog\Controller\Adminhtml\Product implement
4952
* @param Builder $productBuilder
5053
* @param Filter $filter
5154
* @param CollectionFactory $collectionFactory
52-
* @param ProductRepositoryInterface $productRepository
53-
* @param LoggerInterface $logger
55+
* @param ProductRepositoryInterface|null $productRepository
56+
* @param LoggerInterface|null $logger
5457
*/
5558
public function __construct(
5659
Context $context,
@@ -63,20 +66,23 @@ public function __construct(
6366
$this->filter = $filter;
6467
$this->collectionFactory = $collectionFactory;
6568
$this->productRepository = $productRepository ?:
66-
\Magento\Framework\App\ObjectManager::getInstance()->create(ProductRepositoryInterface::class);
69+
ObjectManager::getInstance()->create(ProductRepositoryInterface::class);
6770
$this->logger = $logger ?:
68-
\Magento\Framework\App\ObjectManager::getInstance()->create(LoggerInterface::class);
71+
ObjectManager::getInstance()->create(LoggerInterface::class);
6972
parent::__construct($context, $productBuilder);
7073
}
7174

7275
/**
7376
* Mass Delete Action
7477
*
75-
* @return \Magento\Backend\Model\View\Result\Redirect
78+
* @return Redirect
79+
* @throws LocalizedException
7680
*/
7781
public function execute()
7882
{
7983
$collection = $this->filter->getCollection($this->collectionFactory->create());
84+
$collection->addMediaGalleryData();
85+
8086
$productDeleted = 0;
8187
$productDeletedError = 0;
8288
/** @var \Magento\Catalog\Model\Product $product */
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Model\ResourceModel;
9+
10+
use Exception;
11+
use Magento\Catalog\Api\Data\ProductInterface;
12+
use Magento\Catalog\Model\Product\Gallery\Processor;
13+
use Magento\Catalog\Model\Product\Media\ConfigInterface as MediaConfig;
14+
use Magento\Catalog\Model\ResourceModel\Product\Gallery;
15+
use Magento\Framework\App\Filesystem\DirectoryList;
16+
use Magento\Framework\DataObject;
17+
use Magento\Framework\Exception\FileSystemException;
18+
use Magento\Framework\Filesystem;
19+
use Psr\Log\LoggerInterface;
20+
21+
/**
22+
* Process media gallery and delete media image after product delete
23+
*/
24+
class MediaImageDeleteProcessor
25+
{
26+
/**
27+
* @var MediaConfig
28+
*/
29+
private $imageConfig;
30+
31+
/**
32+
* @var Filesystem
33+
*/
34+
private $mediaDirectory;
35+
36+
/**
37+
* @var Processor
38+
*/
39+
private $imageProcessor;
40+
41+
/**
42+
* @var Gallery
43+
*/
44+
private $productGallery;
45+
46+
/**
47+
* @var LoggerInterface
48+
*/
49+
private $logger;
50+
51+
/**
52+
* Product constructor.
53+
*
54+
* @param MediaConfig $imageConfig
55+
* @param Filesystem $filesystem
56+
* @param Processor $imageProcessor
57+
* @param Gallery $productGallery
58+
* @param LoggerInterface $logger
59+
* @throws FileSystemException
60+
*/
61+
public function __construct(
62+
MediaConfig $imageConfig,
63+
Filesystem $filesystem,
64+
Processor $imageProcessor,
65+
Gallery $productGallery,
66+
LoggerInterface $logger
67+
) {
68+
$this->imageConfig = $imageConfig;
69+
$this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA);
70+
$this->imageProcessor = $imageProcessor;
71+
$this->productGallery = $productGallery;
72+
$this->logger = $logger;
73+
}
74+
75+
/**
76+
* Process $product data and remove image from gallery after product delete
77+
*
78+
* @param DataObject $product
79+
* @return void
80+
*/
81+
public function execute(DataObject $product): void
82+
{
83+
try {
84+
$productImages = $product->getMediaGalleryImages();
85+
foreach ($productImages as $image) {
86+
$imageFile = $image->getFile();
87+
if ($imageFile) {
88+
$this->deleteProductImage($image, $product, $imageFile);
89+
}
90+
}
91+
} catch (Exception $e) {
92+
$this->logger->critical($e);
93+
}
94+
}
95+
96+
/**
97+
* Check if image exists and is not used by any other products
98+
*
99+
* @param string $file
100+
* @return bool
101+
*/
102+
private function canDeleteImage(string $file): bool
103+
{
104+
return $this->productGallery->countImageUses($file) <= 1;
105+
}
106+
107+
/**
108+
* Delete the physical image if it's existed and not used by other products
109+
*
110+
* @param string $imageFile
111+
* @param string $filePath
112+
* @throws FileSystemException
113+
*/
114+
private function deletePhysicalImage(string $imageFile, string $filePath): void
115+
{
116+
if ($this->canDeleteImage($imageFile)) {
117+
$this->mediaDirectory->delete($filePath);
118+
}
119+
}
120+
121+
/**
122+
* Remove product image
123+
*
124+
* @param DataObject $image
125+
* @param ProductInterface $product
126+
* @param string $imageFile
127+
*/
128+
private function deleteProductImage(
129+
DataObject $image,
130+
ProductInterface $product,
131+
string $imageFile
132+
): void {
133+
$catalogPath = $this->imageConfig->getBaseMediaPath();
134+
$filePath = $catalogPath . $imageFile;
135+
136+
if ($this->mediaDirectory->isFile($filePath)) {
137+
try {
138+
$this->productGallery->deleteGallery($image->getValueId());
139+
$this->imageProcessor->removeImage($product, $imageFile);
140+
$this->deletePhysicalImage($imageFile, $filePath);
141+
} catch (Exception $e) {
142+
$this->logger->critical($e);
143+
}
144+
}
145+
}
146+
}

app/code/Magento/Catalog/Model/ResourceModel/Product.php

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ class Product extends AbstractResource
100100
*/
101101
private $eavAttributeManagement;
102102

103+
/**
104+
* @var MediaImageDeleteProcessor
105+
*/
106+
private $mediaImageDeleteProcessor;
107+
103108
/**
104109
* @param \Magento\Eav\Model\Entity\Context $context
105110
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
@@ -114,6 +119,7 @@ class Product extends AbstractResource
114119
* @param TableMaintainer|null $tableMaintainer
115120
* @param UniqueValidationInterface|null $uniqueValidator
116121
* @param AttributeManagementInterface|null $eavAttributeManagement
122+
* @param MediaImageDeleteProcessor|null $mediaImageDeleteProcessor
117123
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
118124
*/
119125
public function __construct(
@@ -129,7 +135,8 @@ public function __construct(
129135
$data = [],
130136
TableMaintainer $tableMaintainer = null,
131137
UniqueValidationInterface $uniqueValidator = null,
132-
AttributeManagementInterface $eavAttributeManagement = null
138+
AttributeManagementInterface $eavAttributeManagement = null,
139+
?MediaImageDeleteProcessor $mediaImageDeleteProcessor = null
133140
) {
134141
$this->_categoryCollectionFactory = $categoryCollectionFactory;
135142
$this->_catalogCategory = $catalogCategory;
@@ -148,6 +155,8 @@ public function __construct(
148155
$this->tableMaintainer = $tableMaintainer ?: ObjectManager::getInstance()->get(TableMaintainer::class);
149156
$this->eavAttributeManagement = $eavAttributeManagement
150157
?? ObjectManager::getInstance()->get(AttributeManagementInterface::class);
158+
$this->mediaImageDeleteProcessor = $mediaImageDeleteProcessor
159+
?? ObjectManager::getInstance()->get(MediaImageDeleteProcessor::class);
151160
}
152161

153162
/**
@@ -819,4 +828,16 @@ protected function getAttributeRow($entity, $object, $attribute)
819828
$data['store_id'] = $object->getStoreId();
820829
return $data;
821830
}
831+
832+
/**
833+
* After delete entity process
834+
*
835+
* @param DataObject $object
836+
* @return $this
837+
*/
838+
protected function _afterDelete(DataObject $object)
839+
{
840+
$this->mediaImageDeleteProcessor->execute($object);
841+
return parent::_afterDelete($object);
842+
}
822843
}

0 commit comments

Comments
 (0)