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

Fixed issue 27051: Saving an attribute with backend_type static #27369

Merged
merged 11 commits into from
Jun 25, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,10 @@ public function execute()
unset($data['apply_to']);
}

if ($model->getBackendType() == 'static' && !$model->getIsUserDefined()) {
$data['frontend_class'] = $model->getFrontendClass();
}

$model->addData($data);

if (!$attributeId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,116 +3,142 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\Catalog\Test\Unit\Controller\Adminhtml\Product\Attribute;

use Magento\Backend\Model\Session;
use Magento\Backend\Model\View\Result\Redirect as ResultRedirect;
use Magento\Catalog\Api\Data\ProductAttributeInterface;
use Magento\Catalog\Controller\Adminhtml\Product\Attribute\Save;
use Magento\Eav\Model\Validator\Attribute\Code as AttributeCodeValidator;
use Magento\Framework\Serialize\Serializer\FormData;
use Magento\Catalog\Test\Unit\Controller\Adminhtml\Product\AttributeTest;
use Magento\Catalog\Model\Product\AttributeSet\BuildFactory;
use Magento\Catalog\Helper\Product as ProductHelper;
use Magento\Catalog\Model\Product\Attribute\Frontend\Inputtype\Presentation;
use Magento\Catalog\Model\Product\AttributeSet\Build;
use Magento\Catalog\Model\Product\AttributeSet\BuildFactory;
use Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory;
use Magento\Catalog\Test\Unit\Controller\Adminhtml\Product\AttributeTest;
use Magento\Eav\Api\Data\AttributeSetInterface;
use Magento\Eav\Model\Adminhtml\System\Config\Source\Inputtype\Validator as InputTypeValidator;
use Magento\Eav\Model\Adminhtml\System\Config\Source\Inputtype\ValidatorFactory;
use Magento\Eav\Model\ResourceModel\Entity\Attribute\Group\CollectionFactory;
use Magento\Eav\Model\Validator\Attribute\Code as AttributeCodeValidator;
use Magento\Framework\Controller\ResultFactory;
use Magento\Framework\Exception\NotFoundException;
use Magento\Framework\Filter\FilterManager;
use Magento\Catalog\Helper\Product as ProductHelper;
use Magento\Framework\Serialize\Serializer\FormData;
use Magento\Framework\View\Element\Messages;
use Magento\Framework\View\LayoutFactory;
use Magento\Backend\Model\View\Result\Redirect as ResultRedirect;
use Magento\Eav\Model\Adminhtml\System\Config\Source\Inputtype\Validator as InputTypeValidator;
use Magento\Framework\View\LayoutInterface;
use PHPUnit\Framework\MockObject\MockObject;

/**
* Test product attribute controller
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.TooManyFields)
*/
class SaveTest extends AttributeTest
{
/**
* @var BuildFactory|\PHPUnit_Framework_MockObject_MockObject
* @var BuildFactory|MockObject
*/
protected $buildFactoryMock;

/**
* @var FilterManager|\PHPUnit_Framework_MockObject_MockObject
* @var FilterManager|MockObject
*/
protected $filterManagerMock;

/**
* @var ProductHelper|\PHPUnit_Framework_MockObject_MockObject
* @var ProductHelper|MockObject
*/
protected $productHelperMock;

/**
* @var AttributeFactory|\PHPUnit_Framework_MockObject_MockObject
* @var AttributeFactory|MockObject
*/
protected $attributeFactoryMock;

/**
* @var ValidatorFactory|\PHPUnit_Framework_MockObject_MockObject
* @var ValidatorFactory|MockObject
*/
protected $validatorFactoryMock;

/**
* @var CollectionFactory|\PHPUnit_Framework_MockObject_MockObject
* @var CollectionFactory|MockObject
*/
protected $groupCollectionFactoryMock;

/**
* @var LayoutFactory|\PHPUnit_Framework_MockObject_MockObject
* @var LayoutFactory|MockObject
*/
protected $layoutFactoryMock;

/**
* @var ResultRedirect|\PHPUnit_Framework_MockObject_MockObject
* @var ResultRedirect|MockObject
*/
protected $redirectMock;

/**
* @var AttributeSet|\PHPUnit_Framework_MockObject_MockObject
* @var AttributeSet|MockObject
*/
protected $attributeSetMock;

/**
* @var Build|\PHPUnit_Framework_MockObject_MockObject
* @var Build|MockObject
*/
protected $builderMock;

/**
* @var InputTypeValidator|\PHPUnit_Framework_MockObject_MockObject
* @var InputTypeValidator|MockObject
*/
protected $inputTypeValidatorMock;

/**
* @var FormData|\PHPUnit_Framework_MockObject_MockObject
* @var FormData|MockObject
*/
protected $formDataSerializerMock;

/**
* @var ProductAttributeInterface|MockObject
*/
protected $productAttributeMock;

/**
* @var Presentation|MockObject
*/
private $formDataSerializerMock;
protected $presentationMock;

/**
* @var ProductAttributeInterface|\PHPUnit_Framework_MockObject_MockObject
* @var Session|MockObject
*/
private $productAttributeMock;
protected $sessionMock;

/**
* @var AttributeCodeValidator|\PHPUnit_Framework_MockObject_MockObject
* @var AttributeCodeValidator|MockObject
*/
private $attributeCodeValidatorMock;
protected $attributeCodeValidatorMock;

protected function setUp()
/**
* @inheritDoc
*/
public function setUp(): void
{
parent::setUp();
$this->filterManagerMock = $this->createMock(FilterManager::class);
$this->productHelperMock = $this->createMock(ProductHelper::class);
$this->attributeSetMock = $this->createMock(AttributeSetInterface::class);
$this->builderMock = $this->createMock(Build::class);
$this->inputTypeValidatorMock = $this->createMock(InputTypeValidator::class);
$this->formDataSerializerMock = $this->createMock(FormData::class);
$this->attributeCodeValidatorMock = $this->createMock(AttributeCodeValidator::class);
$this->presentationMock = $this->createMock(Presentation::class);
$this->sessionMock = $this->createMock(Session::class);
$this->layoutFactoryMock = $this->createMock(LayoutFactory::class);
$this->buildFactoryMock = $this->getMockBuilder(BuildFactory::class)
->setMethods(['create'])
->disableOriginalConstructor()
->getMock();
$this->filterManagerMock = $this->getMockBuilder(FilterManager::class)
->disableOriginalConstructor()
->getMock();
$this->productHelperMock = $this->getMockBuilder(ProductHelper::class)
->disableOriginalConstructor()
->getMock();
$this->attributeFactoryMock = $this->getMockBuilder(AttributeFactory::class)
->setMethods(['create'])
->disableOriginalConstructor()
Expand All @@ -125,32 +151,23 @@ protected function setUp()
->setMethods(['create'])
->disableOriginalConstructor()
->getMock();
$this->layoutFactoryMock = $this->getMockBuilder(LayoutFactory::class)
->disableOriginalConstructor()
->getMock();
$this->redirectMock = $this->getMockBuilder(ResultRedirect::class)
->setMethods(['setData', 'setPath'])
->disableOriginalConstructor()
->getMock();
$this->attributeSetMock = $this->getMockBuilder(AttributeSetInterface::class)
->disableOriginalConstructor()
->getMock();
$this->builderMock = $this->getMockBuilder(Build::class)
->disableOriginalConstructor()
->getMock();
$this->inputTypeValidatorMock = $this->getMockBuilder(InputTypeValidator::class)
->disableOriginalConstructor()
->getMock();
$this->formDataSerializerMock = $this->getMockBuilder(FormData::class)
->disableOriginalConstructor()
->getMock();
$this->attributeCodeValidatorMock = $this->getMockBuilder(AttributeCodeValidator::class)
->disableOriginalConstructor()
->getMock();
$this->productAttributeMock = $this->getMockBuilder(ProductAttributeInterface::class)
->setMethods(['getId', 'get'])
->getMockForAbstractClass();

->setMethods(
[
'getId',
'get',
'getBackendTypeByInput',
'getDefaultValueByInput',
'getBackendType',
'getFrontendClass',
'addData',
'save'
]
)->getMockForAbstractClass();
$this->buildFactoryMock->expects($this->any())
->method('create')
->willReturn($this->builderMock);
Expand All @@ -163,7 +180,7 @@ protected function setUp()
}

/**
* {@inheritdoc}
* @inheritdoc
*/
protected function getModel()
{
Expand All @@ -180,11 +197,17 @@ protected function getModel()
'groupCollectionFactory' => $this->groupCollectionFactoryMock,
'layoutFactory' => $this->layoutFactoryMock,
'formDataSerializer' => $this->formDataSerializerMock,
'attributeCodeValidator' => $this->attributeCodeValidatorMock
'attributeCodeValidator' => $this->attributeCodeValidatorMock,
'presentation' => $this->presentationMock,
'_session' => $this->sessionMock
]);
}

public function testExecuteWithEmptyData()
/**
* @return void
* @throws NotFoundException
*/
public function testExecuteWithEmptyData(): void
{
$this->requestMock->expects($this->any())
->method('getParam')
Expand All @@ -210,7 +233,76 @@ public function testExecuteWithEmptyData()
$this->assertInstanceOf(ResultRedirect::class, $this->getModel()->execute());
}

public function testExecute()
/**
* @return void
* @throws NotFoundException
*/
public function testExecuteSaveFrontendClass(): void
{
$data = [
'frontend_input' => 'test_frontend_input',
];

$this->requestMock->expects($this->any())
->method('getParam')
->willReturnMap([
['isAjax', null, null],
['serialized_options', '[]', ''],
['set', null, 1],
['attribute_code', null, 'test_attribute_code'],
]);
$this->formDataSerializerMock
->expects($this->once())
->method('unserialize')
->with('')
->willReturn([]);
$this->requestMock->expects($this->once())
->method('getPostValue')
->willReturn($data);
$this->inputTypeValidatorMock->expects($this->any())
->method('isValid')
->with($data['frontend_input'])
->willReturn(true);
$this->presentationMock->expects($this->once())
->method('convertPresentationDataToInputType')
->willReturn($data);
$this->productHelperMock->expects($this->once())
->method('getAttributeSourceModelByInputType')
->with($data['frontend_input'])
->willReturn(null);
$this->productHelperMock->expects($this->once())
->method('getAttributeBackendModelByInputType')
->with($data['frontend_input'])
->willReturn(null);
$this->productAttributeMock->expects($this->once())
->method('getBackendTypeByInput')
->with($data['frontend_input'])
->willReturnSelf('test_backend_type');
$this->productAttributeMock->expects($this->once())
->method('getDefaultValueByInput')
->with($data['frontend_input'])
->willReturn(null);
$this->productAttributeMock->expects($this->once())
->method('getBackendType')
->willReturn('static');
$this->productAttributeMock->expects($this->once())
->method('getFrontendClass')
->willReturn('static');
$this->resultFactoryMock->expects($this->any())
->method('create')
->willReturn($this->redirectMock);
$this->redirectMock->expects($this->any())
->method('setPath')
->willReturnSelf();

$this->assertInstanceOf(ResultRedirect::class, $this->getModel()->execute());
}

/**
* @return void
* @throws NotFoundException
*/
public function testExecute(): void
{
$data = [
'new_attribute_set_name' => 'Test attribute set name',
Expand Down Expand Up @@ -273,9 +365,10 @@ public function testExecute()
}

/**
* @throws \Magento\Framework\Exception\NotFoundException
* @return void
* @throws NotFoundException
*/
public function testExecuteWithOptionsDataError()
public function testExecuteWithOptionsDataError(): void
{
$serializedOptions = '{"key":"value"}';
$message = "The attribute couldn't be saved due to an error. Verify your information and try again. "
Expand Down Expand Up @@ -305,10 +398,10 @@ public function testExecuteWithOptionsDataError()
* @param string $path
* @param array $params
* @param array $response
* @return mixed
* @return void
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
private function addReturnResultConditions(string $path = '', array $params = [], array $response = [])
private function addReturnResultConditions(string $path = '', array $params = [], array $response = []): void
{
$layoutMock = $this->getMockBuilder(LayoutInterface::class)
->setMethods(['initMessages', 'getMessagesBlock'])
Expand Down