Skip to content

Commit

Permalink
Merge branch '2.4-develop' of https://github.com/mage-os/mirror-magento2
Browse files Browse the repository at this point in the history
 into 2.4-develop
  • Loading branch information
mage-os-ci committed May 10, 2024
2 parents 717ebd2 + 7e0e558 commit e9cf9ee
Show file tree
Hide file tree
Showing 20 changed files with 751 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
<magentoCLI command="config:set checkout/options/enable_guest_checkout_login 1" stepKey="EnablingGuestCheckoutLogin"/>
</before>
<after>
<actionGroup ref="AdminOpenProductIndexPageActionGroup" stepKey="goToProductList"/>
<actionGroup ref="AdminClearGridFiltersActionGroup" stepKey="resetProductFilters"/>
<actionGroup ref="AdminLogoutActionGroup" stepKey="logoutOfAdmin"/>
<magentoCLI command="config:set checkout/options/enable_guest_checkout_login 0" stepKey="DisablingGuestCheckoutLogin"/>
</after>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?php
/************************************************************************
*
* Copyright 2024 Adobe
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe and its suppliers, if any. The intellectual
* and technical concepts contained herein are proprietary to Adobe
* and its suppliers and are protected by all applicable intellectual
* property laws, including trade secret and copyright laws.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe.
* ************************************************************************
*/
declare(strict_types=1);

namespace Magento\CatalogImportExport\Model\Import\Product;

use Magento\Catalog\Api\Data\ProductInterface;
use Magento\CatalogImportExport\Model\Import\Product;
use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
use Magento\Framework\EntityManager\MetadataPool;
use Magento\Framework\Exception\LocalizedException;

class UniqueAttributeValidator
{
/**
* @var array
*/
private array $cache = [];

/**
* @param MetadataPool $metadataPool
* @param SkuStorage $skuStorage
*/
public function __construct(
private readonly MetadataPool $metadataPool,
private readonly SkuStorage $skuStorage
) {
}

/**
* Check if provided value is unique for the attribute
*
* @param Product $context
* @param string $attributeCode
* @param string $sku
* @param string $value
* @return bool
* @throws \Exception
*/
public function isValid(Product $context, string $attributeCode, string $sku, string $value): bool
{
$cacheKey = strtolower($attributeCode);
if (!isset($this->cache[$cacheKey])) {
$this->cache[$cacheKey] = $this->load($context, $attributeCode);
}
$entityData = $this->skuStorage->get($sku);
$id = null;
if ($entityData !== null) {
$id = $entityData[$this->metadataPool->getMetadata(ProductInterface::class)->getLinkField()];
}
return !isset($this->cache[$cacheKey][$value]) || in_array($id, $this->cache[$cacheKey][$value]);
}

/**
* Load attribute values with corresponding entity ids
*
* @param Product $context
* @param string $attributeCode
* @return array
* @throws LocalizedException
*/
private function load(Product $context, string $attributeCode): array
{
/** @var AbstractAttribute $attributeObject */
$attributeObject = $context->retrieveAttributeByCode($attributeCode);
if ($attributeObject->isStatic()) {
return [];
}
$metadata = $this->metadataPool->getMetadata(ProductInterface::class);
$connection = $context->getConnection();
$idField = $metadata->getLinkField();
$select = $connection->select()
->from(
$attributeObject->getBackend()->getTable(),
['value', $idField]
)
->where(
'attribute_id = :attribute_id'
);
$result = [];
foreach ($connection->fetchAll($select, ['attribute_id' => $attributeObject->getId()]) as $row) {
$result[$row['value']][] = $row[$idField];
}
return $result;
}

/**
* Clear cached attribute values
*
* @return void
*/
public function clearCache(): void
{
$this->cache = [];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ class Validator extends AbstractValidator implements RowValidatorInterface
*/
protected $invalidAttribute;

/**
* @var UniqueAttributeValidator
*/
private $uniqueAttributeValidator;

/**
* @var TimezoneInterface
*/
Expand All @@ -60,16 +65,20 @@ class Validator extends AbstractValidator implements RowValidatorInterface
* @param StringUtils $string
* @param RowValidatorInterface[] $validators
* @param TimezoneInterface|null $localeDate
* @param UniqueAttributeValidator|null $uniqueAttributeValidator
*/
public function __construct(
\Magento\Framework\Stdlib\StringUtils $string,
$validators = [],
?TimezoneInterface $localeDate = null
?TimezoneInterface $localeDate = null,
?UniqueAttributeValidator $uniqueAttributeValidator = null
) {
$this->string = $string;
$this->validators = $validators;
$this->localeDate = $localeDate ?: ObjectManager::getInstance()
->get(TimezoneInterface::class);
$this->uniqueAttributeValidator = $uniqueAttributeValidator
?: ObjectManager::getInstance()->get(UniqueAttributeValidator::class);
}

/**
Expand Down Expand Up @@ -242,7 +251,14 @@ public function isAttributeValid($attrCode, array $attrParams, array $rowData)

if ($valid && !empty($attrParams['is_unique'])) {
if (isset($this->_uniqueAttributes[$attrCode][$rowData[$attrCode]])
&& ($this->_uniqueAttributes[$attrCode][$rowData[$attrCode]] != $rowData[Product::COL_SKU])) {
&& ($this->_uniqueAttributes[$attrCode][$rowData[$attrCode]] != $rowData[Product::COL_SKU])
|| !$this->uniqueAttributeValidator->isValid(
$this->context,
(string) $attrCode,
(string) $rowData[Product::COL_SKU],
(string) $rowData[$attrCode]
)
) {
$this->_addMessages([RowValidatorInterface::ERROR_DUPLICATE_UNIQUE_ATTRIBUTE]);
return false;
}
Expand Down Expand Up @@ -452,11 +468,23 @@ private function isCategoriesValid(string|array $value) : bool
*/
public function init($context)
{
$this->_uniqueAttributes = [];
$this->uniqueAttributeValidator->clearCache();
$this->context = $context;
foreach ($this->validators as $validator) {
$validator->init($context);
}

return $this;
}

/**
* @inheritdoc
*/
public function _resetState(): void
{
$this->_uniqueAttributes = [];
$this->uniqueAttributeValidator->clearCache();
parent::_resetState();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

use Magento\CatalogImportExport\Model\Import\Product;
use Magento\CatalogImportExport\Model\Import\Product\Type\Simple;
use Magento\CatalogImportExport\Model\Import\Product\UniqueAttributeValidator;
use Magento\CatalogImportExport\Model\Import\Product\Validator;
use Magento\CatalogImportExport\Model\Import\Product\Validator\Media;
use Magento\CatalogImportExport\Model\Import\Product\Validator\Website;
Expand Down Expand Up @@ -41,6 +42,11 @@ class ValidatorTest extends TestCase
/** @var Validator\Website|MockObject */
protected $validatorTwo;

/**
* @var UniqueAttributeValidator|MockObject
*/
private $uniqueAttributeValidator;

protected function setUp(): void
{
$entityTypeModel = $this->createPartialMock(
Expand All @@ -63,6 +69,7 @@ protected function setUp(): void
Website::class,
['init', 'isValid', 'getMessages']
);
$this->uniqueAttributeValidator = $this->createMock(UniqueAttributeValidator::class);

$this->validators = [$this->validatorOne, $this->validatorTwo];
$timezone = $this->createMock(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::class);
Expand All @@ -77,7 +84,8 @@ function ($date = null) {
$this->validator = new Validator(
new StringUtils(),
$this->validators,
$timezone
$timezone,
$this->uniqueAttributeValidator
);
$this->validator->init($this->context);
}
Expand All @@ -88,10 +96,18 @@ function ($date = null) {
* @param array $rowData
* @param bool $isValid
* @param string $attrCode
* @param bool $uniqueAttributeValidatorResult
* @dataProvider attributeValidationProvider
*/
public function testAttributeValidation($behavior, $attrParams, $rowData, $isValid, $attrCode = 'attribute_code')
{
public function testAttributeValidation(
string $behavior,
array $attrParams,
array $rowData,
bool $isValid,
string $attrCode = 'attribute_code',
bool $uniqueAttributeValidatorResult = true
) {
$this->uniqueAttributeValidator->method('isValid')->willReturn($uniqueAttributeValidatorResult);
$this->context->method('getMultipleValueSeparator')->willReturn(Product::PSEUDO_MULTI_LINE_SEPARATOR);
$this->context->expects($this->any())->method('getBehavior')->willReturn($behavior);
$result = $this->validator->isAttributeValid(
Expand Down Expand Up @@ -226,6 +242,14 @@ public function attributeValidationProvider()
['product_type' => 'any', 'unique_attribute' => 'unique-value', Product::COL_SKU => 'sku-0'],
true,
'unique_attribute'
],
[
Import::BEHAVIOR_APPEND,
['is_required' => true, 'type' => 'varchar', 'is_unique' => true],
['product_type' => 'any', 'unique_attribute' => 'unique-value', Product::COL_SKU => 'sku-0'],
false,
'unique_attribute',
false
]
];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@
</before>

<after>
<actionGroup ref="AdminOpenProductIndexPageActionGroup" stepKey="goToProductList"/>
<actionGroup ref="AdminClearGridFiltersActionGroup" stepKey="resetProductFilters"/>
<actionGroup ref="AdminLogoutActionGroup" stepKey="adminLogout"/>
<deleteData createDataKey="createConfigChildProduct1" stepKey="deleteConfigChildProduct1"/>
<deleteData createDataKey="createConfigChildProduct2" stepKey="deleteConfigChildProduct2"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@
</before>

<after>
<actionGroup ref="AdminOpenProductIndexPageActionGroup" stepKey="goToProductList"/>
<actionGroup ref="AdminClearGridFiltersActionGroup" stepKey="resetProductFilters"/>
<actionGroup ref="AdminLogoutActionGroup" stepKey="adminLogout"/>
<deleteData createDataKey="createConfigChildProduct1" stepKey="deleteConfigChildProduct1"/>
<deleteData createDataKey="createConfigChildProduct2" stepKey="deleteConfigChildProduct2"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@
</before>

<after>
<actionGroup ref="AdminOpenProductIndexPageActionGroup" stepKey="goToProductList"/>
<actionGroup ref="AdminClearGridFiltersActionGroup" stepKey="resetProductFilters"/>
<actionGroup ref="AdminLogoutActionGroup" stepKey="adminLogout"/>
<deleteData createDataKey="createConfigProduct" stepKey="deleteConfigProduct"/>
<deleteData createDataKey="createConfigChildProduct1" stepKey="deleteConfigChildProduct1"/>
Expand Down
10 changes: 7 additions & 3 deletions app/code/Magento/Customer/Model/Customer.php
Original file line number Diff line number Diff line change
Expand Up @@ -342,21 +342,25 @@ public function _construct()
public function getDataModel()
{
$customerData = $this->getData();
$addressesData = [];
$regularAddresses = $defaultAddresses = [];
/** @var \Magento\Customer\Model\Address $address */
foreach ($this->getAddresses() as $address) {
if (!isset($this->storedAddress[$address->getId()])) {
$this->storedAddress[$address->getId()] = $address->getDataModel();
}
$addressesData[] = $this->storedAddress[$address->getId()];
if ($this->storedAddress[$address->getId()]->isDefaultShipping()) {
$defaultAddresses[] = $this->storedAddress[$address->getId()];
} else {
$regularAddresses[] = $this->storedAddress[$address->getId()];
}
}
$customerDataObject = $this->customerDataFactory->create();
$this->dataObjectHelper->populateWithArray(
$customerDataObject,
$customerData,
\Magento\Customer\Api\Data\CustomerInterface::class
);
$customerDataObject->setAddresses($addressesData)
$customerDataObject->setAddresses(array_merge($defaultAddresses, $regularAddresses))
->setId($this->getId());
return $customerDataObject;
}
Expand Down
18 changes: 14 additions & 4 deletions app/code/Magento/Customer/Test/Unit/Model/CustomerTest.php
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
<?php declare(strict_types=1);
/**
* Unit test for customer service layer \Magento\Customer\Model\Customer
/************************************************************************
*
* Copyright 2023 Adobe
* All Rights Reserved.
*
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
* NOTICE: All information contained herein is, and remains
* the property of Adobe and its suppliers, if any. The intellectual
* and technical concepts contained herein are proprietary to Adobe
* and its suppliers and are protected by all applicable intellectual
* property laws, including trade secret and copyright laws.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe.
* ************************************************************************
*/

/**
Expand Down Expand Up @@ -387,6 +396,7 @@ public function testGetDataModel()
$this->_model->setEntityId($customerId);
$this->_model->setId($customerId);
$addressDataModel = $this->getMockForAbstractClass(AddressInterface::class);
$addressDataModel->expects($this->exactly(4))->method('isDefaultShipping')->willReturn(true);
$address = $this->getMockBuilder(AddressModel::class)
->disableOriginalConstructor()
->setMethods(['setCustomer', 'getDataModel'])
Expand Down
Loading

0 comments on commit e9cf9ee

Please sign in to comment.