diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Edit/Tab/Advanced.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Edit/Tab/Advanced.php index 35f30ed8d3d6b..da044b309f6c7 100644 --- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Edit/Tab/Advanced.php +++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Edit/Tab/Advanced.php @@ -6,13 +6,18 @@ namespace Magento\Catalog\Block\Adminhtml\Product\Attribute\Edit\Tab; +use Magento\Backend\Block\Template\Context; use Magento\Backend\Block\Widget\Form\Generic; +use Magento\Catalog\Model\Attribute\Source\ApplyTo; use Magento\Catalog\Model\ResourceModel\Eav\Attribute; use Magento\Config\Model\Config\Source\Yesno; use Magento\Eav\Block\Adminhtml\Attribute\PropertyLocker; use Magento\Eav\Helper\Data; +use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface; use Magento\Framework\App\ObjectManager; +use Magento\Framework\Data\FormFactory; use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Registry; use Magento\Framework\Stdlib\DateTime; /** @@ -25,11 +30,10 @@ class Advanced extends Generic { /** - * Eav data * * @var Data */ - protected $_eavData = null; + protected $_eavData; /** * @var Yesno @@ -47,27 +51,38 @@ class Advanced extends Generic private $propertyLocker; /** - * @param \Magento\Backend\Block\Template\Context $context - * @param \Magento\Framework\Registry $registry - * @param \Magento\Framework\Data\FormFactory $formFactory + * @var ApplyTo + */ + private $applyTo; + + /** + * @param Context $context + * @param Registry $registry + * @param FormFactory $formFactory * @param Yesno $yesNo * @param Data $eavData * @param array $disableScopeChangeList * @param array $data + * @param PropertyLocker|null $propertyLocker + * @param ApplyTo|null $applyTo */ public function __construct( - \Magento\Backend\Block\Template\Context $context, - \Magento\Framework\Registry $registry, - \Magento\Framework\Data\FormFactory $formFactory, + Context $context, + Registry $registry, + FormFactory $formFactory, Yesno $yesNo, Data $eavData, array $disableScopeChangeList = [], - array $data = [] + array $data = [], + ?PropertyLocker $propertyLocker = null, + ?ApplyTo $applyTo = null ) { $this->_yesNo = $yesNo; $this->_eavData = $eavData; $this->disableScopeChangeList = $disableScopeChangeList; parent::__construct($context, $registry, $formFactory, $data); + $this->propertyLocker = $propertyLocker ?? ObjectManager::getInstance()->get(PropertyLocker::class); + $this->applyTo = $applyTo ?? ObjectManager::getInstance()->get(ApplyTo::class); } /** @@ -230,22 +245,35 @@ protected function _prepareForm() ] ); + $fieldset->addField( + 'apply_to', + 'multiselect', + [ + 'name' => 'apply_to', + 'label' => __('Apply To'), + 'title' => __('Apply To'), + 'values' => $this->applyTo->toOptionArray(), + 'value' => $attributeObject->getApplyTo() + ] + ); + if ($attributeObject->getId()) { $form->getElement('attribute_code')->setDisabled(1); if (!$attributeObject->getIsUserDefined()) { $form->getElement('is_unique')->setDisabled(1); + $form->getElement('apply_to')->setDisabled(1); } } $scopes = [ - \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE => __('Store View'), - \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_WEBSITE => __('Website'), - \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL => __('Global'), + ScopedAttributeInterface::SCOPE_STORE => __('Store View'), + ScopedAttributeInterface::SCOPE_WEBSITE => __('Website'), + ScopedAttributeInterface::SCOPE_GLOBAL => __('Global'), ]; if ($attributeObject->getAttributeCode() == 'status' || $attributeObject->getAttributeCode() == 'tax_class_id' ) { - unset($scopes[\Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE]); + unset($scopes[ScopedAttributeInterface::SCOPE_STORE]); } $fieldset->addField( @@ -266,7 +294,7 @@ protected function _prepareForm() $form->getElement('is_global')->setDisabled(1); } $this->setForm($form); - $this->getPropertyLocker()->lock($form); + $this->propertyLocker->lock($form); return $this; } @@ -291,19 +319,6 @@ private function getAttributeObject() return $this->_coreRegistry->registry('entity_attribute'); } - /** - * Get property locker - * - * @return PropertyLocker - */ - private function getPropertyLocker() - { - if (null === $this->propertyLocker) { - $this->propertyLocker = ObjectManager::getInstance()->get(PropertyLocker::class); - } - return $this->propertyLocker; - } - /** * Get localized date default value * diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php index d443f399360a9..ff2fdbafe9a2a 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php @@ -1,26 +1,25 @@ getIsUserDefined() && $model->getId()) { // Unset attribute field for system attributes unset($data['apply_to']); + } elseif (!isset($data['apply_to'])) { + $data['apply_to'] = []; } if ($model->getBackendType() == 'static' && !$model->getIsUserDefined()) { diff --git a/app/code/Magento/Catalog/Model/Attribute/Source/ApplyTo.php b/app/code/Magento/Catalog/Model/Attribute/Source/ApplyTo.php new file mode 100644 index 0000000000000..4b4dd6bc7b610 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Attribute/Source/ApplyTo.php @@ -0,0 +1,45 @@ +productTypeList = $productTypeList; + } + + /** + * @inheritDoc + */ + public function toOptionArray() + { + $result = []; + + foreach ($this->productTypeList->getProductTypes() as $productType) { + $result[] = [ + 'value' => $productType->getName(), + 'label' => $productType->getLabel() + ]; + } + + return $result; + } +} diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertAdminTextAttributeAbsentOnProductFormActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertAdminTextAttributeAbsentOnProductFormActionGroup.xml new file mode 100644 index 0000000000000..930b97b6f9c3c --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertAdminTextAttributeAbsentOnProductFormActionGroup.xml @@ -0,0 +1,21 @@ + + + + + + + Assert provided text Attribute is absent on the Product page. + + + + + + + + diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertAdminTextAttributePresentOnProductFormActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertAdminTextAttributePresentOnProductFormActionGroup.xml new file mode 100644 index 0000000000000..decbd6be950fd --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertAdminTextAttributePresentOnProductFormActionGroup.xml @@ -0,0 +1,21 @@ + + + + + + + Assert provided text Attribute is present on the Product page. + + + + + + + + diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/CreateProductAttributeForSimpleProductActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/CreateProductAttributeForSimpleProductActionGroup.xml new file mode 100644 index 0000000000000..0e2d838f04821 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/CreateProductAttributeForSimpleProductActionGroup.xml @@ -0,0 +1,20 @@ + + + + + + + EXTENDS: createProductAttribute. Fills in the Apply To with "Simple" value. + + + + + + + diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection/AdvancedAttributePropertiesSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection/AdvancedAttributePropertiesSection.xml index bcd05e139d17c..8276196f8e69c 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection/AdvancedAttributePropertiesSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCreateProductAttributeSection/AdvancedAttributePropertiesSection.xml @@ -22,5 +22,11 @@ + + + + + + diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/CreateProductAttributeEntityTest/CreateProductAttributeEntityApplyToFieldTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/CreateProductAttributeEntityTest/CreateProductAttributeEntityApplyToFieldTest.xml new file mode 100644 index 0000000000000..cc56b6eee5a3c --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Test/CreateProductAttributeEntityTest/CreateProductAttributeEntityApplyToFieldTest.xml @@ -0,0 +1,82 @@ + + + + + + + + + <description value="Check if 'Apply to' field on Product Attribute creation form works properly"/> + <severity value="AVERAGE"/> + <group value="Catalog"/> + </annotations> + + <before> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="SimpleProduct" stepKey="createSimpleProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="VirtualProduct" stepKey="createVirtualProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + </before> + <after> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/> + <deleteData createDataKey="createVirtualProduct" stepKey="deleteVirtualProduct"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <actionGroup ref="DeleteAttributeSetByLabelActionGroup" stepKey="deleteCustomAttributeSet"> + <argument name="label" value="{{CatalogAttributeSet.attribute_set_name}}"/> + </actionGroup> + <actionGroup ref="NavigateToEditProductAttributeActionGroup" stepKey="goToEditPage"> + <argument name="ProductAttribute" value="{{textProductAttribute.attribute_code}}"/> + </actionGroup> + <click stepKey="clickDelete" selector="{{AttributePropertiesSection.DeleteAttribute}}"/> + <click stepKey="clickOk" selector="{{AttributeDeleteModalSection.confirm}}"/> + <waitForPageLoad stepKey="waitForDeletion"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + </after> + + <!--Navigate to Stores > Attributes > Product.--> + <actionGroup ref="AdminOpenProductAttributePageActionGroup" stepKey="goToProductAttributes"/> + + <!-- Create new Product Attribute for Simple products --> + <actionGroup ref="CreateProductAttributeForSimpleProductActionGroup" stepKey="createAttribute"> + <argument name="attribute" value="textProductAttribute"/> + </actionGroup> + + <!-- Add created attribute to Attribute Set --> + <actionGroup ref="AdminAddUnassignedAttributeToGroupActionGroup" stepKey="createCustomAttributeSet"> + <argument name="label" value="{{CatalogAttributeSet.attribute_set_name}}"/> + <argument name="secondOption" value="{{textProductAttribute.attribute_code}}"/> + </actionGroup> + + <!-- Check if Custom Attribute is applied for Simple product --> + <actionGroup ref="AdminProductPageOpenByIdActionGroup" stepKey="openSimpleProductPage"> + <argument name="productId" value="$$createSimpleProduct.id$$"/> + </actionGroup> + <actionGroup ref="AdminProductPageSelectAttributeSetActionGroup" stepKey="selectAttributeSetSimple"> + <argument name="attributeSetName" value="{{CatalogAttributeSet.attribute_set_name}}"/> + </actionGroup> + <actionGroup ref="AssertAdminTextAttributePresentOnProductFormActionGroup" stepKey="checkCustomAttributeSimpleProduct"> + <argument name="attributeCode" value="{{textProductAttribute.attribute_code}}"/> + </actionGroup> + + <!-- Check if Custom Attribute is not applied for Virtual product --> + <actionGroup ref="AdminProductPageOpenByIdActionGroup" stepKey="openVirtualProductPage"> + <argument name="productId" value="$$createVirtualProduct.id$$"/> + </actionGroup> + <actionGroup ref="AdminProductPageSelectAttributeSetActionGroup" stepKey="selectAttributeSetVirtual"> + <argument name="attributeSetName" value="{{CatalogAttributeSet.attribute_set_name}}"/> + </actionGroup> + <actionGroup ref="AssertAdminTextAttributeAbsentOnProductFormActionGroup" stepKey="checkCustomAttributeVirtualProduct"> + <argument name="attributeCode" value="{{textProductAttribute.attribute_code}}"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Attribute/Edit/Tab/AdvancedTest.php b/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Attribute/Edit/Tab/AdvancedTest.php index 8835a2ecd7f34..6226f5d7e73b8 100644 --- a/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Attribute/Edit/Tab/AdvancedTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Attribute/Edit/Tab/AdvancedTest.php @@ -7,6 +7,7 @@ namespace Magento\Catalog\Test\Unit\Block\Adminhtml\Product\Attribute\Edit\Tab; +use Magento\Backend\Block\Widget\Form\Element\ElementCreator; use Magento\Catalog\Block\Adminhtml\Product\Attribute\Edit\Tab\Advanced; use Magento\Catalog\Model\ResourceModel\Eav\Attribute; use Magento\Config\Model\Config\Source\Yesno; @@ -21,6 +22,7 @@ use Magento\Framework\Filesystem; use Magento\Framework\Filesystem\Directory\ReadInterface; use Magento\Framework\Json\Helper\Data as JsonHelper; +use Magento\Framework\ObjectManagerInterface; use Magento\Framework\Registry; use Magento\Framework\Stdlib\DateTime; use Magento\Framework\Stdlib\DateTime\TimezoneInterface; @@ -38,79 +40,75 @@ class AdvancedTest extends TestCase /** * @var Advanced */ - protected $block; + private $block; /** * @var FormFactory|MockObject */ - protected $formFactory; + private $formFactoryMock; /** * @var Registry|MockObject */ - protected $registry; + private $registryMock; /** * @var TimezoneInterface|MockObject */ - protected $localeDate; + private $localeDateMock; /** * @var Yesno|MockObject */ - protected $yesNo; + private $yesNoMock; /** * @var EavHelper|MockObject */ - protected $eavData; + private $eavDataMock; /** * @var Filesystem|MockObject */ - protected $filesystem; + private $filesystemMock; /** * @var PropertyLocker|MockObject */ - protected $propertyLocker; + private $propertyLockerMock; /** - * @inheritdoc + * @inheritDoc */ protected function setUp(): void { $objectManager = new ObjectManager($this); - $objects = [ - [ - JsonHelper::class, - $this->createMock(JsonHelper::class) - ], - [ - DirectoryHelper::class, - $this->createMock(DirectoryHelper::class) - ] - ]; - $objectManager->prepareObjectManager($objects); - - $this->registry = $this->createMock(Registry::class); - $this->formFactory = $this->createMock(FormFactory::class); - $this->yesNo = $this->createMock(Yesno::class); - $this->localeDate = $this->getMockForAbstractClass(TimezoneInterface::class); - $this->eavData = $this->createMock(EavHelper::class); - $this->filesystem = $this->createMock(Filesystem::class); - $this->propertyLocker = $this->createMock(PropertyLocker::class); + $this->registryMock = $this->createMock(Registry::class); + $this->formFactoryMock = $this->createMock(FormFactory::class); + $this->yesNoMock = $this->createMock(Yesno::class); + $this->localeDateMock = $this->createMock(TimezoneInterface::class); + $this->eavDataMock = $this->createMock(EavHelper::class); + $this->filesystemMock = $this->createMock(Filesystem::class); + $this->propertyLockerMock = $this->createMock(PropertyLocker::class); + + $objectManagerMock = $this->createMock(ObjectManagerInterface::class); + $objectManagerMock->method('get') + ->willReturnMap([ + [ElementCreator::class, $objectManager->getObject(ElementCreator::class)], + [JsonHelper::class, $objectManager->getObject(JsonHelper::class)] + ]); + \Magento\Framework\App\ObjectManager::setInstance($objectManagerMock); $this->block = $objectManager->getObject( Advanced::class, [ - 'registry' => $this->registry, - 'formFactory' => $this->formFactory, - 'localeDate' => $this->localeDate, - 'yesNo' => $this->yesNo, - 'eavData' => $this->eavData, - 'filesystem' => $this->filesystem, - 'propertyLocker' => $this->propertyLocker, + 'registry' => $this->registryMock, + 'formFactory' => $this->formFactoryMock, + 'localeDate' => $this->localeDateMock, + 'yesNo' => $this->yesNoMock, + 'eavData' => $this->eavDataMock, + 'filesystem' => $this->filesystemMock, + 'propertyLocker' => $this->propertyLockerMock ] ); } @@ -127,9 +125,9 @@ public function testToHtml() $timeFormat = 'H:i:s:'; $timeZone = 'America/Chicago'; - $fieldSet = $this->createMock(Fieldset::class); - $form = $this->createMock(Form::class); - $attributeModel = $this->getMockBuilder(Attribute::class) + $fieldsetMock = $this->createMock(Fieldset::class); + $formMock = $this->createMock(Form::class); + $attributeModelMock = $this->getMockBuilder(Attribute::class) ->addMethods(['setDisabled']) ->onlyMethods( [ @@ -143,26 +141,26 @@ public function testToHtml() ) ->disableOriginalConstructor() ->getMock(); - $entityType = $this->createMock(EntityType::class); - $formElement = $this->getMockBuilder(Text::class) + $entityTypeMock = $this->createMock(EntityType::class); + $formElementMock = $this->getMockBuilder(Text::class) ->addMethods(['setDisabled']) ->disableOriginalConstructor() ->getMock(); - $directoryReadInterface = $this->getMockForAbstractClass(ReadInterface::class); - - $this->registry->expects($this->any())->method('registry')->with('entity_attribute') - ->willReturn($attributeModel); - $this->formFactory->expects($this->any())->method('create')->willReturn($form); - $form->expects($this->any())->method('addFieldset')->willReturn($fieldSet); - $form->expects($this->any())->method('getElement')->willReturn($formElement); - $fieldSet->expects($this->any())->method('addField')->willReturnSelf(); - $attributeModel->expects($this->any())->method('getDefaultValue')->willReturn($defaultValue); - $attributeModel->expects($this->any())->method('setDisabled')->willReturnSelf(); - $attributeModel->expects($this->any())->method('getId')->willReturn(1); - $attributeModel->expects($this->any())->method('getEntityType')->willReturn($entityType); - $attributeModel->expects($this->any())->method('getIsUserDefined')->willReturn(false); - $attributeModel->expects($this->any())->method('getAttributeCode')->willReturn('attribute_code'); - $attributeModel->expects($this->any())->method('getFrontendInput')->willReturn($frontendInput); + $directoryReadInterfaceMock = $this->getMockForAbstractClass(ReadInterface::class); + + $this->registryMock->method('registry')->with('entity_attribute') + ->willReturn($attributeModelMock); + $this->formFactoryMock->method('create')->willReturn($formMock); + $formMock->method('addFieldset')->willReturn($fieldsetMock); + $formMock->method('getElement')->willReturn($formElementMock); + $fieldsetMock->method('addField')->willReturnSelf(); + $attributeModelMock->method('getDefaultValue')->willReturn($defaultValue); + $attributeModelMock->method('setDisabled')->willReturnSelf(); + $attributeModelMock->method('getId')->willReturn(1); + $attributeModelMock->method('getEntityType')->willReturn($entityTypeMock); + $attributeModelMock->method('getIsUserDefined')->willReturn(false); + $attributeModelMock->method('getAttributeCode')->willReturn('attribute_code'); + $attributeModelMock->method('getFrontendInput')->willReturn($frontendInput); $dateTimeMock = $this->createMock(\DateTime::class); $dateTimeMock->expects($this->once())->method('setTimezone')->with(new \DateTimeZone($timeZone)); @@ -170,21 +168,21 @@ public function testToHtml() ->method('format') ->with(DateTime::DATETIME_PHP_FORMAT) ->willReturn($localizedDefaultValue); - $this->localeDate->expects($this->any())->method('getDateFormat')->willReturn($dateFormat); - $this->localeDate->expects($this->any())->method('getTimeFormat')->willReturn($timeFormat); - $this->localeDate->expects($this->once())->method('getConfigTimezone')->willReturn($timeZone); - $this->localeDate->expects($this->once()) + $this->localeDateMock->method('getDateFormat')->willReturn($dateFormat); + $this->localeDateMock->method('getTimeFormat')->willReturn($timeFormat); + $this->localeDateMock->expects($this->once())->method('getConfigTimezone')->willReturn($timeZone); + $this->localeDateMock->expects($this->once()) ->method('date') ->with($defaultValue, null, false) ->willReturn($dateTimeMock); - $entityType->expects($this->any())->method('getEntityTypeCode')->willReturn('entity_type_code'); - $this->eavData->expects($this->any())->method('getFrontendClasses')->willReturn([]); - $formElement->expects($this->exactly(2))->method('setDisabled')->willReturnSelf(); - $this->yesNo->expects($this->any())->method('toOptionArray')->willReturn(['yes', 'no']); - $this->filesystem->expects($this->any())->method('getDirectoryRead')->willReturn($directoryReadInterface); - $directoryReadInterface->expects($this->any())->method('getRelativePath')->willReturn('relative_path'); - $this->propertyLocker->expects($this->once())->method('lock')->with($form); + $entityTypeMock->method('getEntityTypeCode')->willReturn('entity_type_code'); + $this->eavDataMock->method('getFrontendClasses')->willReturn([]); + $formElementMock->expects($this->exactly(3))->method('setDisabled')->willReturnSelf(); + $this->yesNoMock->method('toOptionArray')->willReturn(['yes', 'no']); + $this->filesystemMock->method('getDirectoryRead')->willReturn($directoryReadInterfaceMock); + $directoryReadInterfaceMock->method('getRelativePath')->willReturn('relative_path'); + $this->propertyLockerMock->expects($this->once())->method('lock')->with($formMock); $this->block->setData(['action' => 'save']); $this->block->toHtml(); diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/SaveTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/SaveTest.php index 4ad31e4d5ce75..8fd1b18848f27 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/SaveTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/SaveTest.php @@ -115,7 +115,6 @@ class SaveTest extends AttributeTest /** * @var Session|MockObject */ - private $sessionMock; protected function setUp(): void @@ -138,6 +137,13 @@ protected function setUp(): void ->onlyMethods(['create']) ->disableOriginalConstructor() ->getMock(); + $this->filterManagerMock = $this->getMockBuilder(FilterManager::class) + ->addMethods(['stripTags']) + ->disableOriginalConstructor() + ->getMock(); + $this->productHelperMock = $this->getMockBuilder(ProductHelper::class) + ->disableOriginalConstructor() + ->getMock(); $this->attributeFactoryMock = $this->getMockBuilder(AttributeFactory::class) ->onlyMethods(['create']) ->disableOriginalConstructor() @@ -171,19 +177,16 @@ protected function setUp(): void 'save' ] )->getMockForAbstractClass(); - $this->buildFactoryMock->expects($this->any()) - ->method('create') + $this->buildFactoryMock->method('create') ->willReturn($this->builderMock); - $this->validatorFactoryMock->expects($this->any()) - ->method('create') + $this->validatorFactoryMock->method('create') ->willReturn($this->inputTypeValidatorMock); - $this->attributeFactoryMock - ->method('create') + $this->attributeFactoryMock->method('create') ->willReturn($this->productAttributeMock); } /** - * @inheritdoc + * @inheritDoc */ protected function getModel() { @@ -208,8 +211,7 @@ protected function getModel() public function testExecuteWithEmptyData() { - $this->requestMock->expects($this->any()) - ->method('getParam') + $this->requestMock->method('getParam') ->willReturnMap([ ['isAjax', null, null], ['serialized_options', '[]', ''], @@ -225,8 +227,7 @@ public function testExecuteWithEmptyData() $this->resultFactoryMock->expects($this->once()) ->method('create') ->willReturn($this->redirectMock); - $this->redirectMock->expects($this->any()) - ->method('setPath') + $this->redirectMock->method('setPath') ->willReturnSelf(); $this->assertInstanceOf(ResultRedirect::class, $this->getModel()->execute()); @@ -238,8 +239,7 @@ public function testExecuteSaveFrontendClass() 'frontend_input' => 'test_frontend_input', ]; - $this->requestMock->expects($this->any()) - ->method('getParam') + $this->requestMock->method('getParam') ->willReturnMap([ ['isAjax', null, null], ['serialized_options', '[]', ''], @@ -254,8 +254,7 @@ public function testExecuteSaveFrontendClass() $this->requestMock->expects($this->once()) ->method('getPostValue') ->willReturn($data); - $this->inputTypeValidatorMock->expects($this->any()) - ->method('isValid') + $this->inputTypeValidatorMock->method('isValid') ->with($data['frontend_input']) ->willReturn(true); $this->presentationMock->expects($this->once()) @@ -299,7 +298,8 @@ public function testExecute() 'new_attribute_set_name' => 'Test attribute set name', 'frontend_input' => 'test_frontend_input', ]; - $this->filterManagerMock + + $this->filterManagerMock->expects($this->once()) ->method('stripTags') ->willReturn('Test attribute set name'); $this->requestMock->expects($this->any()) @@ -329,8 +329,7 @@ public function testExecute() $this->resultFactoryMock->expects($this->once()) ->method('create') ->willReturn($this->redirectMock); - $this->redirectMock->expects($this->any()) - ->method('setPath') + $this->redirectMock->method('setPath') ->willReturnSelf(); $this->builderMock->expects($this->once()) ->method('setEntityTypeId') @@ -344,12 +343,14 @@ public function testExecute() $this->builderMock->expects($this->once()) ->method('getAttributeSet') ->willReturn($this->attributeSetMock); - $this->requestMock->expects($this->any()) - ->method('getParam') + $this->requestMock->method('getParam') ->willReturnMap([ ['set', null, 1], ['attribute_code', null, 'test_attribute_code'] ]); + $this->filterManagerMock->method('stripTags') + ->with($data['new_attribute_set_name']) + ->willReturn($data['new_attribute_set_name']); $this->inputTypeValidatorMock->expects($this->once()) ->method('getMessages') ->willReturn([]); @@ -364,10 +365,9 @@ public function testExecuteWithOptionsDataError() { $serializedOptions = '{"key":"value"}'; $message = "The attribute couldn't be saved due to an error. Verify your information and try again. " - . "If the error persists, please try again later."; + . 'If the error persists, please try again later.'; - $this->requestMock->expects($this->any()) - ->method('getParam') + $this->requestMock->method('getParam') ->willReturnMap([ ['isAjax', null, true], ['serialized_options', '[]', $serializedOptions], @@ -381,18 +381,16 @@ public function testExecuteWithOptionsDataError() ->expects($this->once()) ->method('addErrorMessage') ->with($message); - $this->addReturnResultConditions('catalog/*/edit', ['_current' => true], ['error' => true]); + $this->addReturnResultConditions(['_current' => true], ['error' => true]); $this->getModel()->execute(); } /** - * @param string $path * @param array $params * @param array $response - * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - private function addReturnResultConditions(string $path = '', array $params = [], array $response = []) + private function addReturnResultConditions(array $params = [], array $response = []) { $layoutMock = $this->getMockBuilder(LayoutInterface::class) ->addMethods(['initMessages']) diff --git a/app/code/Magento/Catalog/view/adminhtml/ui_component/product_attribute_add_form.xml b/app/code/Magento/Catalog/view/adminhtml/ui_component/product_attribute_add_form.xml index 7f87eb0cdd391..e93a10442a4dc 100644 --- a/app/code/Magento/Catalog/view/adminhtml/ui_component/product_attribute_add_form.xml +++ b/app/code/Magento/Catalog/view/adminhtml/ui_component/product_attribute_add_form.xml @@ -516,6 +516,20 @@ </checkbox> </formElements> </field> + <field name="apply_to" sortOrder="80" formElement="multiselect"> + <settings> + <dataType>string</dataType> + <label translate="true">Apply To</label> + <dataScope>apply_to</dataScope> + </settings> + <formElements> + <multiselect> + <settings> + <options class="Magento\Catalog\Model\Attribute\Source\ApplyTo"/> + </settings> + </multiselect> + </formElements> + </field> </fieldset> <fieldset name="manage-titles" sortOrder="25"> <settings>