Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rest api multiselect attribute bc break between 2.1.8 and 2.3.0 #21901

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions app/code/Magento/Eav/Model/TypeLocator/SimpleType.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class SimpleType implements CustomAttributeTypeLocatorInterface
* Initialize dependencies.
*
* @param AttributeRepositoryInterface $attributeRepository
* @param ServiceTypeListInterface $serviceTypeList
*/
public function __construct(
AttributeRepositoryInterface $attributeRepository,
Expand All @@ -41,7 +42,7 @@ public function __construct(
}

/**
* {@inheritdoc}
* @inheritdoc
*/
public function getType($attributeCode, $entityType)
{
Expand All @@ -50,6 +51,11 @@ public function getType($attributeCode, $entityType)
} catch (NoSuchEntityException $exception) {
return TypeProcessor::NORMALIZED_ANY_TYPE;
}

if ($attribute->getFrontendInput() === 'multiselect') {
return TypeProcessor::NORMALIZED_ANY_TYPE;
}

$backendType = $attribute->getBackendType();
$backendTypeMap = [
'static' => TypeProcessor::NORMALIZED_ANY_TYPE,
Expand All @@ -64,7 +70,7 @@ public function getType($attributeCode, $entityType)
}

/**
* {@inheritDoc}
* @inheritDoc
*/
public function getAllServiceDataInterfaces()
{
Expand Down
155 changes: 155 additions & 0 deletions app/code/Magento/Eav/Test/Unit/Model/TypeLocator/SimpleTypeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Eav\Test\Unit\Model\TypeLocator;

use Magento\Eav\Model\TypeLocator\SimpleType;
use Magento\Eav\Model\AttributeRepository;
use Magento\Framework\Webapi\CustomAttribute\ServiceTypeListInterface;
use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
use Magento\Framework\Reflection\TypeProcessor;
use Magento\Framework\Exception\NoSuchEntityException;

/**
* Class SimpleTypeTest
*
* @package Magento\Eav\Test\Unit\Model\TypeLocator
*/
class SimpleTypeTest extends \PHPUnit\Framework\TestCase
{
/**
* Test testGetType method
* @return void
*/
public function testGetTypeWithNonexistentAttribute()
{
$getException = new NoSuchEntityException();
$expected = TypeProcessor::NORMALIZED_ANY_TYPE;

/** @var AttributeRepository|\PHPUnit_Framework_MockObject_MockObject $attributeRepositoryMock */
$attributeRepositoryMock = $this->createMock(AttributeRepository::class);
$attributeRepositoryMock->expects($this->any())
->method('get')
->willThrowException($getException);

/** @var ServiceTypeListInterface|\PHPUnit_Framework_MockObject_MockObject $serviceTypeListMock */
$serviceTypeListMock = $this->createMock(ServiceTypeListInterface::class);

/** @var SimpleType|\PHPUnit_Framework_MockObject_MockObject $simpleType */
$simpleType = new SimpleType(
$attributeRepositoryMock,
$serviceTypeListMock
);

$this->assertSame($expected, $simpleType->getType('testAttributeCode', 'testEntityType'));
}

/**
* Test testGetType method
* @return void
*/
public function testGetTypeWithMultiselectFrontendInput()
{
$getFrontendInputReturn = 'multiselect';
$expected = TypeProcessor::NORMALIZED_ANY_TYPE;

/** @var Attribute|\PHPUnit_Framework_MockObject_MockObject $attributeMock */
$attributeMock = $this->createMock(Attribute::class);
$attributeMock->expects($this->any())
->method('getFrontendInput')
->willReturn($getFrontendInputReturn);

/** @var AttributeRepository|\PHPUnit_Framework_MockObject_MockObject $attributeRepositoryMock */
$attributeRepositoryMock = $this->createMock(AttributeRepository::class);
$attributeRepositoryMock->expects($this->any())
->method('get')
->willReturn($attributeMock);

/** @var ServiceTypeListInterface|\PHPUnit_Framework_MockObject_MockObject $serviceTypeListMock */
$serviceTypeListMock = $this->createMock(ServiceTypeListInterface::class);

/** @var SimpleType|\PHPUnit_Framework_MockObject_MockObject $simpleType */
$simpleType = new SimpleType(
$attributeRepositoryMock,
$serviceTypeListMock
);

$this->assertSame($expected, $simpleType->getType('testAttributeCode', 'testEntityType'));
}

/**
* Test testGetType method
* @return void
*/
public function testGetTypeWithBackendTypeInMap()
{
$getFrontendInputReturn = 'textarea';
$getBackendTypeReturn = 'text';
$expected = TypeProcessor::NORMALIZED_STRING_TYPE;

/** @var Attribute|\PHPUnit_Framework_MockObject_MockObject $attributeMock */
$attributeMock = $this->createMock(Attribute::class);
$attributeMock->expects($this->any())
->method('getFrontendInput')
->willReturn($getFrontendInputReturn);
$attributeMock->expects($this->any())
->method('getBackendType')
->willReturn($getBackendTypeReturn);

/** @var AttributeRepository|\PHPUnit_Framework_MockObject_MockObject $attributeRepositoryMock */
$attributeRepositoryMock = $this->createMock(AttributeRepository::class);
$attributeRepositoryMock->expects($this->any())
->method('get')
->willReturn($attributeMock);

/** @var ServiceTypeListInterface|\PHPUnit_Framework_MockObject_MockObject $serviceTypeListMock */
$serviceTypeListMock = $this->createMock(ServiceTypeListInterface::class);

/** @var SimpleType|\PHPUnit_Framework_MockObject_MockObject $simpleType */
$simpleType = new SimpleType(
$attributeRepositoryMock,
$serviceTypeListMock
);

$this->assertSame($expected, $simpleType->getType('testAttributeCode', 'testEntityType'));
}

/**
* Test testGetType method
* @return void
*/
public function testGetTypeWithBackendTypeNotInMap()
{
$getFrontendInputReturn = 'textarea';
$getBackendTypeReturn = 'testBackendTypeNotInMap';
$expected = TypeProcessor::NORMALIZED_ANY_TYPE;

/** @var Attribute|\PHPUnit_Framework_MockObject_MockObject $attributeMock */
$attributeMock = $this->createMock(Attribute::class);
$attributeMock->expects($this->any())
->method('getFrontendInput')
->willReturn($getFrontendInputReturn);
$attributeMock->expects($this->any())
->method('getBackendType')
->willReturn($getBackendTypeReturn);

/** @var AttributeRepository|\PHPUnit_Framework_MockObject_MockObject $attributeRepositoryMock */
$attributeRepositoryMock = $this->createMock(AttributeRepository::class);
$attributeRepositoryMock->expects($this->any())
->method('get')
->willReturn($attributeMock);

/** @var ServiceTypeListInterface|\PHPUnit_Framework_MockObject_MockObject $serviceTypeListMock */
$serviceTypeListMock = $this->createMock(ServiceTypeListInterface::class);

/** @var SimpleType|\PHPUnit_Framework_MockObject_MockObject $simpleType */
$simpleType = new SimpleType(
$attributeRepositoryMock,
$serviceTypeListMock
);

$this->assertSame($expected, $simpleType->getType('testAttributeCode', 'testEntityType'));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,7 @@ public function testProductOptions()
public function testProductWithMediaGallery()
{
$testImagePath = __DIR__ . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'test_image.jpg';
// phpcs:ignore Magento2.Functions.DiscouragedFunction
$encodedImage = base64_encode(file_get_contents($testImagePath));
//create a product with media gallery
$filename1 = 'tiny1' . time() . '.jpg';
Expand Down Expand Up @@ -787,7 +788,9 @@ public function testUpdateWithExtensionAttributes(): void
protected function updateProduct($product)
{
if (isset($product['custom_attributes'])) {
for ($i=0; $i<sizeof($product['custom_attributes']); $i++) {
// phpcs:ignore Magento2.Functions.DiscouragedFunction
$size = sizeof($product['custom_attributes']);
for ($i=0; $i < $size; $i++) {
if ($product['custom_attributes'][$i]['attribute_code'] == 'category_ids'
&& !is_array($product['custom_attributes'][$i]['value'])
) {
Expand Down Expand Up @@ -1208,7 +1211,9 @@ protected function getSimpleProductData($productData = [])
protected function saveProduct($product, $storeCode = null)
{
if (isset($product['custom_attributes'])) {
for ($i=0; $i<sizeof($product['custom_attributes']); $i++) {
// phpcs:ignore Magento2.Functions.DiscouragedFunction
$size = sizeof($product['custom_attributes']);
for ($i=0; $i< $size; $i++) {
if ($product['custom_attributes'][$i]['attribute_code'] == 'category_ids'
&& !is_array($product['custom_attributes'][$i]['value'])
) {
Expand Down Expand Up @@ -1561,40 +1566,94 @@ public function testUpdateStatus()
* Test saving product with custom attribute of multiselect type
*
* 1. Create multi-select attribute
* 2. Create product and set 2 options out of 3 to multi-select attribute
* 3. Verify that 2 options are selected
* 4. Unselect all options
* 5. Verify that non options are selected
* 2. Create product
* 3. Set 2 options out of 3 to multi-select attribute in string format
* 4. Verify that 2 options are selected
*
* @magentoApiDataFixture Magento/Catalog/_files/multiselect_attribute.php
*/
public function testUpdateMultiselectAttributes()
public function testUpdateMultiselectAttributesWithStringValue()
{
$multiselectAttributeCode = 'multiselect_attribute';
$multiselectOptions = $this->getAttributeOptions($multiselectAttributeCode);
$option1 = $multiselectOptions[1]['value'];
$option2 = $multiselectOptions[2]['value'];
$option1Value = $multiselectOptions[1]['value'];
$option2Value = $multiselectOptions[2]['value'];

$productData = $this->getSimpleProductData();

$multiselectValue = "{$option1Value},{$option2Value}";
$productData['custom_attributes'] = [
['attribute_code' => $multiselectAttributeCode, 'value' => $multiselectValue]
];
$this->saveProduct($productData, 'all');

$expectedMultiselectValue = "{$option1Value},{$option2Value}";
$this->assertMultiselectValue(
$productData[ProductInterface::SKU],
$multiselectAttributeCode,
$expectedMultiselectValue
);
}

/**
* Test saving product with custom attribute of multiselect type
*
* 1. Create multi-select attribute
* 2. Create product
* 3. Set 2 options out of 3 to multi-select attribute in array format
* 4. Verify that 2 options are selected
*
* @magentoApiDataFixture Magento/Catalog/_files/multiselect_attribute.php
*/
public function testUpdateMultiselectAttributesWithArrayValue()
{
$multiselectAttributeCode = 'multiselect_attribute';
$multiselectOptions = $this->getAttributeOptions($multiselectAttributeCode);
$option1Value = $multiselectOptions[1]['value'];
$option2Value = $multiselectOptions[2]['value'];

$productData = $this->getSimpleProductData();

$productData['custom_attributes'] = [
['attribute_code' => $multiselectAttributeCode, 'value' => "{$option1},{$option2}"]
['attribute_code' => $multiselectAttributeCode, 'value' => [$option1Value, $option2Value]]
];
$this->saveProduct($productData, 'all');

$expectedMultiselectValue = "{$option1Value},{$option2Value}";
$this->assertMultiselectValue(
$productData[ProductInterface::SKU],
$multiselectAttributeCode,
"{$option1},{$option2}"
$expectedMultiselectValue
);
}

/**
* Test saving product with custom attribute of multiselect type
*
* 1. Create multi-select attribute
* 2. Create product
* 3. Unselect all options
* 4. Verify that non options are selected
*
* @magentoApiDataFixture Magento/Catalog/_files/multiselect_attribute.php
*/
public function testUpdateMultiselectAttributesWithEmptyValue()
{
$multiselectAttributeCode = 'multiselect_attribute';

$productData = $this->getSimpleProductData();

$multiselectValue = "";
$productData['custom_attributes'] = [
['attribute_code' => $multiselectAttributeCode, 'value' => ""]
['attribute_code' => $multiselectAttributeCode, 'value' => $multiselectValue]
];
$this->saveProduct($productData, 'all');

$expectedMultiselectValue = "";
$this->assertMultiselectValue(
$productData[ProductInterface::SKU],
$multiselectAttributeCode,
""
$expectedMultiselectValue
);
}

Expand Down