From ea20604c95f32ec79b61dad7f6b7102f9bfed5f1 Mon Sep 17 00:00:00 2001 From: Andrii Kasian Date: Mon, 17 Oct 2016 15:47:54 +0300 Subject: [PATCH 1/2] MAGETWO-59708: [Backport] - [Customer] Fast Save of Product Variations 2.1.x --- .../Model/Product/Attribute/Backend/Sku.php | 5 +- .../Model/Product/Gallery/CreateHandler.php | 24 ++++- .../Model/Product/Link/SaveHandler.php | 17 ++-- .../Catalog/Model/ResourceModel/Category.php | 4 +- .../Model/ResourceModel/Eav/Attribute.php | 11 +-- .../Model/ResourceModel/Product/Link.php | 24 +++++ .../Model/Stock/StockItemRepository.php | 29 +++++- .../Model/Stock/StockItemRepositoryTest.php | 27 ++++-- .../Helper/Plugin/UpdateConfigurations.php | 24 +++-- .../Model/Product/VariationHandler.php | 9 +- .../Plugin/UpdateConfigurationsTest.php | 48 +++++---- .../components/dynamic-rows-configurable.js | 4 +- .../Entity/Attribute/AbstractAttribute.php | 7 +- .../Model/ResourceModel/AttributeLoader.php | 97 +++++++++++++++++++ .../ResourceModel/AttributePersistor.php | 9 +- .../Eav/Model/ResourceModel/CreateHandler.php | 47 +++++---- .../Eav/Model/ResourceModel/UpdateHandler.php | 27 +++--- .../Attribute/AbstractAttributeTest.php | 2 +- .../Annotation/ApiDataFixture.php | 4 + ...h_shipping_method_and_items_categories.php | 2 +- 20 files changed, 327 insertions(+), 94 deletions(-) create mode 100644 app/code/Magento/Eav/Model/ResourceModel/AttributeLoader.php diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Sku.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Sku.php index 327729cf83695..290770bd296c3 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Sku.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Sku.php @@ -73,9 +73,12 @@ protected function _generateUniqueSku($object) { $attribute = $this->getAttribute(); $entity = $attribute->getEntity(); - $increment = $this->_getLastSimilarAttributeValueIncrement($attribute, $object); $attributeValue = $object->getData($attribute->getAttributeCode()); + $increment = null; while (!$entity->checkAttributeUniqueValue($attribute, $object)) { + if ($increment === null) { + $increment = $this->_getLastSimilarAttributeValueIncrement($attribute, $object); + } $sku = trim($attributeValue); if (strlen($sku . '-' . ++$increment) > self::SKU_MAX_LENGTH) { $sku = substr($sku, 0, -strlen($increment) - 1); diff --git a/app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php b/app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php index e6bce5aeae0ff..e8beec14d5b19 100644 --- a/app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php +++ b/app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php @@ -58,6 +58,11 @@ class CreateHandler implements ExtensionInterface */ protected $fileStorageDb; + /** + * @var array + */ + private $mediaAttributeCodes; + /** * @param \Magento\Framework\EntityManager\MetadataPool $metadataPool * @param \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository @@ -145,9 +150,11 @@ public function execute($product, $arguments = []) } /* @var $mediaAttribute \Magento\Catalog\Api\Data\ProductAttributeInterface */ - foreach ($this->mediaConfig->getMediaAttributeCodes() as $mediaAttrCode) { + foreach ($this->getMediaAttributeCodes() as $mediaAttrCode) { $attrData = $product->getData($mediaAttrCode); - + if (empty($attrData) && empty($clearImages) && empty($newImages) && empty($existImages)) { + continue; + } if (in_array($attrData, $clearImages)) { $product->setData($mediaAttrCode, 'no_selection'); } @@ -393,4 +400,17 @@ protected function copyImage($file) ); } } + + /** + * Get Media Attribute Codes cached value + * + * @return array + */ + private function getMediaAttributeCodes() + { + if ($this->mediaAttributeCodes === null) { + $this->mediaAttributeCodes = $this->mediaConfig->getMediaAttributeCodes(); + } + return $this->mediaAttributeCodes; + } } diff --git a/app/code/Magento/Catalog/Model/Product/Link/SaveHandler.php b/app/code/Magento/Catalog/Model/Product/Link/SaveHandler.php index 3df4d9813a668..167dc2be15b29 100644 --- a/app/code/Magento/Catalog/Model/Product/Link/SaveHandler.php +++ b/app/code/Magento/Catalog/Model/Product/Link/SaveHandler.php @@ -40,7 +40,6 @@ public function __construct( Link $linkResource, ProductLinkRepositoryInterface $productLinkRepository ) { - $this->metadataPool = $metadataPool; $this->linkResource = $linkResource; $this->productLinkRepository = $productLinkRepository; @@ -54,12 +53,18 @@ public function __construct( */ public function execute($entityType, $entity) { - /** @var \Magento\Catalog\Api\Data\ProductInterface $entity*/ - foreach ($this->productLinkRepository->getList($entity) as $link) { - $this->productLinkRepository->delete($link); + $link = $entity->getData($this->metadataPool->getMetadata($entityType)->getLinkField()); + if ($this->linkResource->hasProductLinks($link)) { + /** @var \Magento\Catalog\Api\Data\ProductInterface $entity*/ + foreach ($this->productLinkRepository->getList($entity) as $link) { + $this->productLinkRepository->delete($link); + } } - foreach ($entity->getProductLinks() as $link) { - $this->productLinkRepository->save($link); + $productLinks = $entity->getProductLinks(); + if (count($productLinks) > 0) { + foreach ($entity->getProductLinks() as $link) { + $this->productLinkRepository->save($link); + } } return $entity; } diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category.php b/app/code/Magento/Catalog/Model/ResourceModel/Category.php index 30906b242d90e..90f077c0266b0 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Category.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Category.php @@ -233,7 +233,9 @@ protected function _beforeSave(\Magento\Framework\DataObject $object) if (!$object->getChildrenCount()) { $object->setChildrenCount(0); } - + $object->setAttributeSetId( + $object->getAttributeSetId() ?: $this->getEntityType()->getDefaultAttributeSetId() + ); if ($object->isObjectNew()) { if ($object->getPosition() === null) { $object->setPosition($this->_getMaxPosition($object->getPath()) + 1); diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Eav/Attribute.php b/app/code/Magento/Catalog/Model/ResourceModel/Eav/Attribute.php index c640e42343fc5..3e913b32d186a 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Eav/Attribute.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Eav/Attribute.php @@ -351,14 +351,11 @@ public function getStoreId() */ public function getApplyTo() { - if ($this->getData(self::APPLY_TO)) { - if (is_array($this->getData(self::APPLY_TO))) { - return $this->getData(self::APPLY_TO); - } - return explode(',', $this->getData(self::APPLY_TO)); - } else { - return []; + $applyTo = $this->_getData(self::APPLY_TO) ?: []; + if (!is_array($applyTo)) { + $applyTo = explode(',', $applyTo); } + return $applyTo; } /** diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Link.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Link.php index bbccabe5a61c9..17bfa90e8842d 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Link.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Link.php @@ -96,6 +96,30 @@ public function getProductLinkId($parentId, $linkedProductId, $typeId) return $connection->fetchOne($select, $bind); } + /** + * Check if product has links. + * + * @param int $parentId ID of product + * @return bool + */ + public function hasProductLinks($parentId) + { + $connection = $this->getConnection(); + $select = $connection->select()->from( + $this->getMainTable(), + ['count' => new \Zend_Db_Expr('COUNT(*)')] + )->where( + 'product_id = :product_id' + ) ; + + return $connection->fetchOne( + $select, + [ + 'product_id' => $parentId + ] + ) > 0; + } + /** * Save Product Links process * diff --git a/app/code/Magento/CatalogInventory/Model/Stock/StockItemRepository.php b/app/code/Magento/CatalogInventory/Model/Stock/StockItemRepository.php index bf96f1aaee49e..a339fdf3f8d7d 100644 --- a/app/code/Magento/CatalogInventory/Model/Stock/StockItemRepository.php +++ b/app/code/Magento/CatalogInventory/Model/Stock/StockItemRepository.php @@ -15,13 +15,14 @@ use Magento\CatalogInventory\Model\ResourceModel\Stock\Item as StockItemResource; use Magento\CatalogInventory\Model\Spi\StockStateProviderInterface; use Magento\CatalogInventory\Model\StockRegistryStorage; +use Magento\Framework\App\ObjectManager; use Magento\Framework\DB\MapperFactory; use Magento\Framework\DB\QueryBuilderFactory; use Magento\Framework\Exception\CouldNotDeleteException; use Magento\Framework\Exception\CouldNotSaveException; use Magento\Framework\Exception\NoSuchEntityException; -use Magento\Framework\Stdlib\DateTime\TimezoneInterface; use Magento\Framework\Stdlib\DateTime\DateTime; +use Magento\Framework\Stdlib\DateTime\TimezoneInterface; /** * Class StockItemRepository @@ -89,6 +90,9 @@ class StockItemRepository implements StockItemRepositoryInterface */ protected $stockRegistryStorage; + /** @var \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory */ + protected $productCollectionFactory; + /** * @param StockConfigurationInterface $stockConfiguration * @param StockStateProviderInterface $stockStateProvider @@ -129,6 +133,21 @@ public function __construct( $this->dateTime = $dateTime; } + /** + * @deprecated + * @return \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory + */ + private function getProductCollectionFactory() + { + if ($this->productCollectionFactory === null) { + $this->productCollectionFactory = ObjectManager::getInstance()->get( + \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory::class + ); + } + + return $this->productCollectionFactory; + } + /** * @inheritdoc */ @@ -136,8 +155,12 @@ public function save(\Magento\CatalogInventory\Api\Data\StockItemInterface $stoc { try { /** @var \Magento\Catalog\Model\Product $product */ - $product = $this->productFactory->create(); - $product->load($stockItem->getProductId()); + $product = $this->getProductCollectionFactory()->create() + ->setFlag('has_stock_status_filter') + ->addIdFilter($stockItem->getProductId()) + ->addFieldToSelect('type_id') + ->getFirstItem(); + if (!$product->getId()) { return $stockItem; } diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/StockItemRepositoryTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/StockItemRepositoryTest.php index 34c0546be559b..00b39069323e1 100644 --- a/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/StockItemRepositoryTest.php +++ b/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/StockItemRepositoryTest.php @@ -5,6 +5,8 @@ */ namespace Magento\CatalogInventory\Test\Unit\Model\Stock; +use Magento\Catalog\Model\ResourceModel\Product\Collection; +use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory; use Magento\CatalogInventory\Model\Stock\StockItemRepository; use Magento\CatalogInventory\Api\Data as InventoryApiData; use Magento\CatalogInventory\Model\StockRegistryStorage; @@ -151,9 +153,8 @@ protected function setUp() ->disableOriginalConstructor() ->setMethods(['load', 'getId', 'getTypeId', '__wakeup']) ->getMock(); - $this->productFactoryMock->expects($this->any()) - ->method('create') - ->willReturn($this->productMock); + + $this->productFactoryMock->expects($this->any())->method('create')->willReturn($this->productMock); $this->queryBuilderFactoryMock = $this->getMockBuilder('Magento\Framework\DB\QueryBuilderFactory') ->setMethods(['create']) @@ -183,6 +184,22 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); + $productCollection = $this->getMockBuilder( + \Magento\Catalog\Model\ResourceModel\Product\Collection::class + )->disableOriginalConstructor()->getMock(); + + $productCollection->expects($this->any())->method('setFlag')->willReturnSelf(); + $productCollection->expects($this->any())->method('addIdFilter')->willReturnSelf(); + $productCollection->expects($this->any())->method('addFieldToSelect')->willReturnSelf(); + $productCollection->expects($this->any())->method('getFirstItem')->willReturn($this->productMock); + + $productCollectionFactory = $this->getMockBuilder(CollectionFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + + $productCollectionFactory->expects($this->any())->method('create')->willReturn($productCollection); + $this->model = (new ObjectManager($this))->getObject( StockItemRepository::class, [ @@ -198,6 +215,7 @@ protected function setUp() 'indexProcessor' => $this->indexProcessorMock, 'dateTime' => $this->dateTime, 'stockRegistryStorage' => $this->stockRegistryStorage, + 'productCollectionFactory' => $productCollectionFactory, ] ); } @@ -261,7 +279,6 @@ public function testSave() $productId = 1; $this->stockItemMock->expects($this->any())->method('getProductId')->willReturn($productId); - $this->productMock->expects($this->once())->method('load')->with($productId)->willReturnSelf(); $this->productMock->expects($this->once())->method('getId')->willReturn($productId); $this->productMock->expects($this->once())->method('getTypeId')->willReturn('typeId'); $this->stockConfigurationMock->expects($this->once())->method('isQty')->with('typeId')->willReturn(true); @@ -307,7 +324,6 @@ public function testSaveWithoutProductId() $productId = 1; $this->stockItemMock->expects($this->any())->method('getProductId')->willReturn($productId); - $this->productMock->expects($this->once())->method('load')->with($productId)->willReturnSelf(); $this->productMock->expects($this->once())->method('getId')->willReturn(null); $this->stockRegistryStorage->expects($this->never())->method('removeStockItem'); $this->stockRegistryStorage->expects($this->never())->method('removeStockStatus'); @@ -323,7 +339,6 @@ public function testSaveException() $productId = 1; $this->stockItemMock->expects($this->any())->method('getProductId')->willReturn($productId); - $this->productMock->expects($this->once())->method('load')->with($productId)->willReturnSelf(); $this->productMock->expects($this->once())->method('getId')->willReturn($productId); $this->productMock->expects($this->once())->method('getTypeId')->willReturn('typeId'); $this->stockConfigurationMock->expects($this->once())->method('isQty')->with('typeId')->willReturn(false); diff --git a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurations.php b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurations.php index 2149b740bba8a..6abf1f2ad9b9d 100644 --- a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurations.php +++ b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurations.php @@ -32,7 +32,7 @@ class UpdateConfigurations 'swatch_image', 'small_image', 'thumbnail', - 'image' + 'image', ]; /** @@ -65,13 +65,15 @@ public function afterInitialize( ) { $configurations = $this->getConfigurationsFromProduct($configurableProduct); $configurations = $this->variationHandler->duplicateImagesForVariations($configurations); - foreach ($configurations as $productId => $productData) { - /** @var \Magento\Catalog\Model\Product $product */ - $product = $this->productRepository->getById($productId, false, $this->request->getParam('store', 0)); - $productData = $this->variationHandler->processMediaGallery($product, $productData); - $product->addData($productData); - if ($product->hasDataChanges()) { - $product->save(); + if (count($configurations)) { + foreach ($configurations as $productId => $productData) { + /** @var \Magento\Catalog\Model\Product $product */ + $product = $this->productRepository->getById($productId, false, $this->request->getParam('store', 0)); + $productData = $this->variationHandler->processMediaGallery($product, $productData); + $product->addData($productData); + if ($product->hasDataChanges()) { + $product->save(); + } } } return $configurableProduct; @@ -90,6 +92,12 @@ private function getConfigurationsFromProduct(\Magento\Catalog\Model\Product $co $configurableMatrix = $configurableProduct->hasData('configurable-matrix') ? $configurableProduct->getData('configurable-matrix') : []; foreach ($configurableMatrix as $item) { + if (empty($item['was_changed'])) { + continue; + } else { + unset($item['was_changed']); + } + if (!$item['newProduct']) { $result[$item['id']] = $this->mapData($item); diff --git a/app/code/Magento/ConfigurableProduct/Model/Product/VariationHandler.php b/app/code/Magento/ConfigurableProduct/Model/Product/VariationHandler.php index 7ba330f5a060c..bc272da988c94 100644 --- a/app/code/Magento/ConfigurableProduct/Model/Product/VariationHandler.php +++ b/app/code/Magento/ConfigurableProduct/Model/Product/VariationHandler.php @@ -29,6 +29,9 @@ class VariationHandler /** @var \Magento\Catalog\Model\ProductFactory */ protected $productFactory; + /** @var \Magento\Eav\Model\Entity\Attribute\AbstractAttribute[] */ + private $attributes; + /** * @var \Magento\CatalogInventory\Api\StockConfigurationInterface * @deprecated @@ -70,6 +73,7 @@ public function __construct( public function generateSimpleProducts($parentProduct, $productsData) { $generatedProductIds = []; + $this->attributes = null; $productsData = $this->duplicateImagesForVariations($productsData); foreach ($productsData as $simpleProductData) { $newSimpleProduct = $this->productFactory->create(); @@ -156,7 +160,10 @@ protected function fillSimpleProductData( $parentProduct->getNewVariationsAttributeSetId() ); - foreach ($product->getTypeInstance()->getSetAttributes($product) as $attribute) { + if ($this->attributes === null) { + $this->attributes = $product->getTypeInstance()->getSetAttributes($product); + } + foreach ($this->attributes as $attribute) { if ($attribute->getIsUnique() || $attribute->getAttributeCode() == 'url_key' || $attribute->getFrontend()->getInputType() == 'gallery' || diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurationsTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurationsTest.php index 229844f86ecf3..5cf3e559b3dae 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurationsTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurationsTest.php @@ -90,13 +90,24 @@ public function testAfterInitialize() 'swatch_image' => 'simple2_swatch_image', 'small_image' => 'simple2_small_image', 'thumbnail' => 'simple2_thumbnail', - 'image' => 'simple2_image' + 'image' => 'simple2_image', + 'was_changed' => true, ], [ 'newProduct' => false, 'id' => 'product3', - 'qty' => '3' - ] + 'qty' => '3', + 'was_changed' => true, + ], + [ + 'newProduct' => false, + 'id' => 'product4', + 'status' => 'simple4_status', + 'sku' => 'simple2_sku', + 'name' => 'simple2_name', + 'price' => '3.33', + 'weight' => '5.55', + ], ]; $configurations = [ 'product2' => [ @@ -118,8 +129,8 @@ public function testAfterInitialize() ]; /** @var Product[]|\PHPUnit_Framework_MockObject_MockObject[] $productMocks */ $productMocks = [ - 'product2' => $this->getProductMock($configurations['product2'], true), - 'product3' => $this->getProductMock($configurations['product3']) + 'product2' => $this->getProductMock($configurations['product2'], true, true), + 'product3' => $this->getProductMock($configurations['product3'], false, true), ]; $productMock->expects(static::any()) @@ -167,26 +178,27 @@ public function testAfterInitialize() * @param bool $hasDataChanges * @return Product|\PHPUnit_Framework_MockObject_MockObject */ - protected function getProductMock(array $expectedData = null, $hasDataChanges = false) + protected function getProductMock(array $expectedData = null, $hasDataChanges = false, $wasChanged = false) { $productMock = $this->getMockBuilder(Product::class) ->disableOriginalConstructor() ->getMock(); - if ($expectedData !== null) { - $productMock->expects(static::once()) - ->method('addData') - ->with($expectedData) + if ($wasChanged !== false) { + if ($expectedData !== null) { + $productMock->expects(static::once()) + ->method('addData') + ->with($expectedData) + ->willReturnSelf(); + } + + $productMock->expects(static::any()) + ->method('hasDataChanges') + ->willReturn($hasDataChanges); + $productMock->expects($hasDataChanges ? static::once() : static::never()) + ->method('save') ->willReturnSelf(); } - - $productMock->expects(static::any()) - ->method('hasDataChanges') - ->willReturn($hasDataChanges); - $productMock->expects($hasDataChanges ? static::once() : static::never()) - ->method('save') - ->willReturnSelf(); - return $productMock; } } diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/dynamic-rows-configurable.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/dynamic-rows-configurable.js index ffabd9a8627df..c182d9f8216c0 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/dynamic-rows-configurable.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/dynamic-rows-configurable.js @@ -391,11 +391,11 @@ define([ 'small_image': row['small_image'], image: row.image, 'thumbnail': row.thumbnail, - 'attributes': attributesText + 'attributes': attributesText, + 'was_changed': true }; product[this.canEditField] = row.editable; product[this.newProductField] = row.newProduct; - tmpArray.push(product); }, this); diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php b/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php index 7e40bbd482f83..bdb2e409889ab 100644 --- a/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php +++ b/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php @@ -6,8 +6,8 @@ namespace Magento\Eav\Model\Entity\Attribute; -use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Api\AttributeValueFactory; +use Magento\Framework\Exception\LocalizedException; /** * Entity/Attribute/Model - attribute abstract @@ -595,11 +595,10 @@ public function isValueEmpty($value) { /** @var array $emptyStringTypes list of attribute types that treat empty string as a possible value */ $emptyStringTypes = ['int', 'decimal', 'datetime', 'varchar', 'text', 'static']; - $attributeType = $this->getBackend()->getType(); return (is_array($value) && count($value) == 0) || $value === null - || ($value === false && $attributeType != 'int') - || ($value === '' && in_array($attributeType, $emptyStringTypes)); + || ($value === false && $this->getBackend()->getType() != 'int') + || ($value === '' && in_array($this->getBackend()->getType(), $emptyStringTypes)); } /** diff --git a/app/code/Magento/Eav/Model/ResourceModel/AttributeLoader.php b/app/code/Magento/Eav/Model/ResourceModel/AttributeLoader.php new file mode 100644 index 0000000000000..439f550a2bf02 --- /dev/null +++ b/app/code/Magento/Eav/Model/ResourceModel/AttributeLoader.php @@ -0,0 +1,97 @@ +attributeRepository = $attributeRepository; + $this->metadataPool = $metadataPool; + $this->searchCriteriaBuilder = $searchCriteriaBuilder; + $this->attributeCache = $attributeCache; + } + + /** + * Get attributes list from attribute set + * + * @param string $entityType + * @param int $attributeSetId + * @return \Magento\Eav\Api\Data\AttributeInterface[]|\object[] + */ + public function getAttributes($entityType, $attributeSetId = null) + { + $suffix = self::ATTRIBUTE_SET_ID . '-' . ($attributeSetId ?: 'all'); + if ($attributes = $this->attributeCache->getAttributes($entityType, $suffix)) { + return $attributes; + } + + $metadata = $this->metadataPool->getMetadata($entityType); + + if ($attributeSetId === null) { + $criteria = $this->searchCriteriaBuilder->addFilter(self::ATTRIBUTE_SET_ID, null, 'neq')->create(); + } else { + $criteria = $this->searchCriteriaBuilder->addFilter(self::ATTRIBUTE_SET_ID, $attributeSetId)->create(); + } + + $searchResult = $this->attributeRepository->getList( + $metadata->getEavEntityType(), + $criteria + ); + $attributes = $searchResult->getItems(); + + $this->attributeCache->saveAttributes( + $entityType, + $attributes, + $suffix + ); + return $attributes; + } +} diff --git a/app/code/Magento/Eav/Model/ResourceModel/AttributePersistor.php b/app/code/Magento/Eav/Model/ResourceModel/AttributePersistor.php index 74373cb593c40..5e340595df986 100644 --- a/app/code/Magento/Eav/Model/ResourceModel/AttributePersistor.php +++ b/app/code/Magento/Eav/Model/ResourceModel/AttributePersistor.php @@ -113,13 +113,14 @@ public function processDeletes($entityType, $context) return; } $metadata = $this->metadataPool->getMetadata($entityType); + $linkField = $metadata->getLinkField(); foreach ($this->delete[$entityType] as $link => $data) { $attributeCodes = array_keys($data); foreach ($attributeCodes as $attributeCode) { /** @var AbstractAttribute $attribute */ $attribute = $this->attributeRepository->get($metadata->getEavEntityType(), $attributeCode); $conditions = [ - $metadata->getLinkField() . ' = ?' => $link, + $linkField . ' = ?' => $link, 'attribute_id = ?' => $attribute->getAttributeId() ]; foreach ($context as $scope) { @@ -147,6 +148,7 @@ public function processInserts($entityType, $context) return; } $metadata = $this->metadataPool->getMetadata($entityType); + $linkField = $metadata->getLinkField(); foreach ($this->insert[$entityType] as $link => $data) { foreach ($data as $attributeCode => $attributeValue) { /** @var AbstractAttribute $attribute */ @@ -155,7 +157,7 @@ public function processInserts($entityType, $context) $attributeCode ); $data = [ - $metadata->getLinkField() => $link, + $linkField => $link, 'attribute_id' => $attribute->getAttributeId(), 'value' => $this->prepareValue($entityType, $attributeValue, $attribute) ]; @@ -180,6 +182,7 @@ public function processUpdates($entityType, $context) return; } $metadata = $this->metadataPool->getMetadata($entityType); + $linkField = $metadata->getLinkField(); foreach ($this->update[$entityType] as $link => $data) { foreach ($data as $attributeCode => $attributeValue) { /** @var AbstractAttribute $attribute */ @@ -188,7 +191,7 @@ public function processUpdates($entityType, $context) $attributeCode ); $conditions = [ - $metadata->getLinkField() . ' = ?' => $link, + $linkField . ' = ?' => $link, 'attribute_id = ?' => $attribute->getAttributeId(), ]; foreach ($context as $scope) { diff --git a/app/code/Magento/Eav/Model/ResourceModel/CreateHandler.php b/app/code/Magento/Eav/Model/ResourceModel/CreateHandler.php index 1a8aaaf027f56..df411b6a21698 100644 --- a/app/code/Magento/Eav/Model/ResourceModel/CreateHandler.php +++ b/app/code/Magento/Eav/Model/ResourceModel/CreateHandler.php @@ -6,9 +6,10 @@ namespace Magento\Eav\Model\ResourceModel; use Magento\Eav\Api\AttributeRepositoryInterface as AttributeRepository; -use Magento\Framework\EntityManager\Operation\AttributeInterface; -use Magento\Framework\EntityManager\MetadataPool; use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\EntityManager\MetadataPool; +use Magento\Framework\EntityManager\Operation\AttributeInterface; use Magento\Framework\Model\Entity\ScopeResolver; /** @@ -42,40 +43,43 @@ class CreateHandler implements AttributeInterface */ private $scopeResolver; + /** + * @var AttributeLoader + */ + private $attributeLoader; + /** * @param AttributeRepository $attributeRepository * @param MetadataPool $metadataPool * @param SearchCriteriaBuilder $searchCriteriaBuilder * @param AttributePersistor $attributePersistor * @param ScopeResolver $scopeResolver + * @param AttributeLoader $attributeLoader */ public function __construct( AttributeRepository $attributeRepository, MetadataPool $metadataPool, SearchCriteriaBuilder $searchCriteriaBuilder, AttributePersistor $attributePersistor, - ScopeResolver $scopeResolver + ScopeResolver $scopeResolver, + AttributeLoader $attributeLoader = null ) { $this->attributeRepository = $attributeRepository; $this->metadataPool = $metadataPool; $this->searchCriteriaBuilder = $searchCriteriaBuilder; $this->attributePersistor = $attributePersistor; $this->scopeResolver = $scopeResolver; + $this->attributeLoader = $attributeLoader ?: ObjectManager::getInstance()->get(AttributeLoader::class); } /** * @param string $entityType + * @param int $attributeSetId * @return \Magento\Eav\Api\Data\AttributeInterface[] - * @throws \Exception */ - protected function getAttributes($entityType) + protected function getAttributes($entityType, $attributeSetId = null) { - $metadata = $this->metadataPool->getMetadata($entityType); - $searchResult = $this->attributeRepository->getList( - $metadata->getEavEntityType(), - $this->searchCriteriaBuilder->addFilter('attribute_set_id', null, 'neq')->create() - ); - return $searchResult->getItems(); + return $this->attributeLoader->getAttributes($entityType, $attributeSetId); } /** @@ -92,23 +96,28 @@ public function execute($entityType, $entityData, $arguments = []) $metadata = $this->metadataPool->getMetadata($entityType); if ($metadata->getEavEntityType()) { $processed = []; + $entityLinkField = $metadata->getLinkField(); + $attributeSetId = isset($entityData[AttributeLoader::ATTRIBUTE_SET_ID]) + ? $entityData[AttributeLoader::ATTRIBUTE_SET_ID] + : null; // @todo verify is it normal to not have attributer_set_id /** @var \Magento\Eav\Model\Entity\Attribute\AbstractAttribute $attribute */ - foreach ($this->getAttributes($entityType) as $attribute) { + foreach ($this->getAttributes($entityType, $attributeSetId) as $attribute) { if ($attribute->isStatic()) { continue; } - if (isset($entityData[$attribute->getAttributeCode()]) - && !is_array($entityData[$attribute->getAttributeCode()]) - && !$attribute->isValueEmpty($entityData[$attribute->getAttributeCode()]) + + $attributeCode = $attribute->getAttributeCode(); + if (isset($entityData[$attributeCode]) + && !is_array($entityData[$attributeCode]) + && !$attribute->isValueEmpty($entityData[$attributeCode]) ) { - $entityLinkField = $metadata->getLinkField(); $this->attributePersistor->registerInsert( $entityType, $entityData[$entityLinkField], - $attribute->getAttributeCode(), - $entityData[$attribute->getAttributeCode()] + $attributeCode, + $entityData[$attributeCode] ); - $processed[$attribute->getAttributeCode()] = $entityData[$attribute->getAttributeCode()]; + $processed[$attributeCode] = $entityData[$attributeCode]; } } $context = $this->scopeResolver->getEntityContext($entityType, $entityData); diff --git a/app/code/Magento/Eav/Model/ResourceModel/UpdateHandler.php b/app/code/Magento/Eav/Model/ResourceModel/UpdateHandler.php index 0f892a272fa1a..c775a24a03c46 100644 --- a/app/code/Magento/Eav/Model/ResourceModel/UpdateHandler.php +++ b/app/code/Magento/Eav/Model/ResourceModel/UpdateHandler.php @@ -54,6 +54,11 @@ class UpdateHandler implements AttributeInterface */ private $readHandler; + /** + * @var AttributeLoader + */ + private $attributeLoader; + /** * UpdateHandler constructor. * @param AttributeRepository $attributeRepository @@ -62,6 +67,7 @@ class UpdateHandler implements AttributeInterface * @param AttributePersistor $attributePersistor * @param ReadSnapshot $readSnapshot * @param ScopeResolver $scopeResolver + * @param AttributeLoader $attributeLoader */ public function __construct( AttributeRepository $attributeRepository, @@ -69,7 +75,8 @@ public function __construct( SearchCriteriaBuilder $searchCriteriaBuilder, AttributePersistor $attributePersistor, ReadSnapshot $readSnapshot, - ScopeResolver $scopeResolver + ScopeResolver $scopeResolver, + AttributeLoader $attributeLoader = null ) { $this->attributeRepository = $attributeRepository; $this->metadataPool = $metadataPool; @@ -77,22 +84,17 @@ public function __construct( $this->attributePersistor = $attributePersistor; $this->readSnapshot = $readSnapshot; $this->scopeResolver = $scopeResolver; + $this->attributeLoader = $attributeLoader ?: ObjectManager::getInstance()->get(AttributeLoader::class); } /** * @param string $entityType + * @param int $attributeSetId * @return \Magento\Eav\Api\Data\AttributeInterface[] - * @throws \Exception */ - protected function getAttributes($entityType) + protected function getAttributes($entityType, $attributeSetId = null) { - $metadata = $this->metadataPool->getMetadata($entityType); - - $searchResult = $this->attributeRepository->getList( - $metadata->getEavEntityType(), - $this->searchCriteriaBuilder->addFilter('attribute_set_id', null, 'neq')->create() - ); - return $searchResult->getItems(); + return $this->attributeLoader->getAttributes($entityType, $attributeSetId); } /** @@ -118,8 +120,11 @@ public function execute($entityType, $entityData, $arguments = []) $entityDataForSnapshot[$scope->getIdentifier()] = $entityData[$scope->getIdentifier()]; } } + $attributeSetId = isset($entityData[AttributeLoader::ATTRIBUTE_SET_ID]) + ? $entityData[AttributeLoader::ATTRIBUTE_SET_ID] + : null; // @todo verify is it normal to not have attributer_set_id $snapshot = $this->readSnapshot->execute($entityType, $entityDataForSnapshot); - foreach ($this->getAttributes($entityType) as $attribute) { + foreach ($this->getAttributes($entityType, $attributeSetId) as $attribute) { if ($attribute->isStatic()) { continue; } diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/AbstractAttributeTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/AbstractAttributeTest.php index f083839929170..ffd1ea386c08c 100644 --- a/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/AbstractAttributeTest.php +++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/AbstractAttributeTest.php @@ -207,7 +207,7 @@ public function testIsValueEmpty($isEmpty, $value, $attributeType) ] ); $backendModelMock->expects($this->any())->method('getType')->willReturn($attributeType); - $model->expects($this->once())->method('getBackend')->willReturn($backendModelMock); + $model->expects($this->any())->method('getBackend')->willReturn($backendModelMock); $this->assertEquals($isEmpty, $model->isValueEmpty($value)); } diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/Annotation/ApiDataFixture.php b/dev/tests/api-functional/framework/Magento/TestFramework/Annotation/ApiDataFixture.php index 5eeb7ddb61fa0..0ad53eeeb90d9 100644 --- a/dev/tests/api-functional/framework/Magento/TestFramework/Annotation/ApiDataFixture.php +++ b/dev/tests/api-functional/framework/Magento/TestFramework/Annotation/ApiDataFixture.php @@ -51,6 +51,7 @@ public function __construct($fixtureBaseDir) */ public function startTest(\PHPUnit_Framework_TestCase $test) { + \Magento\TestFramework\Helper\Bootstrap::getInstance()->reinitialize(); /** Apply method level fixtures if thy are available, apply class level fixtures otherwise */ $this->_applyFixtures($this->_getFixtures('method', $test) ?: $this->_getFixtures('class', $test)); } @@ -61,6 +62,9 @@ public function startTest(\PHPUnit_Framework_TestCase $test) public function endTest() { $this->_revertFixtures(); + /** @var $objectManager \Magento\TestFramework\ObjectManager */ + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $objectManager->get(\Magento\Eav\Model\Entity\AttributeCache::class)->clear(); } /** diff --git a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_shipping_method_and_items_categories.php b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_shipping_method_and_items_categories.php index ff547fc93c812..ef52555cad7fe 100644 --- a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_shipping_method_and_items_categories.php +++ b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_shipping_method_and_items_categories.php @@ -56,7 +56,7 @@ )->setId( 444 )->setAttributeSetId( - 5 + 4 )->setStoreId( 1 )->setWebsiteIds( From 6d57a2e922d1879ab69ffe344939be139f56b843 Mon Sep 17 00:00:00 2001 From: Arpita Barua Date: Tue, 18 Oct 2016 13:01:44 -0500 Subject: [PATCH 2/2] MAGETWO-59284: There is no Scope Selector on Product Grid - for 2.1.x - Backported code fix --- .../Adminhtml/Product/MassStatus.php | 13 +- .../Adminhtml/Product/MassStatusTest.php | 147 ++++++++++++++---- .../Unit/Controller/Adminhtml/ProductTest.php | 4 + .../Ui/view/base/web/js/grid/data-storage.js | 4 + 4 files changed, 133 insertions(+), 35 deletions(-) diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassStatus.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassStatus.php index 1f3345ee2f807..2757e3fcdfa54 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassStatus.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassStatus.php @@ -22,12 +22,12 @@ class MassStatus extends \Magento\Catalog\Controller\Adminhtml\Product /** * MassActions filter * - * @var Filter + * @var \Magento\Ui\Component\MassAction\Filter */ protected $filter; /** - * @var CollectionFactory + * @var \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory */ protected $collectionFactory; @@ -35,8 +35,8 @@ class MassStatus extends \Magento\Catalog\Controller\Adminhtml\Product * @param Action\Context $context * @param Builder $productBuilder * @param \Magento\Catalog\Model\Indexer\Product\Price\Processor $productPriceIndexerProcessor - * @param Filter $filter - * @param CollectionFactory $collectionFactory + * @param \Magento\Ui\Component\MassAction\Filter $filter + * @param \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $collectionFactory */ public function __construct( \Magento\Backend\App\Action\Context $context, @@ -81,6 +81,11 @@ public function execute() $productIds = $collection->getAllIds(); $storeId = (int) $this->getRequest()->getParam('store', 0); $status = (int) $this->getRequest()->getParam('status'); + $filters = (array)$this->getRequest()->getParam('filters', []); + + if (isset($filters['store_id'])) { + $storeId = (int)$filters['store_id']; + } try { $this->_validateMassStatus($productIds, $status); diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/MassStatusTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/MassStatusTest.php index 60bdb8c836583..c14514dcb2f09 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/MassStatusTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/MassStatusTest.php @@ -6,80 +6,165 @@ */ namespace Magento\Catalog\Test\Unit\Controller\Adminhtml\Product; -class MassStatusTest extends \Magento\Catalog\Test\Unit\Controller\Adminhtml\ProductTest +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Ui\Component\MassAction\Filter; +use Magento\Backend\Model\View\Result\Redirect; +use Magento\Catalog\Model\Indexer\Product\Price\Processor; +use Magento\Catalog\Controller\Adminhtml\Product\Builder; +use Magento\Framework\Data\Collection\AbstractDb; +use Magento\Catalog\Model\Product\Action; +use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory; +use Magento\Catalog\Controller\Adminhtml\Product\MassStatus; +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Framework\Controller\ResultFactory; +use Magento\Framework\App\Request\Http; +use Magento\Catalog\Model\Product; +use Magento\Framework\ObjectManager\ObjectManager as Manager; + +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class MassStatusTest extends \PHPUnit_Framework_TestCase { /** * @var \PHPUnit_Framework_MockObject_MockObject */ - protected $priceProcessor; + private $priceProcessorMock; + + /** + * @var \Magento\Catalog\Controller\Adminhtml\Product\MassStatus + */ + private $action; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $abstractDbMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $filterMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $requestMock; - /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Backend\Model\View\Result\Redirect */ - protected $resultRedirect; + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $actionMock; protected function setUp() { - $this->priceProcessor = $this->getMockBuilder('Magento\Catalog\Model\Indexer\Product\Price\Processor') + $objectManagerMock = $this->getMockBuilder(Manager::class) + ->disableOriginalConstructor() + ->getMock(); + + $objectManagerHelper = new ObjectManager($this); + $this->priceProcessorMock = $this->getMockBuilder(Processor::class) ->disableOriginalConstructor()->getMock(); - $productBuilder = $this->getMockBuilder('Magento\Catalog\Controller\Adminhtml\Product\Builder')->setMethods([ + $productBuilderMock = $this->getMockBuilder(Builder::class)->setMethods([ 'build', ])->disableOriginalConstructor()->getMock(); - $product = $this->getMockBuilder('\Magento\Catalog\Model\Product')->disableOriginalConstructor() + $this->requestMock = $this->getMockBuilder(Http::class)->setMethods( + ['getParam', 'getPost', 'getFullActionName', 'getPostValue'] + )->disableOriginalConstructor()->getMock(); + + $productMock = $this->getMockBuilder(Product::class)->disableOriginalConstructor() ->setMethods(['getTypeId', 'getStoreId', '__sleep', '__wakeup'])->getMock(); - $product->expects($this->any())->method('getTypeId')->will($this->returnValue('simple')); - $product->expects($this->any())->method('getStoreId')->will($this->returnValue('1')); - $productBuilder->expects($this->any())->method('build')->will($this->returnValue($product)); + $productMock->expects($this->any())->method('getTypeId')->will($this->returnValue('simple')); + $productMock->expects($this->any())->method('getStoreId')->will($this->returnValue('1')); + $productBuilderMock->expects($this->any())->method('build')->will($this->returnValue($productMock)); - $this->resultRedirect = $this->getMockBuilder('Magento\Backend\Model\View\Result\Redirect') + $resultRedirectMock = $this->getMockBuilder(Redirect::class) ->disableOriginalConstructor() ->getMock(); - $resultFactory = $this->getMockBuilder('Magento\Framework\Controller\ResultFactory') + $resultFactory = $this->getMockBuilder(ResultFactory::class) ->disableOriginalConstructor() ->setMethods(['create']) ->getMock(); $resultFactory->expects($this->atLeastOnce()) ->method('create') - ->with(\Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT) - ->willReturn($this->resultRedirect); + ->with(ResultFactory::TYPE_REDIRECT) + ->willReturn($resultRedirectMock); - $abstractDbMock = $this->getMockBuilder('Magento\Framework\Data\Collection\AbstractDb') + $this->abstractDbMock = $this->getMockBuilder(AbstractDb::class) ->disableOriginalConstructor() ->setMethods(['getAllIds', 'getResource']) ->getMock(); - $abstractDbMock->expects($this->any()) + $this->abstractDbMock->expects($this->any()) ->method('getAllIds') ->willReturn([]); - $filterMock = $this->getMockBuilder('Magento\Ui\Component\MassAction\Filter') + $this->filterMock = $this->getMockBuilder(Filter::class) ->disableOriginalConstructor() ->setMethods(['getCollection']) ->getMock(); - $filterMock->expects($this->any()) + $this->filterMock->expects($this->any()) ->method('getCollection') - ->willReturn($abstractDbMock); - - $collectionFactoryMock = $this->getMockBuilder('Magento\Catalog\Model\ResourceModel\Product\CollectionFactory') + ->willReturn($this->abstractDbMock); + $this->actionMock = $this->getMockBuilder(Action::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManagerMock->expects($this->any())->method('get')->willReturn($this->actionMock); + $collectionFactoryMock = $this->getMockBuilder(CollectionFactory::class) ->disableOriginalConstructor() ->setMethods(['create']) ->getMock(); $collectionFactoryMock->expects($this->any()) ->method('create') - ->willReturn($abstractDbMock); - - $additionalParams = ['resultFactory' => $resultFactory]; - $this->action = new \Magento\Catalog\Controller\Adminhtml\Product\MassStatus( - $this->initContext($additionalParams), - $productBuilder, - $this->priceProcessor, - $filterMock, - $collectionFactoryMock + ->willReturn($this->abstractDbMock); + $this->requestMock = $this->getMockBuilder(Http::class)->setMethods( + ['getParam', 'getPost', 'getFullActionName', 'getPostValue'] + )->disableOriginalConstructor()->getMock(); + + $this->action = $objectManagerHelper->getObject( + MassStatus::class, + [ + 'objectManager' => $objectManagerMock, + 'request' => $this->requestMock, + 'productBuilder' => $productBuilderMock, + 'filter' => $this->filterMock, + 'productPriceIndexerProcessor' => $this->priceProcessorMock, + 'collectionFactory' => $collectionFactoryMock, + 'resultFactory' => $resultFactory + ] ); + } public function testMassStatusAction() { - $this->priceProcessor->expects($this->once())->method('reindexList'); + $storeId = 1; + $status = Status::STATUS_DISABLED; + $filters = [ + 'store_id' => 2, + ]; + + $productIds = [3]; + + $this->filterMock->expects($this->once()) + ->method('getCollection') + ->willReturn($this->abstractDbMock); + $this->abstractDbMock->expects($this->once()) + ->method('getAllIds') + ->willReturn($productIds); + $this->requestMock->expects($this->exactly(3)) + ->method('getParam') + ->willReturnMap([ + ['store', 0, $storeId], + ['status', null, $status], + ['filters', [], $filters] + ]); + $this->actionMock->expects($this->once()) + ->method('updateAttributes'); + $this->priceProcessorMock->expects($this->once()) + ->method('reindexList'); + $this->action->execute(); } } diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/ProductTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/ProductTest.php index 13c89a0d34151..54257c4dfc95e 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/ProductTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/ProductTest.php @@ -9,12 +9,16 @@ abstract class ProductTest extends \PHPUnit_Framework_TestCase { /** @var \PHPUnit_Framework_MockObject_MockObject */ protected $context; + /** @var \Magento\Catalog\Controller\Product */ protected $action; + /** @var \Magento\Framework\View\Layout */ protected $layout; + /** @var \Magento\Backend\Model\Session|\PHPUnit_Framework_MockObject_MockObject */ protected $session; + /** @var \Magento\Framework\App\Request\Http|\PHPUnit_Framework_MockObject_MockObject */ protected $request; diff --git a/app/code/Magento/Ui/view/base/web/js/grid/data-storage.js b/app/code/Magento/Ui/view/base/web/js/grid/data-storage.js index d87b6b6b665ca..dca12f832cd15 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/data-storage.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/data-storage.js @@ -79,6 +79,10 @@ define([ getData: function (params, options) { var cachedRequest = this.getRequest(params); + if (params && params.filters && params.filters['store_id']) { + cachedRequest = false; + } + options = options || {}; return !options.refresh && cachedRequest ?