diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Action/Attribute/Tab/Attributes.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Action/Attribute/Tab/Attributes.php
index 2df0ff0b6cd7c..1ebfa14200364 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Action/Attribute/Tab/Attributes.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Action/Attribute/Tab/Attributes.php
@@ -13,7 +13,18 @@
namespace Magento\Catalog\Block\Adminhtml\Product\Edit\Action\Attribute\Tab;
+use Magento\Backend\Block\Template\Context;
+use Magento\Backend\Block\Widget\Tab\TabInterface;
+use Magento\Catalog\Block\Adminhtml\Form;
+use Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Boolean;
+use Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Image;
+use Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Price;
+use Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Weight;
+use Magento\Catalog\Helper\Product\Edit\Action\Attribute;
+use Magento\Catalog\Model\ProductFactory;
use Magento\Framework\Data\Form\Element\AbstractElement;
+use Magento\Framework\Data\FormFactory;
+use Magento\Framework\Registry;
/**
* Attributes tab block
@@ -23,37 +34,38 @@
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @since 100.0.2
*/
-class Attributes extends \Magento\Catalog\Block\Adminhtml\Form implements
- \Magento\Backend\Block\Widget\Tab\TabInterface
+class Attributes extends Form implements TabInterface
{
/**
- * @var \Magento\Catalog\Model\ProductFactory
+ * @var ProductFactory
*/
protected $_productFactory;
/**
- * @var \Magento\Catalog\Helper\Product\Edit\Action\Attribute
+ * @var Attribute
*/
protected $_attributeAction;
- /** @var array */
+ /**
+ * @var array
+ */
private $excludeFields;
/**
- * @param \Magento\Backend\Block\Template\Context $context
- * @param \Magento\Framework\Registry $registry
- * @param \Magento\Framework\Data\FormFactory $formFactory
- * @param \Magento\Catalog\Model\ProductFactory $productFactory
- * @param \Magento\Catalog\Helper\Product\Edit\Action\Attribute $attributeAction
+ * @param Context $context
+ * @param Registry $registry
+ * @param FormFactory $formFactory
+ * @param ProductFactory $productFactory
+ * @param Attribute $attributeAction
* @param array $data
* @param array|null $excludeFields
*/
public function __construct(
- \Magento\Backend\Block\Template\Context $context,
- \Magento\Framework\Registry $registry,
- \Magento\Framework\Data\FormFactory $formFactory,
- \Magento\Catalog\Model\ProductFactory $productFactory,
- \Magento\Catalog\Helper\Product\Edit\Action\Attribute $attributeAction,
+ Context $context,
+ Registry $registry,
+ FormFactory $formFactory,
+ ProductFactory $productFactory,
+ Attribute $attributeAction,
array $data = [],
array $excludeFields = null
) {
@@ -72,7 +84,7 @@ public function __construct(
*/
protected function _prepareForm(): void
{
- $this->setFormExcludedFieldList($this->getExcludedFields());
+ $this->setFormExcludedFieldList($this->excludeFields);
$this->_eventManager->dispatch(
'adminhtml_catalog_product_form_prepare_excluded_field_list',
['object' => $this]
@@ -110,10 +122,10 @@ public function getAttributes()
protected function _getAdditionalElementTypes()
{
return [
- 'price' => \Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Price::class,
- 'weight' => \Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Weight::class,
- 'image' => \Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Image::class,
- 'boolean' => \Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Boolean::class
+ 'price' => Price::class,
+ 'weight' => Weight::class,
+ 'image' => Image::class,
+ 'boolean' => Boolean::class
];
}
@@ -129,7 +141,7 @@ protected function _getAdditionalElementHtml($element)
$nameAttributeHtml = $element->getExtType() === 'multiple' ? 'name="' . $element->getId() . '_checkbox"' : '';
$elementId = $element->getId();
$dataAttribute = "data-disable='{$elementId}'";
- $dataCheckboxName = "toggle_" . "{$elementId}";
+ $dataCheckboxName = "toggle_{$elementId}";
$checkboxLabel = __('Change');
// @codingStandardsIgnoreStart
$html = <<
HTML;
- if ($elementId === 'weight') {
- $html .= <<require(['Magento_Catalog/js/product/weight-handler'], function (weightHandle) {
- weightHandle.hideWeightSwitcher();
-});
-HTML;
- // @codingStandardsIgnoreEnd
- }
+
+ // @codingStandardsIgnoreEnd
return $html;
}
@@ -190,14 +196,4 @@ public function isHidden()
{
return false;
}
-
- /**
- * Returns excluded fields
- *
- * @return array
- */
- private function getExcludedFields(): array
- {
- return $this->excludeFields;
- }
}
diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Weight.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Weight.php
index fec3daeeacd13..70b2948501d2d 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Weight.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Weight.php
@@ -3,55 +3,64 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
-/**
- * Product form weight field helper
- */
namespace Magento\Catalog\Block\Adminhtml\Product\Helper\Form;
+use Magento\Catalog\Api\Data\ProductAttributeInterface;
+use Magento\Directory\Helper\Data;
use Magento\Framework\Data\Form;
use Magento\Catalog\Model\Product\Edit\WeightResolver;
+use Magento\Framework\Data\Form\Element\CollectionFactory;
+use Magento\Framework\Data\Form\Element\Factory;
+use Magento\Framework\Data\Form\Element\Radios;
+use Magento\Framework\Data\Form\Element\Text;
+use Magento\Framework\Escaper;
+use Magento\Framework\Locale\Format;
-class Weight extends \Magento\Framework\Data\Form\Element\Text
+/**
+ * Product form weight field helper
+ */
+class Weight extends Text
{
/**
* Weight switcher radio-button element
*
- * @var \Magento\Framework\Data\Form\Element\Checkbox
+ * @var Radios
*/
protected $weightSwitcher;
/**
- * @var \Magento\Framework\Locale\Format
+ * @var Format
*/
protected $localeFormat;
/**
- * @var \Magento\Directory\Helper\Data
+ * @var Data
*/
protected $directoryHelper;
/**
- * @param \Magento\Framework\Data\Form\Element\Factory $factoryElement
- * @param \Magento\Framework\Data\Form\Element\CollectionFactory $factoryCollection
- * @param \Magento\Framework\Escaper $escaper
- * @param \Magento\Framework\Locale\Format $localeFormat
- * @param \Magento\Directory\Helper\Data $directoryHelper
+ * @param Factory $factoryElement
+ * @param CollectionFactory $factoryCollection
+ * @param Escaper $escaper
+ * @param Format $localeFormat
+ * @param Data $directoryHelper
* @param array $data
*/
public function __construct(
- \Magento\Framework\Data\Form\Element\Factory $factoryElement,
- \Magento\Framework\Data\Form\Element\CollectionFactory $factoryCollection,
- \Magento\Framework\Escaper $escaper,
- \Magento\Framework\Locale\Format $localeFormat,
- \Magento\Directory\Helper\Data $directoryHelper,
+ Factory $factoryElement,
+ CollectionFactory $factoryCollection,
+ Escaper $escaper,
+ Format $localeFormat,
+ Data $directoryHelper,
array $data = []
) {
$this->directoryHelper = $directoryHelper;
$this->localeFormat = $localeFormat;
$this->weightSwitcher = $factoryElement->create('radios');
$this->weightSwitcher->setValue(
- WeightResolver::HAS_WEIGHT
+ WeightResolver::HAS_NO_WEIGHT
)->setValues(
[
['value' => WeightResolver::HAS_WEIGHT, 'label' => __('Yes')],
@@ -75,28 +84,48 @@ public function __construct(
*/
public function getElementHtml()
{
- if (!$this->getForm()->getDataObject()->getTypeInstance()->hasWeight()) {
- $this->weightSwitcher->setValue(WeightResolver::HAS_NO_WEIGHT);
+ if ($this->getForm()->getDataObject()->getTypeInstance()->hasWeight()) {
+ $this->weightSwitcher->setValue(WeightResolver::HAS_WEIGHT);
}
+
if ($this->getDisabled()) {
$this->weightSwitcher->setDisabled($this->getDisabled());
}
- return '
' .
- '
' .
- $this->weightSwitcher->getLabelHtml() .
- '
' .
- $this->weightSwitcher->getElementHtml() .
- '
' .
- '
' .
- '
' .
- parent::getElementHtml() .
- '' .
- '
' .
- '
';
+
+ $htmlId = $this->getHtmlId();
+ $html = '';
+
+ if ($beforeElementHtml = $this->getBeforeElementHtml()) {
+ $html .= '';
+ }
+
+ $html .= '';
+
+ if (is_array($this->getValue())) {
+ foreach ($this->getValue() as $value) {
+ $html .= $this->getHtmlForInputByValue($this->_escape($value));
+ }
+ } else {
+ $html .= $this->getHtmlForInputByValue($this->getEscapedValue());
+ }
+
+ $html .= '
';
+
+ if ($afterElementJs = $this->getAfterElementJs()) {
+ $html .= $afterElementJs;
+ }
+
+ if ($afterElementHtml = $this->getAfterElementHtml()) {
+ $html .= '';
+ }
+
+ $html .= $this->getHtmlForWeightSwitcher();
+
+ return $html;
}
/**
@@ -112,8 +141,7 @@ public function setForm($form)
}
/**
- * @param null|int|string $index
- * @return null|string
+ * @inheritDoc
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function getEscapedValue($index = null)
@@ -134,4 +162,53 @@ public function getEscapedValue($index = null)
return $value;
}
+
+ /**
+ * Get input html by sting value.
+ *
+ * @param string|null $value
+ *
+ * @return string
+ */
+ private function getHtmlForInputByValue($value)
+ {
+ return '_getUiId()
+ . ' value="' . $value . '" ' . $this->serialize($this->getHtmlAttributes()) . '/>';
+ }
+
+ /**
+ * Get weight switcher html.
+ *
+ * @return string
+ */
+ private function getHtmlForWeightSwitcher()
+ {
+ $html = '';
+ $html .= '
' .
+ '
' .
+ $this->weightSwitcher->getLabelHtml() .
+ '
' .
+ $this->weightSwitcher->getElementHtml() .
+ '
' .
+ '
';
+
+ $html .= '
';
+
+ return $html;
+ }
}
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Save.php
index 2d10d7148fb71..696401e5430d6 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Save.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Save.php
@@ -7,6 +7,7 @@
namespace Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute;
use Magento\AsynchronousOperations\Api\Data\OperationInterface;
+use Magento\Catalog\Api\Data\ProductAttributeInterface;
use Magento\Eav\Model\Config;
use Magento\Framework\App\Action\HttpPostActionInterface;
use Magento\Backend\App\Action;
@@ -14,7 +15,7 @@
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
/**
- * Class Save
+ * Class used for saving mass updated products attributes.
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class Save extends \Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute implements HttpPostActionInterface
@@ -146,6 +147,10 @@ private function sanitizeProductAttributes($attributesData)
$dateFormat = $this->timezone->getDateFormat(\IntlDateFormatter::SHORT);
foreach ($attributesData as $attributeCode => $value) {
+ if ($attributeCode === ProductAttributeInterface::CODE_HAS_WEIGHT) {
+ continue;
+ }
+
$attribute = $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $attributeCode);
if (!$attribute->getAttributeId()) {
unset($attributesData[$attributeCode]);
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Action.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Action.php
index d0a3af92126d3..71ab9413a0d09 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Action.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Action.php
@@ -3,42 +3,81 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\Catalog\Model\ResourceModel\Product;
use Magento\Catalog\Api\Data\ProductInterface;
+use Magento\Catalog\Api\Data\ProductAttributeInterface;
+use Magento\Catalog\Model\AbstractModel;
+use Magento\Catalog\Model\Factory;
+use Magento\Catalog\Model\Product;
+use Magento\Catalog\Model\Product\Type;
+use Magento\Catalog\Model\Product\TypeTransitionManager;
+use Magento\Catalog\Model\ResourceModel\AbstractResource;
+use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory as ProductCollectionFactory;
use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
+use Magento\Eav\Model\Entity\Attribute\UniqueValidationInterface;
+use Magento\Eav\Model\Entity\Context;
+use Magento\Framework\DataObject;
+use Magento\Framework\Stdlib\DateTime\DateTime;
+use Magento\Store\Model\StoreManagerInterface;
/**
* Catalog Product Mass processing resource model
*
* @author Magento Core Team
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
-class Action extends \Magento\Catalog\Model\ResourceModel\AbstractResource
+class Action extends AbstractResource
{
/**
- * @var \Magento\Framework\Stdlib\DateTime\DateTime
+ * @var DateTime
*/
private $dateTime;
/**
- * @param \Magento\Eav\Model\Entity\Context $context
- * @param \Magento\Store\Model\StoreManagerInterface $storeManager
- * @param \Magento\Catalog\Model\Factory $modelFactory
- * @param \Magento\Eav\Model\Entity\Attribute\UniqueValidationInterface $uniqueValidator
- * @param \Magento\Framework\Stdlib\DateTime\DateTime $dateTime
+ * @var ProductCollectionFactory
+ */
+ private $productCollectionFactory;
+
+ /**
+ * @var TypeTransitionManager
+ */
+ private $typeTransitionManager;
+
+ /**
+ * Entity type id values to save
+ *
+ * @var array
+ */
+ private $typeIdValuesToSave = [];
+
+ /**
+ * @param Context $context
+ * @param StoreManagerInterface $storeManager
+ * @param Factory $modelFactory
+ * @param UniqueValidationInterface $uniqueValidator
+ * @param DateTime $dateTime
+ * @param CollectionFactory $productCollectionFactory
+ * @param TypeTransitionManager $typeTransitionManager
* @param array $data
*/
public function __construct(
- \Magento\Eav\Model\Entity\Context $context,
- \Magento\Store\Model\StoreManagerInterface $storeManager,
- \Magento\Catalog\Model\Factory $modelFactory,
- \Magento\Eav\Model\Entity\Attribute\UniqueValidationInterface $uniqueValidator,
- \Magento\Framework\Stdlib\DateTime\DateTime $dateTime,
+ Context $context,
+ StoreManagerInterface $storeManager,
+ Factory $modelFactory,
+ UniqueValidationInterface $uniqueValidator,
+ DateTime $dateTime,
+ ProductCollectionFactory $productCollectionFactory,
+ TypeTransitionManager $typeTransitionManager,
$data = []
) {
parent::__construct($context, $storeManager, $modelFactory, $data, $uniqueValidator);
$this->dateTime = $dateTime;
+ $this->productCollectionFactory = $productCollectionFactory;
+ $this->typeTransitionManager = $typeTransitionManager;
}
/**
@@ -50,7 +89,7 @@ protected function _construct()
{
$resource = $this->_resource;
$this->setType(
- \Magento\Catalog\Model\Product::ENTITY
+ Product::ENTITY
)->setConnection(
$resource->getConnection('catalog')
);
@@ -67,13 +106,18 @@ protected function _construct()
*/
public function updateAttributes($entityIds, $attrData, $storeId)
{
- $object = new \Magento\Framework\DataObject();
+ $object = new DataObject();
$object->setStoreId($storeId);
$attrData[ProductInterface::UPDATED_AT] = $this->dateTime->gmtDate();
$this->getConnection()->beginTransaction();
try {
foreach ($attrData as $attrCode => $value) {
+ if ($attrCode === ProductAttributeInterface::CODE_HAS_WEIGHT) {
+ $this->updateHasWeightAttribute($entityIds, $value);
+ continue;
+ }
+
$attribute = $this->getAttribute($attrCode);
if (!$attribute->getAttributeId()) {
continue;
@@ -105,7 +149,7 @@ public function updateAttributes($entityIds, $attrData, $storeId)
/**
* Insert or Update attribute data
*
- * @param \Magento\Catalog\Model\AbstractModel $object
+ * @param AbstractModel $object
* @param AbstractAttribute $attribute
* @param mixed $value
* @return $this
@@ -136,13 +180,13 @@ protected function _saveAttributeValue($object, $attribute, $value)
}
$data = $attribute->isStatic()
- ? new \Magento\Framework\DataObject(
+ ? new DataObject(
[
$this->getLinkField() => $entityId,
$attribute->getAttributeCode() => $this->_prepareValueForSave($value, $attribute),
]
)
- : new \Magento\Framework\DataObject(
+ : new DataObject(
[
'attribute_id' => $attribute->getAttributeId(),
'store_id' => $storeId,
@@ -178,9 +222,10 @@ protected function _saveAttributeValue($object, $attribute, $value)
}
/**
- * Resolve entity id
+ * Resolve entity id for current entity
*
* @param int $entityId
+ *
* @return int
*/
protected function resolveEntityId($entityId)
@@ -194,4 +239,87 @@ protected function resolveEntityId($entityId)
->where('entity_id = ?', $entityId);
return $this->getConnection()->fetchOne($select);
}
+
+ /**
+ * Process product_has_weight attribute update
+ *
+ * @param array $entityIds
+ * @param string $value
+ */
+ private function updateHasWeightAttribute($entityIds, $value): void
+ {
+ $productCollection = $this->productCollectionFactory->create();
+ $productCollection->addIdFilter($entityIds);
+ // Type can be changed depending on weight only between simple and virtual products
+ $productCollection->addFieldToFilter(
+ Product::TYPE_ID,
+ [
+ 'in' => [
+ Type::TYPE_SIMPLE,
+ Type::TYPE_VIRTUAL
+ ]
+ ]
+ );
+ $productCollection->addFieldToSelect(Product::TYPE_ID);
+ $i = 0;
+
+ foreach ($productCollection->getItems() as $product) {
+ $product->setData(ProductAttributeInterface::CODE_HAS_WEIGHT, $value);
+ $oldTypeId = $product->getTypeId();
+ $this->typeTransitionManager->processProduct($product);
+
+ if ($oldTypeId !== $product->getTypeId()) {
+ $i++;
+ $this->saveTypeIdValue($product);
+
+ // save collected data every 1000 rows
+ if ($i % 1000 === 0) {
+ $this->processTypeIdValues();
+ }
+ }
+ }
+
+ $this->processTypeIdValues();
+ }
+
+ /**
+ * Save type id value to be updated
+ *
+ * @param Product $product
+ * @return $this
+ */
+ private function saveTypeIdValue($product): self
+ {
+ $typeId = $product->getTypeId();
+
+ if (!array_key_exists($typeId, $this->typeIdValuesToSave)) {
+ $this->typeIdValuesToSave[$typeId] = [];
+ }
+
+ $this->typeIdValuesToSave[$typeId][] = $product->getId();
+
+ return $this;
+ }
+
+ /**
+ * Update type id values
+ *
+ * @return $this
+ */
+ private function processTypeIdValues(): self
+ {
+ $connection = $this->getConnection();
+ $table = $this->getTable('catalog_product_entity');
+
+ foreach ($this->typeIdValuesToSave as $typeId => $entityIds) {
+ $connection->update(
+ $table,
+ ['type_id' => $typeId],
+ ['entity_id IN (?)' => $entityIds]
+ );
+ }
+ $this->typeIdValuesToSave = [];
+
+ return $this;
+ }
}
diff --git a/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Helper/Form/WeightTest.php b/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Helper/Form/WeightTest.php
index ffcb476465dc4..2b11d62961007 100644
--- a/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Helper/Form/WeightTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Helper/Form/WeightTest.php
@@ -5,62 +5,72 @@
*/
namespace Magento\Catalog\Test\Unit\Block\Adminhtml\Product\Helper\Form;
-class WeightTest extends \PHPUnit\Framework\TestCase
+use Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Weight;
+use Magento\Framework\Data\Form;
+use Magento\Framework\Data\Form\Element\CollectionFactory;
+use Magento\Framework\Data\Form\Element\Factory;
+use Magento\Framework\Data\Form\Element\Radios;
+use Magento\Framework\Locale\Format;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
+
+class WeightTest extends TestCase
{
/**
- * @var \Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Weight
+ * @var Weight
*/
protected $_model;
/**
- * @var \PHPUnit_Framework_MockObject_MockObject
+ * @var Radios|MockObject
*/
protected $weightSwitcher;
/**
- * @var \PHPUnit_Framework_MockObject_MockObject
+ * @var Factory|MockObject
*/
protected $factory;
/**
- * @var \PHPUnit_Framework_MockObject_MockObject
+ * @var CollectionFactory|MockObject
*/
protected $collectionFactory;
/**
- * @var \PHPUnit_Framework_MockObject_MockObject
+ * @var Format|MockObject
*/
protected $localeFormat;
protected function setUp()
{
$this->weightSwitcher = $this->createPartialMock(
- \Magento\Framework\Data\Form\Element\Radios::class,
+ Radios::class,
['setId', 'setName', 'setLabel', 'setForm']
);
- $this->weightSwitcher->expects($this->any())->method('setId')->will($this->returnSelf());
- $this->weightSwitcher->expects($this->any())->method('setName')->will($this->returnSelf());
- $this->weightSwitcher->expects($this->any())->method('setLabel')->will($this->returnSelf());
+ $this->weightSwitcher->method('setId')->will($this->returnSelf());
+ $this->weightSwitcher->method('setName')->will($this->returnSelf());
+ $this->weightSwitcher->method('setLabel')->will($this->returnSelf());
- $this->factory = $this->createMock(\Magento\Framework\Data\Form\Element\Factory::class);
+ $this->factory = $this->createMock(Factory::class);
$this->factory->expects(
$this->once()
)->method(
'create'
)->with(
$this->equalTo('radios')
- )->will(
- $this->returnValue($this->weightSwitcher)
+ )->willReturn(
+ $this->weightSwitcher
);
- $this->localeFormat = $this->createMock(\Magento\Framework\Locale\Format::class);
+ $this->localeFormat = $this->createMock(Format::class);
$this->collectionFactory = $this->createPartialMock(
- \Magento\Framework\Data\Form\Element\CollectionFactory::class,
+ CollectionFactory::class,
['create']
);
- $this->_model = (new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this))->getObject(
- \Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Weight::class,
+ $this->_model = (new ObjectManager($this))->getObject(
+ Weight::class,
[
'factoryElement' => $this->factory,
'factoryCollection' => $this->collectionFactory,
@@ -71,10 +81,8 @@ protected function setUp()
public function testSetForm()
{
- $form = $this->createMock(\Magento\Framework\Data\Form::class);
- $this->weightSwitcher->expects(
- $this->any()
- )->method(
+ $form = $this->createMock(Form::class);
+ $this->weightSwitcher->method(
'setForm'
)->with(
$this->equalTo($form)
@@ -87,9 +95,7 @@ public function testSetForm()
public function testGetEscapedValue()
{
- $this->localeFormat->expects(
- $this->any()
- )->method(
+ $this->localeFormat->method(
'getPriceFormat'
)->willReturn([
'precision' => 2,
@@ -97,7 +103,7 @@ public function testGetEscapedValue()
'groupSymbol' => '.',
]);
- $this->_model->setValue('30000.4');
+ $this->_model->setValue(30000.4);
$this->_model->setEntityAttribute(true);
$return = $this->_model->getEscapedValue('30000.4');
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/ActionTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/ActionTest.php
new file mode 100644
index 0000000000000..0027fd9fecc11
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/ActionTest.php
@@ -0,0 +1,338 @@
+contextMock = $this->getMockBuilder(Context::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->storeManagerMock = $this->getMockBuilder(StoreManagerInterface::class)
+ ->getMockForAbstractClass();
+ $this->factoryMock = $this->getMockBuilder(Factory::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->uniqueValidatorMock = $this->getMockBuilder(UniqueValidationInterface::class)
+ ->getMockForAbstractClass();
+ $this->productCollectionFactoryMock = $this->getMockBuilder(ProductCollectionFactory::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->typeTransitionManagerMock = $this->createPartialMock(
+ TypeTransitionManager::class,
+ ['processProduct']
+ );
+ $this->dateTimeMock = $this->getMockBuilder(DateTime::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->eavConfigMock = $this->getMockBuilder(Config::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->resourceMock = $this->getMockBuilder(ResourceConnection::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->entityTypeMock = $this->getMockBuilder(EntityType::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->contextMock->method('getEavConfig')
+ ->willReturn($this->eavConfigMock);
+ $this->contextMock->method('getResource')
+ ->willReturn($this->resourceMock);
+ $this->eavConfigMock->method('getEntityType')
+ ->willReturn($this->entityTypeMock);
+ $updatedAtAttributeMock = $this->getMockBuilder(AbstractAttribute::class)
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $this->eavConfigMock->method('getAttribute')
+ ->willReturn($updatedAtAttributeMock);
+
+ $objectManager = new ObjectManager($this);
+ $this->model = $objectManager->getObject(
+ Action::class,
+ [
+ 'context' => $this->contextMock,
+ 'storeManager' => $this->storeManagerMock,
+ 'modelFactory' => $this->factoryMock,
+ 'uniqueValidator' => $this->uniqueValidatorMock,
+ 'dateTime' => $this->dateTimeMock,
+ 'productCollectionFactory' => $this->productCollectionFactoryMock,
+ 'typeTransitionManager' => $this->typeTransitionManagerMock,
+ 'data' => []
+ ]
+ );
+ }
+
+ private function prepareAdapter()
+ {
+ $this->connectionMock = $this->getMockBuilder(AdapterInterface::class)
+ ->getMockForAbstractClass();
+ $this->resourceMock->method('getConnection')
+ ->willReturn($this->connectionMock);
+ $this->resourceMock->method('getTableName')
+ ->willReturn('catalog_product_entity');
+ }
+
+ private function prepareProductCollection($items)
+ {
+ $this->productCollectionMock = $this->getMockBuilder(ProductCollection::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->productCollectionMock->method('addIdFilter')
+ ->with(static::ENTITY_IDS)
+ ->willReturnSelf();
+ $this->productCollectionMock->method('addFieldToFilter')
+ ->willReturnSelf();
+ $this->productCollectionMock->method('addFieldToSelect')
+ ->willReturnSelf();
+ $this->productCollectionMock->method('getItems')
+ ->willReturn($items);
+ $this->productCollectionFactoryMock->method('create')
+ ->willReturn($this->productCollectionMock);
+ }
+
+ /**
+ * @param int $hasWeight
+ * @param string $typeId
+ * @param Product[] $items
+ * @param int[] $entityIds
+ * @dataProvider updateProductHasWeightAttributesDataProvider
+ */
+ public function testUpdateProductHasWeightAttributes($hasWeight, $typeId, $items, $entityIds)
+ {
+ $this->prepareAdapter();
+ $this->prepareProductCollection($items);
+ $attrData = [
+ ProductAttributeInterface::CODE_HAS_WEIGHT => $hasWeight
+ ];
+ $storeId = 0;
+
+ $this->connectionMock->expects($this->once())
+ ->method('update')
+ ->with(
+ 'catalog_product_entity',
+ ['type_id' => $typeId],
+ ['entity_id IN (?)' => $entityIds]
+ );
+
+ $this->model->updateAttributes(static::ENTITY_IDS, $attrData, $storeId);
+ }
+
+ /**
+ * Update Attributes data provider
+ *
+ * @return array
+ */
+ public function updateProductHasWeightAttributesDataProvider()
+ {
+ return [
+ [
+ WeightResolver::HAS_WEIGHT,
+ Type::TYPE_SIMPLE,
+ $this->getProductsVirtualToSimple(),
+ static::ENTITY_IDS
+ ],
+ [
+ WeightResolver::HAS_NO_WEIGHT,
+ Type::TYPE_VIRTUAL,
+ $this->getProductsSimpleToVirtual(),
+ static::ENTITY_IDS
+ ],
+ [
+ WeightResolver::HAS_NO_WEIGHT,
+ Type::TYPE_VIRTUAL,
+ $this->getProductsMixedTypes(),
+ array_slice(static::ENTITY_IDS, 2, 2)
+ ]
+ ];
+ }
+
+ private function getProductsSimpleToVirtual()
+ {
+ $result = [];
+
+ foreach (static::ENTITY_IDS as $entityId) {
+ $productMock = $this->getMockBuilder(Product::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $productMock->method('getId')
+ ->willReturn($entityId);
+ $productMock->expects($this->at(1))
+ ->method('getTypeId')
+ ->willReturn(Type::TYPE_SIMPLE);
+ $productMock->expects($this->at(2))
+ ->method('getTypeId')
+ ->willReturn(Type::TYPE_VIRTUAL);
+ $productMock->expects($this->at(3))
+ ->method('getTypeId')
+ ->willReturn(Type::TYPE_VIRTUAL);
+
+ $result[] = $productMock;
+ }
+
+ return $result;
+ }
+
+ private function getProductsVirtualToSimple()
+ {
+ $result = [];
+
+ foreach (static::ENTITY_IDS as $entityId) {
+ $productMock = $this->getMockBuilder(Product::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $productMock->method('getId')
+ ->willReturn($entityId);
+ $productMock->expects($this->at(1))
+ ->method('getTypeId')
+ ->willReturn(Type::TYPE_VIRTUAL);
+ $productMock->expects($this->at(2))
+ ->method('getTypeId')
+ ->willReturn(Type::TYPE_SIMPLE);
+ $productMock->expects($this->at(3))
+ ->method('getTypeId')
+ ->willReturn(Type::TYPE_SIMPLE);
+
+ $result[] = $productMock;
+ }
+
+ return $result;
+ }
+
+ private function getProductsMixedTypes()
+ {
+ $result = [];
+
+ $i = 0;
+ foreach (static::ENTITY_IDS as $entityId) {
+ $productMock = $this->getMockBuilder(Product::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $productMock->method('getId')
+ ->willReturn($entityId);
+
+ if ($i < 2) {
+ $productMock->expects($this->at(1))
+ ->method('getTypeId')
+ ->willReturn(Type::TYPE_SIMPLE);
+ $productMock->expects($this->at(2))
+ ->method('getTypeId')
+ ->willReturn(Type::TYPE_SIMPLE);
+ } else {
+ $productMock->expects($this->at(1))
+ ->method('getTypeId')
+ ->willReturn(Type::TYPE_SIMPLE);
+ $productMock->expects($this->at(2))
+ ->method('getTypeId')
+ ->willReturn(Type::TYPE_VIRTUAL);
+ $productMock->expects($this->at(3))
+ ->method('getTypeId')
+ ->willReturn(Type::TYPE_VIRTUAL);
+ }
+
+ $result[] = $productMock;
+ $i++;
+ }
+
+ return $result;
+ }
+}
diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/action/attribute.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/action/attribute.phtml
index 056cf014f769a..1eb3f9a03d3f9 100644
--- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/action/attribute.phtml
+++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/action/attribute.phtml
@@ -17,6 +17,7 @@