Skip to content

Commit

Permalink
Showing 124 changed files with 3,471 additions and 738 deletions.
10 changes: 5 additions & 5 deletions app/bootstrap.php
Original file line number Diff line number Diff line change
@@ -14,15 +14,15 @@
#ini_set('display_errors', 1);

/* PHP version validation */
if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 70103) {
if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 70300) {
if (PHP_SAPI == 'cli') {
echo 'Magento supports PHP 7.1.3 or later. ' .
'Please read https://devdocs.magento.com/guides/v2.3/install-gde/system-requirements-tech.html';
echo 'Magento supports PHP 7.3.0 or later. ' .
'Please read https://devdocs.magento.com/guides/v2.4/install-gde/system-requirements-tech.html';
} else {
echo <<<HTML
<div style="font:12px/1.35em arial, helvetica, sans-serif;">
<p>Magento supports PHP 7.1.3 or later. Please read
<a target="_blank" href="https://devdocs.magento.com/guides/v2.3/install-gde/system-requirements-tech.html">
<p>Magento supports PHP 7.3.0 or later. Please read
<a target="_blank" href="https://devdocs.magento.com/guides/v2.4/install-gde/system-requirements-tech.html">
Magento System Requirements</a>.
</div>
HTML;
Original file line number Diff line number Diff line change
@@ -24,14 +24,15 @@
<actionGroup ref="CliCacheCleanActionGroup" stepKey="cleanCache">
<argument name="tags" value="config"/>
</actionGroup>
<magentoCLI command="setup:static-content:deploy -f" stepKey="deployStaticContent"/>
<actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/>
</before>
<after>
<magentoCLI command="config:set {{MinifyJavaScriptFilesDisableConfigData.path}} {{MinifyJavaScriptFilesDisableConfigData.value}}" stepKey="disableJsMinification"/>
<actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/>
</after>
<see userInput="Dashboard" selector="{{AdminHeaderSection.pageTitle}}" stepKey="seeDashboardTitle"/>
<waitForPageLoad stepKey="waitForPageLoadOnDashboard"/>
<see userInput="Dashboard" selector="{{AdminHeaderSection.pageTitle}}" stepKey="seeDashboardTitle"/>
<actionGroup ref="AssertAdminSuccessLoginActionGroup" stepKey="loggedInSuccessfully"/>
<actionGroup ref="AssertAdminPageIsNot404ActionGroup" stepKey="dontSee404Page"/>
</test>
13 changes: 12 additions & 1 deletion app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php
Original file line number Diff line number Diff line change
@@ -596,10 +596,21 @@ private function canRemoveImage(ProductInterface $product, string $imageFile) :b
$canRemoveImage = true;
$gallery = $this->getImagesForAllStores($product);
$storeId = $product->getStoreId();
$storeIds = [];
$storeIds[] = 0;
$websiteIds = array_map('intval', $product->getWebsiteIds() ?? []);
foreach ($this->storeManager->getStores() as $store) {
if (in_array((int) $store->getWebsiteId(), $websiteIds, true)) {
$storeIds[] = (int) $store->getId();
}
}

if (!empty($gallery)) {
foreach ($gallery as $image) {
if ($image['filepath'] === $imageFile && (int) $image['store_id'] !== $storeId) {
if (in_array((int) $image['store_id'], $storeIds)
&& $image['filepath'] === $imageFile
&& (int) $image['store_id'] !== $storeId
) {
$canRemoveImage = false;
}
}
94 changes: 89 additions & 5 deletions app/code/Magento/Catalog/Model/Product/Gallery/UpdateHandler.php
Original file line number Diff line number Diff line change
@@ -5,17 +5,69 @@
*/
namespace Magento\Catalog\Model\Product\Gallery;

use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
use Magento\Catalog\Model\Product;
use Magento\Catalog\Model\Product\Media\Config;
use Magento\Catalog\Model\ResourceModel\Product\Gallery;
use Magento\Framework\EntityManager\Operation\ExtensionInterface;
use Magento\Eav\Model\ResourceModel\AttributeValue;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\EntityManager\MetadataPool;
use Magento\Framework\Filesystem;
use Magento\Framework\Json\Helper\Data;
use Magento\MediaStorage\Helper\File\Storage\Database;
use Magento\Store\Model\Store;
use Magento\Store\Model\StoreManagerInterface;

/**
* Update handler for catalog product gallery.
*
* @api
* @since 101.0.0
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class UpdateHandler extends \Magento\Catalog\Model\Product\Gallery\CreateHandler
class UpdateHandler extends CreateHandler
{
/**
* @var AttributeValue
*/
private $attributeValue;

/**
* @param MetadataPool $metadataPool
* @param ProductAttributeRepositoryInterface $attributeRepository
* @param Gallery $resourceModel
* @param Data $jsonHelper
* @param Config $mediaConfig
* @param Filesystem $filesystem
* @param Database $fileStorageDb
* @param StoreManagerInterface|null $storeManager
* @param AttributeValue|null $attributeValue
*/
public function __construct(
MetadataPool $metadataPool,
ProductAttributeRepositoryInterface $attributeRepository,
Gallery $resourceModel,
Data $jsonHelper,
Config $mediaConfig,
Filesystem $filesystem,
Database $fileStorageDb,
StoreManagerInterface $storeManager = null,
?AttributeValue $attributeValue = null
) {
parent::__construct(
$metadataPool,
$attributeRepository,
$resourceModel,
$jsonHelper,
$mediaConfig,
$filesystem,
$fileStorageDb,
$storeManager
);
$this->attributeValue = $attributeValue ?: ObjectManager::getInstance()->get(AttributeValue::class);
}

/**
* @inheritdoc
*
@@ -26,6 +78,7 @@ protected function processDeletedImages($product, array &$images)
$filesToDelete = [];
$recordsToDelete = [];
$picturesInOtherStores = [];
$imagesToDelete = [];

foreach ($this->resourceModel->getProductImages($product, $this->extractStoreIds($product)) as $image) {
$picturesInOtherStores[$image['filepath']] = true;
@@ -38,6 +91,7 @@ protected function processDeletedImages($product, array &$images)
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
@@ -48,8 +102,8 @@ protected function processDeletedImages($product, array &$images)
}
}

$this->deleteMediaAttributeValues($product, $imagesToDelete);
$this->resourceModel->deleteGallery($recordsToDelete);

$this->removeDeletedImages($filesToDelete);
}

@@ -94,14 +148,14 @@ protected function processNewImage($product, array &$image)
/**
* Retrieve store ids from product.
*
* @param \Magento\Catalog\Model\Product $product
* @param Product $product
* @return array
* @since 101.0.0
*/
protected function extractStoreIds($product)
{
$storeIds = $product->getStoreIds();
$storeIds[] = \Magento\Store\Model\Store::DEFAULT_STORE_ID;
$storeIds[] = Store::DEFAULT_STORE_ID;

// Removing current storeId.
$storeIds = array_flip($storeIds);
@@ -125,5 +179,35 @@ protected function removeDeletedImages(array $files)
foreach ($files as $filePath) {
$this->mediaDirectory->delete($catalogPath . '/' . $filePath);
}
return null;
}

/**
* Delete media attributes values for given images
*
* @param Product $product
* @param string[] $images
*/
private function deleteMediaAttributeValues(Product $product, array $images): void
{
if ($images) {
$values = $this->attributeValue->getValues(
ProductInterface::class,
$product->getData($this->metadata->getLinkField()),
$this->mediaConfig->getMediaAttributeCodes()
);
$valuesToDelete = [];
foreach ($values as $value) {
if (in_array($value['value'], $images, true)) {
$valuesToDelete[] = $value;
}
}
if ($valuesToDelete) {
$this->attributeValue->deleteValues(
ProductInterface::class,
$valuesToDelete
);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@
<element name="selectFromGalleryButton" type="button" selector="//*[@class='file-uploader-area']/label[text()='Select from Gallery']"/>
<element name="uploadImageFile" type="input" selector=".file-uploader-area>input"/>
<element name="imageFileName" type="text" selector=".file-uploader-filename"/>
<element name="imageFileMeta" type="text" selector=".file-uploader-meta"/>
<element name="removeImageButton" type="button" selector=".file-uploader-summary .action-remove"/>
<element name="AddCMSBlock" type="select" selector="//*[@name='landing_page']"/>
<element name="description" type="input" selector="//*[@name='description']"/>
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
<test name="AdminUpdateCategoryWithProductsDefaultSortingTest">
<annotations>
<features value="Catalog"/>
<stories value="Update categories"/>
<title value="Update category, sort products by default sorting"/>
<description value="Login as admin, update category and sort products"/>
<testCaseId value="MC-25667"/>
<severity value="CRITICAL"/>
<group value="catalog"/>
<group value="mtf_migrated"/>
</annotations>
<before>
<createData entity="defaultSimpleProduct" stepKey="simpleProduct" />
<createData entity="_defaultCategory" stepKey="createCategory"/>
<actionGroup ref="AdminLoginActionGroup" stepKey="loginToAdminPanel"/>
</before>
<after>
<deleteData createDataKey="createCategory" stepKey="deleteCategory"/>
<deleteData createDataKey="simpleProduct" stepKey="deleteSimpleProduct"/>
<actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/>
<magentoCron groups="index" stepKey="reindexInvalidatedIndices"/>
</after>

<!--Open Category Page-->
<actionGroup ref="GoToAdminCategoryPageByIdActionGroup" stepKey="goToAdminCategoryPage">
<argument name="id" value="$createCategory.id$"/>
</actionGroup>

<!--Update Product Display Setting-->
<waitForElementVisible selector="{{AdminCategoryDisplaySettingsSection.settingsHeader}}" stepKey="waitForDisplaySettingsSection"/>
<conditionalClick selector="{{AdminCategoryDisplaySettingsSection.settingsHeader}}" dependentSelector="{{AdminCategoryDisplaySettingsSection.displayMode}}" visible="false" stepKey="openDisplaySettingsSection"/>
<waitForElementVisible selector="{{CategoryDisplaySettingsSection.productListCheckBox}}" stepKey="waitForAvailableProductListCheckbox"/>
<click selector="{{CategoryDisplaySettingsSection.productListCheckBox}}" stepKey="enableTheAvailableProductList"/>
<selectOption selector="{{CategoryDisplaySettingsSection.productList}}" parameterArray="['Product Name', 'Price']" stepKey="selectPrice"/>
<waitForElementVisible selector="{{CategoryDisplaySettingsSection.defaultProductLisCheckBox}}" stepKey="waitForDefaultProductList"/>
<click selector="{{CategoryDisplaySettingsSection.defaultProductLisCheckBox}}" stepKey="enableTheDefaultProductList"/>
<selectOption selector="{{CategoryDisplaySettingsSection.defaultProductList}}" userInput="name" stepKey="selectProductName"/>

<!--Add Products in Category-->
<actionGroup ref="AdminCategoryAssignProductActionGroup" stepKey="assignSimpleProductToCategory">
<argument name="productSku" value="$simpleProduct.sku$"/>
</actionGroup>
<actionGroup ref="AdminSaveCategoryFormActionGroup" stepKey="saveCategory"/>

<!--Verify Category Title-->
<see selector="{{AdminCategoryContentSection.categoryPageTitle}}" userInput="{{_defaultCategory.name}}" stepKey="seeCategoryNamePageTitle" />

<!--Verify Category in store front page-->
<amOnPage url="{{StorefrontCategoryPage.url($createCategory.custom_attributes[url_key]$)}}" stepKey="openStorefrontCategoryPage"/>

<!--Verify Product in Category-->
<actionGroup ref="AssertStorefrontProductIsPresentOnCategoryPageActionGroup" stepKey="assertSimpleProductOnCategoryPage">
<argument name="productName" value="$simpleProduct.name$"/>
</actionGroup>

<!--Verify product name and sku on Store Front-->
<actionGroup ref="AssertProductNameAndSkuInStorefrontProductPageByCustomAttributeUrlKeyActionGroup" stepKey="assertProductOnStorefrontProductPage">
<argument name="product" value="$simpleProduct$"/>
</actionGroup>
</test>
</tests>

Original file line number Diff line number Diff line change
@@ -7,15 +7,18 @@
-->
<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
<test name="AdminUpdateCategoryWithProductsTest">
<test name="AdminUpdateCategoryWithProductsTest" deprecated="Use AdminUpdateCategoryWithProductsDefaultSortingTest instead">
<annotations>
<stories value="Update categories"/>
<title value="Update category, sort products by default sorting"/>
<title value="DEPRECATED. Update category, sort products by default sorting"/>
<description value="Login as admin, update category and sort products"/>
<testCaseId value="MC-6059"/>
<severity value="BLOCKER"/>
<group value="Catalog"/>
<group value="mtf_migrated"/>
<skip>
<issueId value="DEPRECATED">Use AdminUpdateCategoryWithProductsDefaultSortingTest instead</issueId>
</skip>
</annotations>
<before>
<actionGroup ref="AdminLoginActionGroup" stepKey="loginToAdminPanel"/>
Original file line number Diff line number Diff line change
@@ -188,12 +188,17 @@ define([
_addItem: function (event, imageData) {
var count = this.element.find(this.options.imageSelector).length,
element,
imgElement;
imgElement,
position = count + 1,
lastElement = this.element.find(this.options.imageSelector + ':last');

if (lastElement.length === 1) {
position = parseInt(lastElement.data('imageData').position || count, 10) + 1;
}
imageData = $.extend({
'file_id': imageData['value_id'] ? imageData['value_id'] : Math.random().toString(33).substr(2, 18),
'disabled': imageData.disabled ? imageData.disabled : 0,
'position': count + 1,
'position': position,
sizeLabel: bytesToSize(imageData.size)
}, imageData);

@@ -206,7 +211,7 @@ define([
if (count === 0) {
element.prependTo(this.element);
} else {
element.insertAfter(this.element.find(this.options.imageSelector + ':last'));
element.insertAfter(lastElement);
}

if (!this.options.initialized &&
Loading

0 comments on commit 173356c

Please sign in to comment.