Skip to content

Commit

Permalink
Merge branch '2.4-develop' into AC-9547
Browse files Browse the repository at this point in the history
  • Loading branch information
svera authored Oct 26, 2023
2 parents 387dffc + 2f5faa7 commit 53769f6
Show file tree
Hide file tree
Showing 10 changed files with 343 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public function __construct(
* @throws InputException
* @throws StateException
* @throws LocalizedException
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function processMediaGallery(ProductInterface $product, array $mediaGalleryEntries) :void
{
Expand Down Expand Up @@ -113,6 +114,9 @@ public function processMediaGallery(ProductInterface $product, array $mediaGalle
// phpcs:ignore Magento2.Performance.ForeachArrayMerge
$existingMediaGallery[$key] = array_merge($existingEntry, $updatedEntry);
}
} elseif (!empty($newEntries) && isset($existingEntry['value_id'])) {
//avoid deleting an exiting image while adding a new one
unset($existingMediaGallery[$key]);
} elseif ($this->canRemoveImage($product, $existingEntry)) {
//set the removed flag
$existingEntry['removed'] = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\Catalog\Test\Unit\Model\ProductRepository;

use Magento\Catalog\Model\Product;
use Magento\Catalog\Model\Product\Gallery\DeleteValidator;
use Magento\Catalog\Model\Product\Gallery\Processor;
use Magento\Catalog\Model\Product\Media\Config;
use Magento\Catalog\Model\ProductRepository\MediaGalleryProcessor;
use Magento\Framework\Api\Data\ImageContentInterface;
use Magento\Framework\Api\Data\ImageContentInterfaceFactory;
use Magento\Framework\Api\ImageContent;
use Magento\Framework\Api\ImageProcessorInterface;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;

class MediaGalleryProcessorTest extends TestCase
{
/**
* @var MediaGalleryProcessor
*/
private $galleryProcessor;

/**
* @var Processor|MockObject
*/
private $processorMock;

/**
* @var ImageContentInterfaceFactory|MockObject
*/
private $contentFactoryMock;

/**
* @var ImageProcessorInterface|MockObject
*/
private $imageProcessorMock;

/**
* @var DeleteValidator|MockObject
*/
private $deleteValidatorMock;

/**
* @var Product|MockObject
*/
private $productMock;

protected function setUp(): void
{
$this->processorMock = $this->getMockBuilder(Processor::class)
->disableOriginalConstructor()
->getMock();
$this->contentFactoryMock = $this->getMockBuilder(ImageContentInterfaceFactory::class)
->disableOriginalConstructor()
->getMock();
$this->imageProcessorMock = $this->getMockBuilder(ImageProcessorInterface::class)
->disableOriginalConstructor()
->getMock();
$this->deleteValidatorMock = $this->getMockBuilder(DeleteValidator::class)
->disableOriginalConstructor()
->getMock();
$this->productMock = $this->getMockBuilder(Product::class)
->addMethods(['getMediaGallery'])
->onlyMethods(['hasGalleryAttribute', 'getMediaConfig', 'getMediaAttributes'])
->disableOriginalConstructor()
->getMock();

$this->galleryProcessor = new MediaGalleryProcessor(
$this->processorMock,
$this->contentFactoryMock,
$this->imageProcessorMock,
$this->deleteValidatorMock
);
}

/**
* The media gallery array should not have "removed" key while adding the new entry
*
* @return void
*/
public function testProcessMediaGallery(): void
{
$initialExitingEntry = [
'value_id' => 5,
"label" => "new_label_text",
'file' => 'filename1',
'position' => 10,
'disabled' => false,
'types' => ['image', 'small_image']
];
$newEntriesData = [
'images' => [
$initialExitingEntry,
[
'value_id' => null,
'label' => "label_text",
'position' => 10,
'disabled' => false,
'types' => ['image', 'small_image'],
'content' => [
'data' => [
ImageContentInterface::NAME => 'filename',
ImageContentInterface::TYPE => 'image/jpeg',
ImageContentInterface::BASE64_ENCODED_DATA => 'encoded_content'
]
],
'media_type' => 'media_type'
]
]
];
$newExitingEntriesData = [
'images' => [
$initialExitingEntry,
[
'value_id' => 6,
"label" => "label_text2",
'file' => 'filename2',
'position' => 10,
'disabled' => false,
'types' => ['image', 'small_image']
]
]
];
$this->productMock->method('getMediaGallery')
->willReturnOnConsecutiveCalls(
$newExitingEntriesData['images'],
$newExitingEntriesData['images']
);
$this->productMock->expects($this->any())
->method('getMediaAttributes')
->willReturn(["image" => "imageAttribute", "small_image" => "small_image_attribute"]);
$this->productMock->method('hasGalleryAttribute')->willReturn(true);
$mediaTmpPath = '/tmp';
$absolutePath = '/a/b/filename.jpg';
$this->processorMock->expects($this->once())->method('clearMediaAttribute')
->with($this->productMock, ['image', 'small_image']);
$mediaConfigMock = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
$mediaConfigMock->expects($this->once())->method('getTmpMediaShortUrl')->with($absolutePath)
->willReturn($mediaTmpPath . $absolutePath);
$this->productMock->expects($this->once())->method('getMediaConfig')->willReturn($mediaConfigMock);
//verify new entries
$contentDataObject = $this->getMockBuilder(ImageContent::class)
->disableOriginalConstructor()
->setMethods(null)
->getMock();
$this->contentFactoryMock->expects($this->once())->method('create')->willReturn($contentDataObject);
$this->imageProcessorMock->expects($this->once())->method('processImageContent')->willReturn($absolutePath);
$imageFileUri = $mediaTmpPath . $absolutePath;
$this->processorMock->expects($this->once())->method('addImage')
->willReturnCallback(
function ($product, $imageFileUri) use ($newEntriesData) {
foreach ($product['media_gallery']['images'] as $entry) {
if (isset($entry['value_id'])) {
$this->assertArrayNotHasKey('removed', $entry);
}
}
$this->productMock->setData('media_gallery', $newEntriesData);
return $imageFileUri;
}
);
$this->processorMock->expects($this->once())->method('updateImage')
->with(
$this->productMock,
$imageFileUri,
[
'label' => 'label_text',
'position' => 10,
'disabled' => false,
'media_type' => 'media_type',
]
);
$this->galleryProcessor->processMediaGallery($this->productMock, $newEntriesData['images']);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
use Magento\Catalog\Model\CategoryFactory;
use Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator;
use Magento\CatalogUrlRewrite\Model\Category\ChildrenCategoriesProvider;
use Magento\Store\Model\Store;
use Magento\Store\Model\StoreManagerInterface;

/**
* Perform url updating for children categories.
Expand All @@ -31,19 +31,27 @@ class Move
*/
private $categoryFactory;

/**
* @var StoreManagerInterface
*/
private $storeManager;

/**
* @param CategoryUrlPathGenerator $categoryUrlPathGenerator
* @param ChildrenCategoriesProvider $childrenCategoriesProvider
* @param CategoryFactory $categoryFactory
* @param StoreManagerInterface $storeManager
*/
public function __construct(
CategoryUrlPathGenerator $categoryUrlPathGenerator,
ChildrenCategoriesProvider $childrenCategoriesProvider,
CategoryFactory $categoryFactory
CategoryFactory $categoryFactory,
StoreManagerInterface $storeManager
) {
$this->categoryUrlPathGenerator = $categoryUrlPathGenerator;
$this->childrenCategoriesProvider = $childrenCategoriesProvider;
$this->categoryFactory = $categoryFactory;
$this->storeManager = $storeManager;
}

/**
Expand All @@ -67,6 +75,7 @@ public function afterChangeParent(
$categoryStoreId = $category->getStoreId();
foreach ($category->getStoreIds() as $storeId) {
$category->setStoreId($storeId);
$this->removeObsoleteUrlPathEntries($category);
$this->updateCategoryUrlKeyForStore($category);
$category->unsUrlPath();
$category->setUrlPath($this->categoryUrlPathGenerator->getUrlPath($category));
Expand All @@ -92,24 +101,13 @@ private function updateCategoryUrlKeyForStore(Category $category)
$category->setUrlKey($item->getUrlKey());
}

/**
* Check is global scope.
*
* @param int|null $storeId
* @return bool
*/
private function isGlobalScope($storeId)
{
return null === $storeId || $storeId == Store::DEFAULT_STORE_ID;
}

/**
* Updates url_path for child categories.
*
* @param Category $category
* @return void
*/
private function updateUrlPathForChildren($category)
private function updateUrlPathForChildren(Category $category): void
{
foreach ($this->childrenCategoriesProvider->getChildren($category, true) as $childCategory) {
$childCategory->setStoreId($category->getStoreId());
Expand All @@ -118,4 +116,27 @@ private function updateUrlPathForChildren($category)
$childCategory->getResource()->saveAttribute($childCategory, 'url_path');
}
}

/**
* Clean obsolete entries
*
* @param Category $category
* @return void
*/
private function removeObsoleteUrlPathEntries(Category $category): void
{
if ($this->storeManager->hasSingleStore()) {
return;
}
$origPath = $category->getOrigData('path');
$path = $category->getData('path');
if ($origPath != null && $path != null && $origPath != $path) {
$category->unsUrlPath();
$category->getResource()->saveAttribute($category, 'url_path');
foreach ($this->childrenCategoriesProvider->getChildren($category, true) as $childCategory) {
$childCategory->unsUrlPath();
$childCategory->getResource()->saveAttribute($childCategory, 'url_path');
}
}
}
}
Loading

0 comments on commit 53769f6

Please sign in to comment.