Skip to content

Commit

Permalink
Merge branch '2.4-develop' into fix-CategoryWithOverriddenUrlKey
Browse files Browse the repository at this point in the history
  • Loading branch information
engcom-Echo authored Sep 17, 2020
2 parents ec3e6da + 57c527e commit 7a6a740
Show file tree
Hide file tree
Showing 44 changed files with 1,731 additions and 127 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
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
Expand Up @@ -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;
}
}
Expand Down
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
Expand Up @@ -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
*
Expand All @@ -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;
Expand All @@ -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
Expand All @@ -48,8 +102,8 @@ protected function processDeletedImages($product, array &$images)
}
}

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

$this->removeDeletedImages($filesToDelete);
}

Expand Down Expand Up @@ -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);
Expand All @@ -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
@@ -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
Expand Up @@ -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"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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 &&
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\CatalogInventory\Model\ResourceModel;

use Magento\CatalogInventory\Api\Data\StockStatusInterface;
use Magento\CatalogInventory\Api\StockConfigurationInterface;
use Magento\CatalogInventory\Model\Stock;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\DB\Select;

/**
* Generic in-stock status filter
*/
class StockStatusFilter implements StockStatusFilterInterface
{
private const TABLE_NAME = 'cataloginventory_stock_status';
/**
* @var ResourceConnection
*/
private $resource;

/**
* @var StockConfigurationInterface
*/
private $stockConfiguration;

/**
* @param ResourceConnection $resource
* @param StockConfigurationInterface $stockConfiguration
*/
public function __construct(
ResourceConnection $resource,
StockConfigurationInterface $stockConfiguration
) {
$this->resource = $resource;
$this->stockConfiguration = $stockConfiguration;
}

/**
* @inheritDoc
*/
public function execute(
Select $select,
string $productTableAlias,
string $stockStatusTableAlias = self::TABLE_ALIAS,
?int $websiteId = null
): Select {
$stockStatusTable = $this->resource->getTableName(self::TABLE_NAME);
$joinCondition = [
"{$stockStatusTableAlias}.product_id = {$productTableAlias}.entity_id",
$select->getConnection()->quoteInto(
"{$stockStatusTableAlias}.website_id = ?",
$this->stockConfiguration->getDefaultScopeId()
),
$select->getConnection()->quoteInto(
"{$stockStatusTableAlias}.stock_id = ?",
Stock::DEFAULT_STOCK_ID
)
];
$select->join(
[$stockStatusTableAlias => $stockStatusTable],
implode(' AND ', $joinCondition),
[]
);
$select->where("{$stockStatusTableAlias}.stock_status = ?", StockStatusInterface::STATUS_IN_STOCK);

return $select;
}
}
Loading

0 comments on commit 7a6a740

Please sign in to comment.