diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php index c7a0cd0c533b1..cbcbbd66897b1 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php @@ -18,6 +18,7 @@ use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface; use Magento\ImportExport\Model\Import\Entity\AbstractEntity; use Magento\Catalog\Model\Product\Visibility; + /** * Import entity product model * @SuppressWarnings(PHPMD.TooManyFields) @@ -1190,7 +1191,7 @@ protected function _saveLinks() } $linkKey = "{$productId}-{$linkedId}-{$linkId}"; - if(empty($productLinkKeys[$linkKey])) { + if (empty($productLinkKeys[$linkKey])) { $productLinkKeys[$linkKey] = $nextLinkId; } if (!isset($linkRows[$linkKey])) { @@ -2087,65 +2088,15 @@ protected function _saveProductWebsites(array $websiteData) protected function _saveStockItem() { $indexer = $this->indexerRegistry->get('catalog_product_category'); + /** @var $stockResource \Magento\CatalogInventory\Model\ResourceModel\Stock\Item */ $stockResource = $this->_stockResItemFac->create(); $entityTable = $stockResource->getMainTable(); - while ($bunch = $this->_dataSourceModel->getNextBunch()) { - $stockData = []; - $productIdsToReindex = []; - // Format bunch to stock data rows - foreach ($bunch as $rowNum => $rowData) { - if (!$this->isRowAllowedToImport($rowData, $rowNum)) { - continue; - } - $row = []; - $row['product_id'] = $this->skuProcessor->getNewSku($rowData[self::COL_SKU])['entity_id']; - $productIdsToReindex[] = $row['product_id']; - - $row['website_id'] = $this->stockConfiguration->getDefaultScopeId(); - $row['stock_id'] = $this->stockRegistry->getStock($row['website_id'])->getStockId(); - - $stockItemDo = $this->stockRegistry->getStockItem($row['product_id'], $row['website_id']); - $existStockData = $stockItemDo->getData(); - - $row = array_merge( - $this->defaultStockData, - array_intersect_key($existStockData, $this->defaultStockData), - array_intersect_key($rowData, $this->defaultStockData), - $row - ); - - if ($this->stockConfiguration->isQty( - $this->skuProcessor->getNewSku($rowData[self::COL_SKU])['type_id'] - )) { - $stockItemDo->setData($row); - $row['is_in_stock'] = $this->stockStateProvider->verifyStock($stockItemDo); - if ($this->stockStateProvider->verifyNotification($stockItemDo)) { - $row['low_stock_date'] = $this->dateTime->gmDate( - 'Y-m-d H:i:s', - (new \DateTime())->getTimestamp() - ); - } - $row['stock_status_changed_auto'] = - (int) !$this->stockStateProvider->verifyStock($stockItemDo); - } else { - $row['qty'] = 0; - } - if (!isset($stockData[$rowData[self::COL_SKU]])) { - $stockData[$rowData[self::COL_SKU]] = $row; - } - } - - // Insert rows - if (!empty($stockData)) { - $this->_connection->insertOnDuplicate($entityTable, array_values($stockData)); - } - - if ($productIdsToReindex) { - $indexer->reindexList($productIdsToReindex); - } + while ($bunch = $this->_dataSourceModel->getNextBunch()) { + $this->formatBunchToStockDataRows($bunch, $entityTable, $indexer); } + return $this; } @@ -2739,4 +2690,74 @@ private function getProductIdentifierField() } return $this->productEntityIdentifierField; } + + /** + * Get stock data rows from bunch. + * + * @param array $bunch + * @param string $entityTable + * @param \Magento\Framework\Indexer\IndexerInterface $indexer + * @return void + */ + private function formatBunchToStockDataRows( + $bunch, + $entityTable, + \Magento\Framework\Indexer\IndexerInterface $indexer + ) { + $stockData = []; + $productIdsToReindex = []; + + foreach ($bunch as $rowNum => $rowData) { + if (!$this->isRowAllowedToImport($rowData, $rowNum)) { + continue; + } + + $row = []; + $row['product_id'] = $this->skuProcessor->getNewSku($rowData[self::COL_SKU])['entity_id']; + $row['website_id'] = $this->stockConfiguration->getDefaultScopeId(); + $row['stock_id'] = $this->stockRegistry->getStock($row['website_id'])->getStockId(); + + $productIdsToReindex[] = $row['product_id']; + $stockItemDo = $this->stockRegistry->getStockItem($row['product_id'], $row['website_id']); + $existStockData = $stockItemDo->getData(); + + $row = array_merge( + $this->defaultStockData, + array_intersect_key($existStockData, $this->defaultStockData), + array_intersect_key($rowData, $this->defaultStockData), + $row + ); + + if ($this->stockConfiguration->isQty( + $this->skuProcessor->getNewSku($rowData[self::COL_SKU])['type_id'] + ) + ) { + $stockItemDo->setData($row); + $row['is_in_stock'] = $this->stockStateProvider->verifyStock($stockItemDo); + if ($this->stockStateProvider->verifyNotification($stockItemDo)) { + $row['low_stock_date'] = $this->dateTime->gmDate( + 'Y-m-d H:i:s', + (new \DateTime())->getTimestamp() + ); + } + $row['stock_status_changed_auto'] = + (int)!$this->stockStateProvider->verifyStock($stockItemDo); + } else { + $row['qty'] = 0; + } + + if (!isset($stockData[$rowData[self::COL_SKU]])) { + $stockData[$rowData[self::COL_SKU]] = $row; + } + } + + // Insert rows + if (!empty($stockData)) { + $this->_connection->insertOnDuplicate($entityTable, array_values($stockData)); + } + + if ($productIdsToReindex && !$indexer->isScheduled()) { + $indexer->reindexList($productIdsToReindex); + } + } } diff --git a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php index ec2bd15f10210..a6d27eb557eef 100644 --- a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php +++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php @@ -5,9 +5,7 @@ */ namespace Magento\CatalogImportExport\Test\Unit\Model\Import; -use Magento\CatalogImportExport\Model\Import\Product; use Magento\Framework\App\Filesystem\DirectoryList; -use Magento\Framework\Stdlib\DateTime; use Magento\ImportExport\Model\Import; /** @@ -398,7 +396,7 @@ protected function setUp() 'data' => $this->data ] ); - $reflection = new \ReflectionClass('\Magento\CatalogImportExport\Model\Import\Product'); + $reflection = new \ReflectionClass(\Magento\CatalogImportExport\Model\Import\Product::class); $reflectionProperty = $reflection->getProperty('metadataPool'); $reflectionProperty->setAccessible(true); $reflectionProperty->setValue($this->importProduct, $metadataPoolMock); @@ -410,7 +408,7 @@ protected function setUp() protected function _objectConstructor() { $this->optionFactory = $this->getMock( - '\Magento\CatalogImportExport\Model\Import\Product\OptionFactory', + \Magento\CatalogImportExport\Model\Import\Product\OptionFactory::class, ['create'], [], '', @@ -1683,4 +1681,89 @@ protected function createModelMockWithErrorAggregator(array $methods = [], array return $importProduct; } + + /** + * Test indexer not run reindexList in update by schedule mode. + * + * @return void + */ + public function testStockItemReindexListNotCall() + { + $indexer = $this->getMockBuilder(\Magento\Framework\Indexer\IndexerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $stockResource = $this->getMockBuilder(\Magento\CatalogInventory\Model\ResourceModel\Stock\Item::class) + ->disableOriginalConstructor() + ->getMock(); + + $stock = $this->getMockBuilder(\Magento\CatalogInventory\Api\Data\StockInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $stockItem = $this->getMockBuilder(\Magento\CatalogInventory\Api\Data\StockItemInterface::class) + ->setMethods(['getData']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->indexerRegistry->expects($this->once()) + ->method('get') + ->with('catalog_product_category') + ->willReturn($indexer); + + $this->_stockResItemFac->expects($this->once()) + ->method('create') + ->willReturn($stockResource); + + $stockResource->expects($this->once()) + ->method('getMainTable') + ->willReturn('mainTable'); + + $this->_dataSourceModel->expects($this->atLeastOnce()) + ->method('getNextBunch') + ->willReturnOnConsecutiveCalls( + [ + 0 => [ + 'sku' => 'product_dynamic', + 'product_type' => 'simple', + '_attribute_set' => 'attributeSet1' + ] + ], + [] + ); + + $this->validator->expects($this->once()) + ->method('isValid') + ->willReturn(true); + + $this->skuProcessor->expects($this->atLeastOnce()) + ->method('getNewSku') + ->willReturn([ + 'sku' => 'product_dynamic_3326', + 'type_id' => 'simple', + 'attr_set_code' => 'attributeSet1', + 'entity_id' => 1 + ]); + + $this->stockRegistry->expects($this->once()) + ->method('getStock') + ->willReturn($stock); + + $this->stockRegistry->expects($this->once()) + ->method('getStockItem') + ->willReturn($stockItem); + + $stockItem->expects($this->once()) + ->method('getData') + ->willReturn([]); + + $indexer->expects($this->once()) + ->method('isScheduled') + ->willReturn(true); + + $indexer->expects($this->never()) + ->method('reindexList'); + + $this->invokeMethod($this->importProduct, '_saveStockItem'); + } } diff --git a/app/code/Magento/ImportExport/Model/Import.php b/app/code/Magento/ImportExport/Model/Import.php index eeabb7d99aa49..3bd1446fd26b6 100644 --- a/app/code/Magento/ImportExport/Model/Import.php +++ b/app/code/Magento/ImportExport/Model/Import.php @@ -612,7 +612,9 @@ public function invalidateIndex() foreach (array_keys($relatedIndexers) as $indexerId) { try { $indexer = $this->indexerRegistry->get($indexerId); - $indexer->invalidate(); + if (!$indexer->isScheduled()) { + $indexer->invalidate(); + } } catch (\InvalidArgumentException $e) { } } diff --git a/app/code/Magento/Swatches/Block/Product/Renderer/Configurable.php b/app/code/Magento/Swatches/Block/Product/Renderer/Configurable.php index 8a6438a57fddb..c54c49a2a2b5d 100644 --- a/app/code/Magento/Swatches/Block/Product/Renderer/Configurable.php +++ b/app/code/Magento/Swatches/Block/Product/Renderer/Configurable.php @@ -18,6 +18,8 @@ use Magento\Swatches\Helper\Data as SwatchData; use Magento\Swatches\Helper\Media; use Magento\Swatches\Model\Swatch; +use Magento\Framework\App\ObjectManager; +use Magento\Swatches\Model\SwatchAttributesProvider; /** * Swatch renderer block @@ -60,10 +62,17 @@ class Configurable extends \Magento\ConfigurableProduct\Block\Product\View\Type\ /** * Indicate if product has one or more Swatch attributes * + * @deprecated unused + * * @var boolean */ protected $isProductHasSwatchAttribute; + /** + * @var SwatchAttributesProvider + */ + private $swatchAttributesProvider; + /** * @param Context $context * @param ArrayUtils $arrayUtils @@ -76,6 +85,7 @@ class Configurable extends \Magento\ConfigurableProduct\Block\Product\View\Type\ * @param SwatchData $swatchHelper * @param Media $swatchMediaHelper * @param array $data other data + * @param SwatchAttributesProvider $swatchAttributesProvider * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -89,11 +99,13 @@ public function __construct( ConfigurableAttributeData $configurableAttributeData, SwatchData $swatchHelper, Media $swatchMediaHelper, - array $data = [] + array $data = [], + SwatchAttributesProvider $swatchAttributesProvider = null ) { $this->swatchHelper = $swatchHelper; $this->swatchMediaHelper = $swatchMediaHelper; - + $this->swatchAttributesProvider = $swatchAttributesProvider + ?: ObjectManager::getInstance()->get(SwatchAttributesProvider::class); parent::__construct( $context, $arrayUtils, @@ -201,6 +213,9 @@ protected function getSwatchAttributesData() } /** + * @deprecated unused + * @see isProductHasSwatchAttribute(). + * * @codeCoverageIgnore * @return void */ @@ -209,6 +224,16 @@ protected function initIsProductHasSwatchAttribute() $this->isProductHasSwatchAttribute = $this->swatchHelper->isProductHasSwatch($this->getProduct()); } + /** + * @codeCoverageIgnore + * @return bool + */ + protected function isProductHasSwatchAttribute() + { + $swatchAttributes = $this->swatchAttributesProvider->provide($this->getProduct()); + return count($swatchAttributes) > 0; + } + /** * Add Swatch Data for attribute * @@ -371,7 +396,6 @@ protected function getConfigurableOptionsIds(array $attributeData) */ protected function _toHtml() { - $this->initIsProductHasSwatchAttribute(); $this->setTemplate( $this->getRendererTemplate() ); @@ -384,7 +408,7 @@ protected function _toHtml() */ protected function getRendererTemplate() { - return $this->isProductHasSwatchAttribute ? + return $this->isProductHasSwatchAttribute() ? self::SWATCH_RENDERER_TEMPLATE : self::CONFIGURABLE_RENDERER_TEMPLATE; } diff --git a/app/code/Magento/Swatches/Block/Product/Renderer/Listing/Configurable.php b/app/code/Magento/Swatches/Block/Product/Renderer/Listing/Configurable.php index 3a6193193d410..be9c3a0d00c24 100644 --- a/app/code/Magento/Swatches/Block/Product/Renderer/Listing/Configurable.php +++ b/app/code/Magento/Swatches/Block/Product/Renderer/Listing/Configurable.php @@ -43,7 +43,7 @@ protected function _toHtml() protected function getHtmlOutput() { $output = ''; - if ($this->isProductHasSwatchAttribute) { + if ($this->isProductHasSwatchAttribute()) { $output = parent::getHtmlOutput(); } diff --git a/app/code/Magento/Swatches/Helper/Data.php b/app/code/Magento/Swatches/Helper/Data.php index 42c36d5b5bf4a..812bc0468bf45 100644 --- a/app/code/Magento/Swatches/Helper/Data.php +++ b/app/code/Magento/Swatches/Helper/Data.php @@ -8,16 +8,16 @@ use Magento\Catalog\Helper\Image; use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory; use Magento\ConfigurableProduct\Model\Product\Type\Configurable; -use Magento\Framework\App\Helper\Context; use Magento\Catalog\Api\Data\ProductInterface as Product; use Magento\Catalog\Model\Product as ModelProduct; use Magento\Store\Model\StoreManagerInterface; use Magento\Swatches\Model\ResourceModel\Swatch\CollectionFactory as SwatchCollectionFactory; use Magento\Swatches\Model\Swatch; use Magento\Catalog\Model\ResourceModel\Eav\Attribute; -use Magento\Framework\Exception\InputException; use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\ResourceModel\Product\Collection as ProductCollection; +use Magento\Framework\App\ObjectManager; +use Magento\Swatches\Model\SwatchAttributesProvider; /** * Class Helper Data @@ -63,6 +63,11 @@ class Data */ protected $imageHelper; + /** + * @var SwatchAttributesProvider + */ + private $swatchAttributesProvider; + /** * Data key which should populated to Attribute entity from "additional_data" field * @@ -80,19 +85,23 @@ class Data * @param StoreManagerInterface $storeManager * @param SwatchCollectionFactory $swatchCollectionFactory * @param Image $imageHelper + * @param SwatchAttributesProvider $swatchAttributesProvider */ public function __construct( CollectionFactory $productCollectionFactory, ProductRepositoryInterface $productRepository, StoreManagerInterface $storeManager, SwatchCollectionFactory $swatchCollectionFactory, - Image $imageHelper + Image $imageHelper, + SwatchAttributesProvider $swatchAttributesProvider = null ) { $this->productCollectionFactory = $productCollectionFactory; $this->productRepository = $productRepository; $this->storeManager = $storeManager; $this->swatchCollectionFactory = $swatchCollectionFactory; $this->imageHelper = $imageHelper; + $this->swatchAttributesProvider = $swatchAttributesProvider + ?: ObjectManager::getInstance()->get(SwatchAttributesProvider::class); } /** @@ -335,14 +344,8 @@ private function getAllSizeImages(ModelProduct $product, $imageFile) */ private function getSwatchAttributes(Product $product) { - $attributes = $this->getAttributesFromConfigurable($product); - $result = []; - foreach ($attributes as $attribute) { - if ($this->isSwatchAttribute($attribute)) { - $result[] = $attribute; - } - } - return $result; + $swatchAttributes = $this->swatchAttributesProvider->provide($product); + return $swatchAttributes; } /** @@ -447,7 +450,8 @@ private function addFallbackOptions(array $fallbackValues, array $swatches) */ public function isProductHasSwatch(Product $product) { - return sizeof($this->getSwatchAttributes($product)); + $swatchAttributes = $this->getSwatchAttributes($product); + return count($swatchAttributes) > 0; } /** diff --git a/app/code/Magento/Swatches/Model/SwatchAttributeCodes.php b/app/code/Magento/Swatches/Model/SwatchAttributeCodes.php new file mode 100644 index 0000000000000..87a095c2f47ca --- /dev/null +++ b/app/code/Magento/Swatches/Model/SwatchAttributeCodes.php @@ -0,0 +1,122 @@ +cache = $cache; + $this->resourceConnection = $resourceConnection; + $this->cacheKey = $cacheKey; + $this->cacheTags = $cacheTags; + } + + /** + * Returns list of known swatch attribute codes. Check cache and database. + * + * @return array + */ + public function getCodes() + { + if ($this->swatchAttributeCodes === null) { + $swatchAttributeCodesCache = $this->cache->load($this->cacheKey); + if (false === $swatchAttributeCodesCache) { + $swatchAttributeCodes = $this->loadSwatchAttributeCodes(); + $this->cache->save(json_encode($swatchAttributeCodes), $this->cacheKey, $this->cacheTags); + } else { + $swatchAttributeCodes = json_decode($swatchAttributeCodesCache, true); + } + $this->swatchAttributeCodes = $swatchAttributeCodes; + } + + return $this->swatchAttributeCodes; + } + + /** + * Returns list of known swatch attributes. + * + * @return array + */ + private function loadSwatchAttributeCodes() + { + $select = $this->resourceConnection->getConnection()->select() + ->from( + ['a' => $this->resourceConnection->getTableName('eav_attribute')], + [ + 'attribute_id' => 'a.attribute_id', + 'attribute_code' => 'a.attribute_code', + ] + )->where( + 'a.attribute_id IN (?)', + new \Zend_Db_Expr(sprintf('(%s)', $this->getAttributeIdsSelect())) + ); + $result = $this->resourceConnection->getConnection()->fetchPairs($select); + return $result; + } + + /** + * Returns Select for attributes Ids. + * + * @return Select + */ + private function getAttributeIdsSelect() + { + return $this->resourceConnection->getConnection()->select() + ->from( + ['o' => $this->resourceConnection->getTableName('eav_attribute_option')], + ['attribute_id' => 'o.attribute_id'] + )->join( + ['s' => $this->resourceConnection->getTableName('eav_attribute_option_swatch')], + 'o.option_id = s.option_id', + [] + ); + } +} diff --git a/app/code/Magento/Swatches/Model/SwatchAttributesProvider.php b/app/code/Magento/Swatches/Model/SwatchAttributesProvider.php new file mode 100644 index 0000000000000..e0d435d8b838c --- /dev/null +++ b/app/code/Magento/Swatches/Model/SwatchAttributesProvider.php @@ -0,0 +1,69 @@ + Attribute[]] + */ + private $attributesPerProduct; + + /** + * @param Configurable $typeConfigurable + * @param SwatchAttributeCodes $swatchAttributeCodes + */ + public function __construct( + Configurable $typeConfigurable, + SwatchAttributeCodes $swatchAttributeCodes + ) { + $this->typeConfigurable = $typeConfigurable; + $this->swatchAttributeCodes = $swatchAttributeCodes; + } + + /** + * Provide list of swatch attributes for product. If product is not configurable return empty array. + * + * @param Product $product + * @return Attribute[] + */ + public function provide(Product $product) + { + if ($product->getTypeId() !== Configurable::TYPE_CODE) { + return []; + } + if (!isset($this->attributesPerProduct[$product->getId()])) { + $configurableAttributes = $this->typeConfigurable->getConfigurableAttributes($product); + $swatchAttributeIds = array_keys($this->swatchAttributeCodes->getCodes()); + $swatchAttributes = []; + foreach ($configurableAttributes as $configurableAttribute) { + if (in_array($configurableAttribute->getAttributeId(), $swatchAttributeIds)) { + $swatchAttributes[$configurableAttribute->getAttributeId()] + = $configurableAttribute->getProductAttribute(); + } + } + $this->attributesPerProduct[$product->getId()] = $swatchAttributes; + } + return $this->attributesPerProduct[$product->getId()]; + } +} diff --git a/app/code/Magento/Swatches/Test/Unit/Helper/DataTest.php b/app/code/Magento/Swatches/Test/Unit/Helper/DataTest.php index 4bc35c259099e..ff98da76c5548 100644 --- a/app/code/Magento/Swatches/Test/Unit/Helper/DataTest.php +++ b/app/code/Magento/Swatches/Test/Unit/Helper/DataTest.php @@ -5,6 +5,9 @@ */ namespace Magento\Swatches\Test\Unit\Helper; +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class DataTest extends \PHPUnit_Framework_TestCase { /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Catalog\Helper\Image */ @@ -43,23 +46,26 @@ class DataTest extends \PHPUnit_Framework_TestCase /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Catalog\Api\ProductRepositoryInterface */ protected $productRepoMock; + /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Swatches\Model\SwatchAttributesProvider */ + private $swatchAttributesProviderMock; + protected function setUp() { $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $this->imageHelperMock = $this->getMock('\Magento\Catalog\Helper\Image', [], [], '', false); + $this->imageHelperMock = $this->getMock(\Magento\Catalog\Helper\Image::class, [], [], '', false); $this->productCollectionFactoryMock = $this->getMock( - '\Magento\Catalog\Model\ResourceModel\Product\CollectionFactory', + \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory::class, ['create'], [], '', false ); - $this->productMock = $this->getMock('\Magento\Catalog\Model\Product', [], [], '', false); + $this->productMock = $this->getMock(\Magento\Catalog\Model\Product::class, [], [], '', false); $this->productCollectionMock = $this->objectManager->getCollectionMock( - '\Magento\Catalog\Model\ResourceModel\Product\Collection', + \Magento\Catalog\Model\ResourceModel\Product\Collection::class, [ $this->productMock, $this->productMock, @@ -67,35 +73,55 @@ protected function setUp() ); $this->configurableMock = $this->getMock( - '\Magento\ConfigurableProduct\Model\Product\Type\Configurable', + \Magento\ConfigurableProduct\Model\Product\Type\Configurable::class, [], [], '', false ); $this->productModelFactoryMock = $this->getMock( - '\Magento\Catalog\Model\ProductFactory', + \Magento\Catalog\Model\ProductFactory::class, ['create'], [], '', false ); - $this->productRepoMock = $this->getMock('\Magento\Catalog\Api\ProductRepositoryInterface', [], [], '', false); + $this->productRepoMock = $this->getMock( + \Magento\Catalog\Api\ProductRepositoryInterface::class, + [], + [], + '', + false + ); - $this->storeManagerMock = $this->getMock('\Magento\Store\Model\StoreManager', [], [], '', false); + $this->storeManagerMock = $this->getMock(\Magento\Store\Model\StoreManager::class, [], [], '', false); $this->swatchCollectionFactoryMock = $this->getMock( - '\Magento\Swatches\Model\ResourceModel\Swatch\CollectionFactory', + \Magento\Swatches\Model\ResourceModel\Swatch\CollectionFactory::class, ['create'], [], '', false ); - $this->attributeMock = $this->getMock('\Magento\Catalog\Model\ResourceModel\Eav\Attribute', [], [], '', false); + $this->attributeMock = $this->getMock( + \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class, + [], + [], + '', + false + ); + + $this->swatchAttributesProviderMock = $this->getMock( + \Magento\Swatches\Model\SwatchAttributesProvider::class, + ['provide'], + [], + '', + false + ); $this->swatchHelperObject = $this->objectManager->getObject( - '\Magento\Swatches\Helper\Data', + \Magento\Swatches\Helper\Data::class, [ 'productCollectionFactory' => $this->productCollectionFactoryMock, 'configurable' => $this->configurableMock, @@ -103,6 +129,7 @@ protected function setUp() 'storeManager' => $this->storeManagerMock, 'swatchCollectionFactory' => $this->swatchCollectionFactoryMock, 'imageHelper' => $this->imageHelperMock, + 'swatchAttributesProvider' => $this->swatchAttributesProviderMock, ] ); } @@ -114,6 +141,7 @@ public function dataForAdditionalData() 'update_product_preview_image' => 1, 'use_product_image_for_swatch' => 0 ]; + return [ [ serialize($additionalData), @@ -165,6 +193,7 @@ public function dataForAssembleEavAttribute() 'update_product_preview_image' => 1, 'use_product_image_for_swatch' => 0 ]; + return [ [ serialize($additionalData), @@ -198,7 +227,7 @@ public function testLoadFirstVariationWithSwatchImage($imageTypes, $expected, $r if ($expected === false) { $this->assertFalse($result); } else { - $this->assertInstanceOf('\Magento\Catalog\Model\Product', $result); + $this->assertInstanceOf(\Magento\Catalog\Model\Product::class, $result); } } @@ -212,7 +241,7 @@ public function dataForVariationWithSwatchImage() 'thumbnail' => '/m/a/magento.png', 'swatch_image' => '/m/a/magento.png', //important ], - '\Magento\Catalog\Model\Product', + \Magento\Catalog\Model\Product::class, ['color' => 31] ], [ @@ -257,7 +286,7 @@ public function testLoadFirstVariationWithImage($imageTypes, $expected, $require if ($expected === false) { $this->assertFalse($result); } else { - $this->assertInstanceOf('\Magento\Catalog\Model\Product', $result); + $this->assertInstanceOf(\Magento\Catalog\Model\Product::class, $result); } } @@ -271,7 +300,7 @@ public function dataForVariationWithImage() 'thumbnail' => '/m/a/magento.png', 'swatch_image' => '/m/a/magento.png', ], - '\Magento\Catalog\Model\Product', + \Magento\Catalog\Model\Product::class, ['color' => 31] ], [ @@ -327,9 +356,9 @@ public function testGetProductMediaGallery($mediaGallery, $image) ->with(95) ->willReturn($this->productMock); - $mediaObject = $this->getMock('\Magento\Framework\DataObject', [], [], '', false); + $mediaObject = $this->getMock(\Magento\Framework\DataObject::class, [], [], '', false); $iterator = new \ArrayIterator([$mediaObject]); - $mediaCollectionMock = $this->getMock('\Magento\Framework\Data\Collection', [], [], '', false); + $mediaCollectionMock = $this->getMock(\Magento\Framework\Data\Collection::class, [], [], '', false); $mediaCollectionMock->expects($this->any())->method('getIterator')->willReturn($iterator); $mediaObject->method('getData')->withConsecutive( ['value_id'], @@ -373,8 +402,11 @@ public function dataForMediaGallery() protected function getSwatchAttributes() { $this->getAttributesFromConfigurable(); - $this->attributeMock->method('hasData')->with('swatch_input_type')->willReturn(true); - $this->attributeMock->method('getData')->with('swatch_input_type')->willReturn('visual'); + $returnFromProvideMethod = [$this->attributeMock]; + $this->swatchAttributesProviderMock + ->method('provide') + ->with($this->productMock) + ->willReturn($returnFromProvideMethod); } protected function getUsedProducts(array $attributes) @@ -384,10 +416,10 @@ protected function getUsedProducts(array $attributes) ->method('getTypeInstance') ->willReturn($this->configurableMock); - $product1 = $this->getMock('\Magento\Catalog\Model\Product', ['hasData'], [], '', false); + $product1 = $this->getMock(\Magento\Catalog\Model\Product::class, ['hasData'], [], '', false); $product1->setData($attributes); - $product2 = $this->getMock('\Magento\Catalog\Model\Product', ['hasData'], [], '', false); + $product2 = $this->getMock(\Magento\Catalog\Model\Product::class, ['hasData'], [], '', false); $product2->setData($attributes); $simpleProducts = [$product2, $product1]; @@ -399,13 +431,8 @@ protected function getUsedProducts(array $attributes) protected function getAttributesFromConfigurable() { - $this->productMock - ->expects($this->atLeastOnce()) - ->method('getTypeInstance') - ->willReturn($this->configurableMock); - $confAttribute = $this->getMock( - '\Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute', + \Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute::class, [], [], '', @@ -442,7 +469,7 @@ protected function addfilterByParent() ->with('catalog_product_relation') ->willReturn('catalog_product_relation'); - $zendDbSelectMock = $this->getMock('Magento\Framework\DB\Select', [], [], '', false); + $zendDbSelectMock = $this->getMock(\Magento\Framework\DB\Select::class, [], [], '', false); $this->productCollectionMock->method('getSelect')->willReturn($zendDbSelectMock); $zendDbSelectMock->method('join')->willReturn($zendDbSelectMock); @@ -451,7 +478,7 @@ protected function addfilterByParent() public function dataForCreateSwatchProduct() { - $productMock = $this->getMock('\Magento\Catalog\Model\Product', [], [], '', false); + $productMock = $this->getMock(\Magento\Catalog\Model\Product::class, [], [], '', false); return [ [ @@ -487,7 +514,7 @@ public function dataForCreateSwatchProduct() public function dataForCreateSwatchProductByFallback() { - $productMock = $this->getMock('\Magento\Catalog\Model\Product', [], [], '', false); + $productMock = $this->getMock(\Magento\Catalog\Model\Product::class, [], [], '', false); return [ [ @@ -504,49 +531,27 @@ public function dataForCreateSwatchProductByFallback() */ public function testGetSwatchAttributesAsArray($optionsArray, $attributeData, $expected) { - $configurable = $this->getMock( - '\Magento\ConfigurableProduct\Model\Product\Type\Configurable', - [], - [], - '', - false - ); + $this->swatchAttributesProviderMock + ->method('provide') + ->with($this->productMock) + ->willReturn([$this->attributeMock]); - $this->productMock - ->expects($this->atLeastOnce()) - ->method('getTypeInstance') - ->willReturn($configurable); + $storeId = 1; - $confAttribute = $this->getMock( - '\Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute', + $this->attributeMock->method('setStoreId')->with($storeId)->will($this->returnSelf()); + $storeMock = $this->getMock(\Magento\Store\Model\Store::class, [], [], '', false); + $storeMock->method('getId')->willReturn($storeId); + $this->storeManagerMock->method('getStore')->willReturn($storeMock); + + $this->attributeMock->method('getData')->with('')->willReturn($attributeData); + + $sourceMock = $this->getMock( + \Magento\Eav\Model\Entity\Attribute\Source\AbstractSource::class, [], [], '', false ); - - $configurable - ->expects($this->atLeastOnce()) - ->method('getConfigurableAttributes') - ->with($this->productMock) - ->willReturn([$confAttribute]); - - $confAttribute - ->expects($this->atLeastOnce()) - ->method('__call') - ->with('getProductAttribute') - ->willReturn($this->attributeMock); - - $this->attributeMock->method('setStoreId')->will($this->returnSelf()); - $storeMock = $this->getMock('\Magento\Store\Model\Store', [], [], '', false); - $storeMock->method('getId')->willReturn(1); - $this->storeManagerMock->method('getStore')->willReturn($storeMock); - - $this->attributeMock->method('hasData')->with('swatch_input_type')->willReturn(true); - $this->attributeMock->expects($this->at(1))->method('getData')->with('swatch_input_type')->willReturn('visual'); - $this->attributeMock->expects($this->at(3))->method('getData')->with('')->willReturn($attributeData); - - $sourceMock = $this->getMock('\Magento\Eav\Model\Entity\Attribute\Source\AbstractSource', [], [], '', false); $sourceMock->expects($this->any())->method('getAllOptions')->with(false)->willReturn($optionsArray); $this->attributeMock->method('getSource')->willReturn($sourceMock); @@ -602,7 +607,7 @@ public function dataForGettingSwatchAsArray() public function testGetSwatchesByOptionsIdIf1() { - $swatchMock = $this->getMock('\Magento\Swatches\Model\Swatch', [], [], '', false); + $swatchMock = $this->getMock(\Magento\Swatches\Model\Swatch::class, [], [], '', false); $optionsData = [ [ @@ -619,7 +624,7 @@ public function testGetSwatchesByOptionsIdIf1() $swatchMock->expects($this->at(2))->method('getData')->with('')->willReturn($optionsData[0]); $swatchCollectionMock = $this->objectManager->getCollectionMock( - '\Magento\Swatches\Model\ResourceModel\Swatch\Collection', + \Magento\Swatches\Model\ResourceModel\Swatch\Collection::class, [ $swatchMock, ] @@ -628,7 +633,7 @@ public function testGetSwatchesByOptionsIdIf1() $swatchCollectionMock->method('addFilterByOptionsIds')->with([35])->will($this->returnSelf()); - $storeMock = $this->getMock('\Magento\Store\Model\Store', [], [], '', false); + $storeMock = $this->getMock(\Magento\Store\Model\Store::class, [], [], '', false); $this->storeManagerMock->method('getStore')->willReturn($storeMock); $storeMock->method('getId')->willReturn(1); @@ -637,7 +642,7 @@ public function testGetSwatchesByOptionsIdIf1() public function testGetSwatchesByOptionsIdIf2() { - $swatchMock = $this->getMock('\Magento\Swatches\Model\Swatch', [], [], '', false); + $swatchMock = $this->getMock(\Magento\Swatches\Model\Swatch::class, [], [], '', false); $optionsData = [ [ @@ -668,7 +673,7 @@ public function testGetSwatchesByOptionsIdIf2() $swatchMock->expects($this->at(9))->method('getData')->with('')->willReturn($optionsData[1]); $swatchCollectionMock = $this->objectManager->getCollectionMock( - '\Magento\Swatches\Model\ResourceModel\Swatch\Collection', + \Magento\Swatches\Model\ResourceModel\Swatch\Collection::class, [ $swatchMock, $swatchMock, @@ -678,7 +683,7 @@ public function testGetSwatchesByOptionsIdIf2() $swatchCollectionMock->method('addFilterByOptionsIds')->with([35])->will($this->returnSelf()); - $storeMock = $this->getMock('\Magento\Store\Model\Store', [], [], '', false); + $storeMock = $this->getMock(\Magento\Store\Model\Store::class, [], [], '', false); $this->storeManagerMock->method('getStore')->willReturn($storeMock); $storeMock->method('getId')->willReturn(1); @@ -687,7 +692,7 @@ public function testGetSwatchesByOptionsIdIf2() public function testGetSwatchesByOptionsIdIf3() { - $swatchMock = $this->getMock('\Magento\Swatches\Model\Swatch', [], [], '', false); + $swatchMock = $this->getMock(\Magento\Swatches\Model\Swatch::class, [], [], '', false); $optionsData = [ 'type' => 0, @@ -704,7 +709,7 @@ public function testGetSwatchesByOptionsIdIf3() $swatchMock->expects($this->at(4))->method('getData')->with('')->willReturn($optionsData); $swatchCollectionMock = $this->objectManager->getCollectionMock( - '\Magento\Swatches\Model\ResourceModel\Swatch\Collection', + \Magento\Swatches\Model\ResourceModel\Swatch\Collection::class, [ $swatchMock, ] @@ -713,7 +718,7 @@ public function testGetSwatchesByOptionsIdIf3() $swatchCollectionMock->method('addFilterByOptionsIds')->with([35])->will($this->returnSelf()); - $storeMock = $this->getMock('\Magento\Store\Model\Store', [], [], '', false); + $storeMock = $this->getMock(\Magento\Store\Model\Store::class, [], [], '', false); $this->storeManagerMock->method('getStore')->willReturn($storeMock); $storeMock->method('getId')->willReturn(1); @@ -724,7 +729,7 @@ public function testIsProductHasSwatch() { $this->getSwatchAttributes(); $result = $this->swatchHelperObject->isProductHasSwatch($this->productMock); - $this->assertEquals(2, $result); + $this->assertEquals(true, $result); } /** @@ -794,6 +799,7 @@ public function dataForIsVisualSwatchType() 'update_product_preview_image' => 1, 'use_product_image_for_swatch' => 0 ]; + return [ [ serialize($additionalData), @@ -850,6 +856,7 @@ public function dataForIsTextSwatchType() 'update_product_preview_image' => 1, 'use_product_image_for_swatch' => 0 ]; + return [ [ serialize($additionalData), diff --git a/app/code/Magento/Swatches/Test/Unit/Model/Plugin/ProductImageTest.php b/app/code/Magento/Swatches/Test/Unit/Model/Plugin/ProductImageTest.php index 2b7db39c41ae5..6100801f17984 100644 --- a/app/code/Magento/Swatches/Test/Unit/Model/Plugin/ProductImageTest.php +++ b/app/code/Magento/Swatches/Test/Unit/Model/Plugin/ProductImageTest.php @@ -34,15 +34,15 @@ class ProductImageTest extends \PHPUnit_Framework_TestCase protected function setUp() { $this->swatchesHelperMock = $this->getMock( - '\Magento\Swatches\Helper\Data', - ['loadVariationByFallback', 'isSwatchAttribute'], + \Magento\Swatches\Helper\Data::class, + ['loadVariationByFallback', 'isSwatchAttribute', 'isProductHasSwatch'], [], '', false ); $this->attributeFactoryMock = $this->getMock( - '\Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory', + \Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory::class, ['create'], [], '', @@ -50,7 +50,7 @@ protected function setUp() ); $this->eavConfigMock = $this->getMock( - '\Magento\Eav\Model\Config', + \Magento\Eav\Model\Config::class, [], [], '', @@ -58,20 +58,20 @@ protected function setUp() ); $this->attributeMock = $this->getMock( - '\Magento\Catalog\Model\ResourceModel\Eav\Attribute', + \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class, ['loadByCode', 'getId', 'getUsedInProductListing', 'getIsFilterable', 'getData'], [], '', false ); - $this->requestMock = $this->getMock('\Magento\Framework\App\Request\Http', ['getParams'], [], '', false); - $this->productMock = $this->getMock('\Magento\Catalog\Model\Product', [], [], '', false); + $this->requestMock = $this->getMock(\Magento\Framework\App\Request\Http::class, ['getParams'], [], '', false); + $this->productMock = $this->getMock(\Magento\Catalog\Model\Product::class, [], [], '', false); $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->pluginModel = $objectManager->getObject( - 'Magento\Swatches\Model\Plugin\ProductImage', + \Magento\Swatches\Model\Plugin\ProductImage::class, [ 'swatchesHelperData' => $this->swatchesHelperMock, 'eavConfig' => $this->eavConfigMock, @@ -98,8 +98,12 @@ public function testBeforeGetImage($expected) ->expects($this->exactly($expected['loadVariationByFallback_count'])) ->method('loadVariationByFallback') ->willReturn($expected['product']); + $this->swatchesHelperMock + ->method('isProductHasSwatch') + ->with($this->productMock) + ->willReturn(false); - $productImageMock = $this->getMock('Magento\Catalog\Block\Product\AbstractProduct', [], [], '', false); + $productImageMock = $this->getMock(\Magento\Catalog\Block\Product\AbstractProduct::class, [], [], '', false); $result = $this->pluginModel->beforeGetImage($productImageMock, $this->productMock, $expected['page_handle']); $this->assertEquals([$this->productMock, $expected['page_handle'], []], $result); @@ -155,7 +159,7 @@ protected function canReplaceImageWithSwatch($expected) */ public function dataForTest() { - $productMock = $this->getMock('\Magento\Catalog\Model\Product', [], [], '', false); + $productMock = $this->getMock(\Magento\Catalog\Model\Product::class, [], [], '', false); $productMock->expects($this->any())->method('getImage')->willReturn(false); return [ diff --git a/app/code/Magento/Swatches/Test/Unit/Model/SwatchAttributeCodesTest.php b/app/code/Magento/Swatches/Test/Unit/Model/SwatchAttributeCodesTest.php new file mode 100644 index 0000000000000..8705103f805c9 --- /dev/null +++ b/app/code/Magento/Swatches/Test/Unit/Model/SwatchAttributeCodesTest.php @@ -0,0 +1,166 @@ + 'text_swatch', + 11 => 'image_swatch' + ]; + + protected function setUp() + { + $this->cache = $this->getMock( + CacheInterface::class, + [ + 'getFrontend', + 'load', + 'save', + 'remove', + 'clean' + ], + [], + '', + false + ); + + $this->resourceConnection = $this->getMock( + ResourceConnection::class, + ['getConnection', 'getTableName'], + [], + '', + false + ); + + $cacheTags = [Attribute::CACHE_TAG]; + + $this->swatchAttributeCodesModel = new SwatchAttributeCodes( + $this->cache, + $this->resourceConnection, + self::CACHE_KEY, + $cacheTags + ); + } + + /** + * @dataProvider dataForGettingCodes + */ + public function testGetCodes($swatchAttributeCodesCache, $expected) + { + $this->cache + ->method('load') + ->with(self::CACHE_KEY) + ->willReturn($swatchAttributeCodesCache); + + $adapterMock = $this->getMock( + Mysql::class, + ['select', 'fetchPairs'], + [], + '', + false + ); + + $selectMock = $this->getMock( + Select::class, + ['from', 'where', 'join'], + [], + '', + false + ); + $selectMock + ->method('from') + ->withConsecutive( + [ + self::identicalTo( + ['a' => self::ATTRIBUTE_TABLE], + [ + 'attribute_id' => 'a.attribute_id', + 'attribute_code' => 'a.attribute_code', + ] + ) + ], + [ + self::identicalTo( + ['o' => self::ATTRIBUTE_OPTION_TABLE], + ['attribute_id' => 'o.attribute_id'] + ) + ] + ) + ->willReturnSelf(); + + //used anything for second argument because of new \Zend_Db_Expt used in code. + $selectMock->method('where') + ->with( + self::identicalTo('a.attribute_id IN (?)'), + self::anything() + ) + ->willReturnSelf(); + + $adapterMock->method('select') + ->willReturn($selectMock); + $adapterMock->method('fetchPairs') + ->with($selectMock) + ->willReturn($this->swatchAttributesCodes); + + $this->resourceConnection + ->method('getConnection') + ->willReturn($adapterMock); + + $this->resourceConnection + ->method('getTableName') + ->withConsecutive( + [self::ATTRIBUTE_TABLE], + [self::ATTRIBUTE_OPTION_TABLE], + [self::SWATCH_OPTION_TABLE] + )->will(self::onConsecutiveCalls( + self::ATTRIBUTE_TABLE, + self::ATTRIBUTE_OPTION_TABLE, + self::SWATCH_OPTION_TABLE + )); + + $result = $this->swatchAttributeCodesModel->getCodes(); + $this->assertEquals($expected, $result); + } + + public function dataForGettingCodes() + { + return [ + [false, $this->swatchAttributesCodes], + [json_encode($this->swatchAttributesCodes), $this->swatchAttributesCodes] + ]; + } +} diff --git a/app/code/Magento/Swatches/Test/Unit/Model/SwatchAttributesProviderTest.php b/app/code/Magento/Swatches/Test/Unit/Model/SwatchAttributesProviderTest.php new file mode 100644 index 0000000000000..6dd0bf6f8e05e --- /dev/null +++ b/app/code/Magento/Swatches/Test/Unit/Model/SwatchAttributesProviderTest.php @@ -0,0 +1,114 @@ +typeConfigurableMock = $this->getMock( + Configurable::class, + ['getConfigurableAttributes', 'getCodes'], + [], + '', + false + ); + + $this->swatchAttributeCodesMock = $this->getMock( + SwatchAttributeCodes::class, + [], + [], + '', + false + ); + + $this->productMock = $this->getMock( + \Magento\Catalog\Model\Product::class, + ['getId', 'getTypeId'], + [], + '', + false + ); + + $this->swatchAttributeProvider = new SwatchAttributesProvider( + $this->typeConfigurableMock, + $this->swatchAttributeCodesMock + ); + } + + public function testProvide() + { + $this->productMock->method('getId')->willReturn(1); + $this->productMock->method('getTypeId') + ->willReturn(Configurable::TYPE_CODE); + + $productAttributeMock = $this->getMock( + Interceptor::class, + [], + [], + '', + false + ); + + $configAttributeMock = $this->getMock( + Configurable\Attribute::class, + ['getAttributeId', 'getProductAttribute'], + [], + '', + false + ); + $configAttributeMock + ->method('getAttributeId') + ->willReturn(1); + + $configAttributeMock + ->method('getProductAttribute') + ->willReturn($productAttributeMock); + + $this->typeConfigurableMock + ->method('getConfigurableAttributes') + ->with($this->productMock) + ->willReturn([$configAttributeMock]); + + $swatchAttributes = [1 => 'text_swatch']; + + $this->swatchAttributeCodesMock + ->method('getCodes') + ->willReturn($swatchAttributes); + + $expected = [1 => $productAttributeMock]; + + $result = $this->swatchAttributeProvider->provide($this->productMock); + + $this->assertEquals($expected, $result); + } +} diff --git a/app/code/Magento/Swatches/etc/adminhtml/system.xml b/app/code/Magento/Swatches/etc/adminhtml/system.xml index a36fb39c8c5ec..c16464e24dadb 100644 --- a/app/code/Magento/Swatches/etc/adminhtml/system.xml +++ b/app/code/Magento/Swatches/etc/adminhtml/system.xml @@ -12,6 +12,10 @@ + + + Magento\Config\Model\Config\Source\Yesno + diff --git a/app/code/Magento/Swatches/etc/config.xml b/app/code/Magento/Swatches/etc/config.xml index ab9f7d1023926..54ef5ea728862 100644 --- a/app/code/Magento/Swatches/etc/config.xml +++ b/app/code/Magento/Swatches/etc/config.xml @@ -10,6 +10,7 @@ 16 + 1 diff --git a/app/code/Magento/Swatches/etc/di.xml b/app/code/Magento/Swatches/etc/di.xml index dff3b4871403b..114054ed28757 100644 --- a/app/code/Magento/Swatches/etc/di.xml +++ b/app/code/Magento/Swatches/etc/di.xml @@ -73,4 +73,12 @@ + + + swatch-attribute-list + + Magento\Eav\Model\Entity\Attribute::CACHE_TAG + + + diff --git a/app/code/Magento/Swatches/view/frontend/layout/catalog_category_view.xml b/app/code/Magento/Swatches/view/frontend/layout/catalog_category_view.xml index c8d243a3af960..501866f18b5d5 100644 --- a/app/code/Magento/Swatches/view/frontend/layout/catalog_category_view.xml +++ b/app/code/Magento/Swatches/view/frontend/layout/catalog_category_view.xml @@ -11,7 +11,7 @@ - + diff --git a/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_advanced_result.xml b/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_advanced_result.xml index c8d243a3af960..501866f18b5d5 100644 --- a/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_advanced_result.xml +++ b/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_advanced_result.xml @@ -11,7 +11,7 @@ - + diff --git a/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_result_index.xml b/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_result_index.xml index c8d243a3af960..98e9c54b4a793 100644 --- a/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_result_index.xml +++ b/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_result_index.xml @@ -11,7 +11,7 @@ - + diff --git a/dev/tests/functional/.htaccess.sample b/dev/tests/functional/.htaccess.sample new file mode 100644 index 0000000000000..ce860a0805f4d --- /dev/null +++ b/dev/tests/functional/.htaccess.sample @@ -0,0 +1,6 @@ +########################################### +## Allow access to command.php + + order allow,deny + allow from all + diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli.php new file mode 100644 index 0000000000000..350c9585d15fd --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli.php @@ -0,0 +1,64 @@ +transport = $transport; + } + + /** + * Run command. + * + * @param string $command + * @param array $options [optional] + * @return void + */ + protected function execute($command, $options = []) + { + $curl = $this->transport; + $curl->write($this->prepareUrl($command, $options), [], CurlInterface::GET); + $curl->read(); + $curl->close(); + } + + /** + * Prepare url. + * + * @param string $command + * @param array $options + * @return string + */ + private function prepareUrl($command, array $options) + { + $command .= ' ' . implode(' ', $options); + return $_ENV['app_frontend_url'] . self::URL . '?command=' . urlencode($command); + } +} diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli/Cache.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli/Cache.php new file mode 100644 index 0000000000000..272e3158d3c27 --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli/Cache.php @@ -0,0 +1,65 @@ + 0, 'Yes' => 1, ], + 'used_in_product_listing' => [ + 'No' => '0', + 'Yes' => '1', + ], ]; /** @@ -76,6 +80,7 @@ public function persist(FixtureInterface $fixture = null) unset($data['options']); } + $data = $this->changeStructureOfTheData($data); $url = $_ENV['app_backend_url'] . 'catalog/product_attribute/save/back/edit'; $curl = new BackendDecorator(new CurlTransport(), $this->_configuration); $curl->write($url, $data); @@ -104,4 +109,13 @@ public function persist(FixtureInterface $fixture = null) return $resultData; } + + /** + * @param array $data + * @return array + */ + protected function changeStructureOfTheData(array $data) + { + return $data; + } } diff --git a/dev/tests/functional/tests/app/Magento/Config/Test/TestStep/SetupConfigurationStep.php b/dev/tests/functional/tests/app/Magento/Config/Test/TestStep/SetupConfigurationStep.php index 49b7d2f519d95..a1f3996197517 100644 --- a/dev/tests/functional/tests/app/Magento/Config/Test/TestStep/SetupConfigurationStep.php +++ b/dev/tests/functional/tests/app/Magento/Config/Test/TestStep/SetupConfigurationStep.php @@ -6,8 +6,10 @@ namespace Magento\Config\Test\TestStep; +use Magento\Config\Test\Fixture\ConfigData; use Magento\Mtf\Fixture\FixtureFactory; use Magento\Mtf\TestStep\TestStepInterface; +use Magento\Mtf\Util\Command\Cli\Cache; /** * Setup configuration using handler. @@ -35,19 +37,41 @@ class SetupConfigurationStep implements TestStepInterface */ protected $rollback; + /** + * Flush cache. + * + * @var bool + */ + protected $flushCache; + + /** + * Cli command to do operations with cache. + * + * @var Cache + */ + private $cache; + /** * Preparing step properties. * - * @constructor * @param FixtureFactory $fixtureFactory + * @param Cache $cache * @param string $configData * @param bool $rollback + * @param bool $flushCache */ - public function __construct(FixtureFactory $fixtureFactory, $configData = null, $rollback = false) - { + public function __construct( + FixtureFactory $fixtureFactory, + Cache $cache, + $configData = null, + $rollback = false, + $flushCache = false + ) { $this->fixtureFactory = $fixtureFactory; $this->configData = $configData; $this->rollback = $rollback; + $this->flushCache = $flushCache; + $this->cache = $cache; } /** @@ -66,14 +90,19 @@ public function run() $result = []; foreach ($configData as $configDataSet) { + /** @var ConfigData $config */ $config = $this->fixtureFactory->createByCode('configData', ['dataset' => $configDataSet . $prefix]); if ($config->hasData('section')) { $config->persist(); - $result[] = $config; + $result = array_merge($result, $config->getSection()); + } + if ($this->flushCache) { + $this->cache->flush(); } } + $config = $this->fixtureFactory->createByCode('configData', ['data' => $result]); - return ['config' => $result]; + return ['config' => $config]; } /** diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ListProduct.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ListProduct.php new file mode 100644 index 0000000000000..711072ae9e7cf --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ListProduct.php @@ -0,0 +1,29 @@ +productItem, $product->getName()); + + return $this->blockFactory->create( + \Magento\Swatches\Test\Block\Product\ProductList\ProductItem::class, + ['element' => $this->_rootElement->find($locator, Locator::SELECTOR_XPATH)] + ); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ProductList/ProductItem.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ProductList/ProductItem.php new file mode 100755 index 0000000000000..a1bc18a1a6d2d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ProductList/ProductItem.php @@ -0,0 +1,33 @@ +_rootElement->find($this->swatchBlockSelector)->isVisible(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSwatchesVisibilityInCategory.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSwatchesVisibilityInCategory.php new file mode 100644 index 0000000000000..11c82e301e646 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSwatchesVisibilityInCategory.php @@ -0,0 +1,78 @@ +openCategoryPage($cmsIndex, $product); + + $swatchesBlockVisible = $catalogCategoryView->getListSwatchesProductBlock() + ->getProductItem($product)->isSwatchesBlockVisible(); + + if ($visible) { + \PHPUnit_Framework_Assert::assertTrue( + $swatchesBlockVisible, + 'Swatches are absent on category page.' + ); + } else { + \PHPUnit_Framework_Assert::assertFalse( + $swatchesBlockVisible, + 'Swatches are still present on category page.' + ); + } + } + + /** + * Open category view page. + * + * @param CmsIndex $cmsIndex + * @param FixtureInterface $product + * @return void + */ + private function openCategoryPage( + CmsIndex $cmsIndex, + FixtureInterface $product + ) { + $categoryIds = $product->getCategoryIds(); + $categoryName = reset($categoryIds); + $cmsIndex->open(); + $cmsIndex->getTopmenu()->selectCategoryByName($categoryName); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Swatches visibility is correct.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Fixture/ConfigurableProduct.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Fixture/ConfigurableProduct.xml new file mode 100644 index 0000000000000..84bdd02c92927 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Fixture/ConfigurableProduct.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Fixture/SwatchProductAttribute.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Fixture/SwatchProductAttribute.xml new file mode 100644 index 0000000000000..29ff66dc2cbea --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Fixture/SwatchProductAttribute.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Handler/SwatchProductAttribute/Curl.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Handler/SwatchProductAttribute/Curl.php new file mode 100644 index 0000000000000..2bc6d35262ca2 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Handler/SwatchProductAttribute/Curl.php @@ -0,0 +1,49 @@ +mappingData['frontend_input'] = [ + 'Text Swatch' => 'swatch_text', + ]; + } + + /** + * Re-map options from default options structure to swatches structure, + * as swatches was initially created with name convention differ from other attributes. + * + * @param array $data + * @return array + */ + protected function changeStructureOfTheData(array $data) + { + $data = parent::changeStructureOfTheData($data); + $data['optiontext'] = $data['option']; + $data['swatchtext'] = [ + 'value' => $data['option']['value'] + ]; + unset($data['option']); + return $data; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Handler/SwatchProductAttribute/SwatchProductAttributeInterface.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Handler/SwatchProductAttribute/SwatchProductAttributeInterface.php new file mode 100644 index 0000000000000..9dd7c573c19b2 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Handler/SwatchProductAttribute/SwatchProductAttributeInterface.php @@ -0,0 +1,17 @@ + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigData.xml new file mode 100644 index 0000000000000..78f7f2c39203b --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigData.xml @@ -0,0 +1,26 @@ + + + + + + + default + 0 + 1 + + + + + + default + 0 + 0 + + + + diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct.xml new file mode 100644 index 0000000000000..098f28965d65d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct.xml @@ -0,0 +1,42 @@ + + + + + + Test configurable product with color %isolation% + sku_test_configurable_product_%isolation% + + 40 + price_40 + + This item has weight + 30 + Yes + Catalog, Search + + taxable_goods + + configurable-product-%isolation% + + text_swatch + + + In Stock + + + default_subcategory + + + Main Website + + + custom_attribute_set + + + + diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml new file mode 100644 index 0000000000000..f702347a0d660 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml @@ -0,0 +1,48 @@ + + + + + + + + + + 12.00 + Yes + + + 20.00 + Yes + + + 18.00 + Yes + + + + + + swatchesProductAttribute::attribute_type_text_swatch + + + + 10 + 1 + + + 10 + 1 + + + 10 + 1 + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/SwatchProductAttribute.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/SwatchProductAttribute.xml new file mode 100644 index 0000000000000..9ca01c98bf902 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/SwatchProductAttribute.xml @@ -0,0 +1,34 @@ + + + + + + sw_color%isolation% + Text Swatch + Text Swatch + Yes + + + No + R + R + + + No + G + G + + + No + B + B + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/CheckSwatchesInCategoryPageTest.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/CheckSwatchesInCategoryPageTest.php new file mode 100644 index 0000000000000..3499dd8beedac --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/CheckSwatchesInCategoryPageTest.php @@ -0,0 +1,126 @@ + Configuration > Catalog > Catalog > Storefront. + * 3. Set Show Swatches in Product List = No. + * 4. Save configuration. + * 5. Clean cache. + * 6. Go to storefront > category with configurable product. + * 7. Check swatches not visible in catalog item. + * 8. Navigate to Stores > Configuration > Catalog > Catalog > Storefront. + * 9. Set Show Swatches in Product List = Yes. + * 10. Save configuration. + * 11. Clean cache. + * 12. Go to storefront > category with configurable product. + * 13. Check swatches are visible in catalog item. + * + * @group Swatches (MX) + * @ZephyrId MAGETWO-65485 + */ +class CheckSwatchesInCategoryPageTest extends Injectable +{ + /** + * Category page. + * + * @var CatalogCategoryView + */ + protected $catalogCategoryView; + + /** + * Index page. + * + * @var CmsIndex + */ + protected $cmsIndex; + + /** + * Factory for creation SetupConfigurationStep. + * + * @var TestStepFactory + */ + protected $testStepFactory; + + /** + * Factory for creation AssertSwatchesVisibilityInCategory. + * + * @var ConstraintFactory + */ + protected $constraintFactory; + + /** + * @param CatalogCategoryView $catalogCategoryView + * @param CmsIndex $cmsIndex + * @param TestStepFactory $testStepFactory + * @param ConstraintFactory $constraintFactory + */ + public function __prepare( + CatalogCategoryView $catalogCategoryView, + CmsIndex $cmsIndex, + TestStepFactory $testStepFactory, + ConstraintFactory $constraintFactory + ) { + $this->catalogCategoryView = $catalogCategoryView; + $this->cmsIndex = $cmsIndex; + $this->testStepFactory = $testStepFactory; + $this->constraintFactory = $constraintFactory; + } + + /** + * Test check swatches on category page run. + * + * @param ConfigurableProduct $product + * @return array + */ + public function test(ConfigurableProduct $product) + { + //Preconditions: + $product->persist(); + + //Steps: + $this->testStepFactory->create( + SetupConfigurationStep::class, + ['configData' => 'disable_swatches_visibility_in_catalog'] + )->run(); + + /** @var AssertSwatchesVisibilityInCategory $assertSwatchesVisibility */ + $assertSwatchesVisibility = $this->constraintFactory->get( + AssertSwatchesVisibilityInCategory::class + ); + $assertSwatchesVisibility->processAssert( + $this->catalogCategoryView, + $this->cmsIndex, + $product, + false + ); + + $this->testStepFactory->create( + SetupConfigurationStep::class, + ['configData' => 'enable_swatches_visibility_in_catalog', 'flushCache' => true] + )->run(); + + return ['product' => $product]; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/CheckSwatchesInCategoryPageTest.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/CheckSwatchesInCategoryPageTest.xml new file mode 100644 index 0000000000000..dd860ffba2b9e --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/CheckSwatchesInCategoryPageTest.xml @@ -0,0 +1,15 @@ + + + + + + product_with_text_swatch + + + + diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/etc/curl/di.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/etc/curl/di.xml new file mode 100644 index 0000000000000..b0d43eb4cce2f --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/etc/curl/di.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/dev/tests/functional/utils/command.php b/dev/tests/functional/utils/command.php new file mode 100644 index 0000000000000..397f60cd07ea1 --- /dev/null +++ b/dev/tests/functional/utils/command.php @@ -0,0 +1,12 @@ + [ - 'token' => 'Magento\ImportExport\Model\Source\Import\Behavior\Basic', + 'token' => \Magento\ImportExport\Model\Source\Import\Behavior\Basic::class, 'code' => 'basic_behavior', 'notes' => [ \Magento\ImportExport\Model\Import::BEHAVIOR_REPLACE => "Note: Product IDs will be regenerated." ], ], 'customer_composite' => [ - 'token' => 'Magento\ImportExport\Model\Source\Import\Behavior\Basic', + 'token' => \Magento\ImportExport\Model\Source\Import\Behavior\Basic::class, 'code' => 'basic_behavior', 'notes' => [], ], 'customer' => [ - 'token' => 'Magento\ImportExport\Model\Source\Import\Behavior\Custom', + 'token' => \Magento\ImportExport\Model\Source\Import\Behavior\Custom::class, 'code' => 'custom_behavior', 'notes' => [], ], 'customer_address' => [ - 'token' => 'Magento\ImportExport\Model\Source\Import\Behavior\Custom', + 'token' => \Magento\ImportExport\Model\Source\Import\Behavior\Custom::Class, 'code' => 'custom_behavior', 'notes' => [], ], @@ -60,18 +65,24 @@ class ImportTest extends \PHPUnit_Framework_TestCase * @var array */ protected $_uniqueBehaviors = [ - 'basic_behavior' => 'Magento\ImportExport\Model\Source\Import\Behavior\Basic', - 'custom_behavior' => 'Magento\ImportExport\Model\Source\Import\Behavior\Custom', + 'basic_behavior' => \Magento\ImportExport\Model\Source\Import\Behavior\Basic::class, + 'custom_behavior' => \Magento\ImportExport\Model\Source\Import\Behavior\Custom::class, ]; protected function setUp() { + $this->indexerRegistry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Framework\Indexer\IndexerRegistry::class + ); $this->_importConfig = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - 'Magento\ImportExport\Model\Import\Config' + \Magento\ImportExport\Model\Import\Config::class ); $this->_model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - 'Magento\ImportExport\Model\Import', - ['importConfig' => $this->_importConfig] + \Magento\ImportExport\Model\Import::class, + [ + 'importConfig' => $this->_importConfig, + 'indexerRegistry' => $this->indexerRegistry + ] ); } @@ -82,7 +93,7 @@ public function testImportSource() { /** @var $customersCollection \Magento\Customer\Model\ResourceModel\Customer\Collection */ $customersCollection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - 'Magento\Customer\Model\ResourceModel\Customer\Collection' + \Magento\Customer\Model\ResourceModel\Customer\Collection::class ); $existCustomersCount = count($customersCollection->load()); @@ -108,7 +119,7 @@ public function testValidateSource() $this->_model->setEntity('catalog_product'); /** @var \Magento\ImportExport\Model\Import\AbstractSource|\PHPUnit_Framework_MockObject_MockObject $source */ $source = $this->getMockForAbstractClass( - 'Magento\ImportExport\Model\Import\AbstractSource', + \Magento\ImportExport\Model\Import\AbstractSource::class, [['sku', 'name']] ); $source->expects($this->any())->method('_getNextRow')->will($this->returnValue(false)); @@ -122,7 +133,7 @@ public function testValidateSource() public function testValidateSourceException() { $source = $this->getMockForAbstractClass( - 'Magento\ImportExport\Model\Import\AbstractSource', + \Magento\ImportExport\Model\Import\AbstractSource::class, [], '', false @@ -195,4 +206,72 @@ public function testGetUniqueEntityBehaviors() $this->assertEquals($behaviorClass, $actualBehaviors[$behaviorCode]); } } + + /** + * Check if index is not broken when update by schedule and broken when update on save. + * + * @param $expectedStatus + * @param $schedule + * @return void + * @dataProvider invalidateIndexDataProvider + */ + public function testInvalidateIndex($expectedStatus, $schedule) + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + + $indexerName = 'catalog_product'; + + /** @var $config \Magento\ImportExport\Model\Import\ConfigInterface*/ + $config = $objectManager->create(\Magento\ImportExport\Model\Import\ConfigInterface::class); + + $relatedIndexers = $config->getRelatedIndexers($indexerName); + + /** @var \Magento\Framework\Indexer\StateInterface $state */ + $state = $objectManager->get(\Magento\Framework\Indexer\StateInterface::class); + + foreach (array_keys($relatedIndexers) as $indexerId) { + try { + $state->loadByIndexer($indexerId); + $state->setStatus(\Magento\Framework\Indexer\StateInterface::STATUS_VALID); + + /** @var \Magento\Indexer\Model\Indexer $indexer */ + $indexer = $this->indexerRegistry->get($indexerId); + $indexer->setState($state); + $indexer->setScheduled($schedule); + } catch (\InvalidArgumentException $e) { + } + } + + $this->_model->setData('entity', $indexerName); + $this->_model->invalidateIndex(); + + foreach (array_keys($relatedIndexers) as $indexerId) { + try { + /** @var \Magento\Indexer\Model\Indexer $indexer */ + $indexer = $this->indexerRegistry->get($indexerId); + $state = $indexer->getState(); + self::assertEquals($expectedStatus, $state->getStatus()); + } catch (\InvalidArgumentException $e) { + } + } + } + + /** + * Data provider for test 'testSaveStockItemQtyCheckIndexes' + * + * @return array + */ + public function invalidateIndexDataProvider() + { + return [ + 'Update by schedule' => [ + '$expectedStatus' => \Magento\Framework\Indexer\StateInterface::STATUS_VALID, + '$schedule' => true, + ], + 'Update on save' => [ + '$expectedStatus' => \Magento\Framework\Indexer\StateInterface::STATUS_INVALID, + '$schedule' => false, + ] + ]; + } } diff --git a/dev/tests/integration/testsuite/Magento/Swatches/Model/SwatchAttributeCodesTest.php b/dev/tests/integration/testsuite/Magento/Swatches/Model/SwatchAttributeCodesTest.php new file mode 100644 index 0000000000000..4b573bf590232 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Swatches/Model/SwatchAttributeCodesTest.php @@ -0,0 +1,42 @@ +_objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->swatchAttributeCodes = $this->_objectManager->create( + \Magento\Swatches\Model\SwatchAttributeCodes::class + ); + } + + /** + * @magentoDbIsolation enabled + * @magentoDataFixture Magento/Swatches/_files/swatch_attribute.php + */ + public function testGetCodes() + { + $attribute = $this->_objectManager + ->create(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class) + ->load('color_swatch', 'attribute_code'); + $expected = [ + $attribute->getAttributeId() => $attribute->getAttributeCode() + ]; + $swatchAttributeCodes = $this->swatchAttributeCodes->getCodes(); + + $this->assertEquals($expected, $swatchAttributeCodes); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Swatches/_files/swatch_attribute.php b/dev/tests/integration/testsuite/Magento/Swatches/_files/swatch_attribute.php new file mode 100644 index 0000000000000..803ecde086c16 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Swatches/_files/swatch_attribute.php @@ -0,0 +1,73 @@ + 1, + 'is_visible_on_front' => 1, + 'is_visible_in_advanced_search' => 0, + 'attribute_code' => 'color_swatch', + 'backend_type' => '', + 'is_searchable' => 0, + 'is_filterable' => 0, + 'is_filterable_in_search' => 0, + 'frontend_label' => 'Attribute ', + 'entity_type_id' => 4 +]; +$optionsPerAttribute = 3; + +$data['frontend_input'] = 'swatch_visual'; +$data['swatch_input_type'] = 'visual'; +$data['swatchvisual']['value'] = array_reduce( + range(1, $optionsPerAttribute), + function ($values, $index) use ($optionsPerAttribute) { + $values['option_' . $index] = '#' + . str_repeat( + dechex(255 * $index / $optionsPerAttribute), + 3 + ); + return $values; + }, + [] +); +$data['optionvisual']['value'] = array_reduce( + range(1, $optionsPerAttribute), + function ($values, $index) use ($optionsPerAttribute) { + $values['option_' . $index] = ['option ' . $index]; + return $values; + }, + [] +); + +$data['options']['option'] = array_reduce( + range(1, $optionsPerAttribute), + function ($values, $index) use ($optionsPerAttribute) { + $values[] = [ + 'label' => 'option ' . $index, + 'value' => 'option_' . $index + ]; + return $values; + }, + [] +); + +$options = []; +foreach ($data['options']['option'] as $optionData) { + $options[] = $objectManager->get(AttributeOptionInterface::class) + ->setLabel($optionData['label']) + ->setValue($optionData['value']) + ; +} + +$attribute = $objectManager->create( + \Magento\Catalog\Api\Data\ProductAttributeInterface::class, + ['data' => $data] +); +$attribute->setOptions($options); +$attribute->save(); diff --git a/dev/tests/integration/testsuite/Magento/Swatches/_files/swatch_attribute_rollback.php b/dev/tests/integration/testsuite/Magento/Swatches/_files/swatch_attribute_rollback.php new file mode 100644 index 0000000000000..f4d4e5ea8a582 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Swatches/_files/swatch_attribute_rollback.php @@ -0,0 +1,23 @@ +get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute */ +$attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->create(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class); + +$attribute->loadByCode(4, 'color_swatch'); + +if ($attribute->getId()) { + $attribute->delete(); +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/setup/src/Magento/Setup/Fixtures/OrdersFixture.php b/setup/src/Magento/Setup/Fixtures/OrdersFixture.php index 74c523cfa9b57..2c366c0b3115c 100644 --- a/setup/src/Magento/Setup/Fixtures/OrdersFixture.php +++ b/setup/src/Magento/Setup/Fixtures/OrdersFixture.php @@ -10,6 +10,7 @@ /** * Class OrdersFixture + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class OrdersFixture extends Fixture { @@ -34,66 +35,66 @@ public function execute() $quoteTableName = $this->getTableName( 'quote', - 'Magento\Quote\Model\ResourceModel\Quote' + \Magento\Quote\Model\ResourceModel\Quote::class ); $quoteAddressTableName = $this->getTableName( 'quote_address', - 'Magento\Quote\Model\ResourceModel\Quote\Address' + \Magento\Quote\Model\ResourceModel\Quote\Address::class ); $quoteItemTableName = $this->getTableName( 'quote_item', - 'Magento\Quote\Model\ResourceModel\Quote\Item' + \Magento\Quote\Model\ResourceModel\Quote\Item::class ); $quoteItemOptionTableName = $this->getTableName( 'quote_item_option', - 'Magento\Quote\Model\ResourceModel\Quote\Item\Option' + \Magento\Quote\Model\ResourceModel\Quote\Item\Option::class ); $quotePaymentTableName = $this->getTableName( 'quote_payment', - 'Magento\Quote\Model\ResourceModel\Quote\Payment' + \Magento\Quote\Model\ResourceModel\Quote\Payment::class ); $quoteAddressRateTableName = $this->getTableName( 'quote_shipping_rate', - 'Magento\Quote\Model\ResourceModel\Quote\Address\Rate' + \Magento\Quote\Model\ResourceModel\Quote\Address\Rate::class ); $reportEventTableName = $this->getTableName( 'report_event', - 'Magento\Reports\Model\ResourceModel\Event' + \Magento\Reports\Model\ResourceModel\Event::class ); $salesOrderTableName = $this->getTableName( 'sales_order', - 'Magento\Sales\Model\ResourceModel\Order' + \Magento\Sales\Model\ResourceModel\Order::class ); $salesOrderAddressTableName = $this->getTableName( 'sales_order_address', - 'Magento\Sales\Model\ResourceModel\Order' + \Magento\Sales\Model\ResourceModel\Order::class ); $salesOrderGridTableName = $this->getTableName( 'sales_order_grid', - 'Magento\Sales\Model\ResourceModel\Order\Grid' + \Magento\Sales\Model\ResourceModel\Order\Grid::class ); $salesOrderItemTableName = $this->getTableName( 'sales_order_item', - 'Magento\Sales\Model\ResourceModel\Order\Item' + \Magento\Sales\Model\ResourceModel\Order\Item::class ); $salesOrderPaymentTableName = $this->getTableName( 'sales_order_payment', - 'Magento\Sales\Model\ResourceModel\Order\Payment' + \Magento\Sales\Model\ResourceModel\Order\Payment::class ); $salesOrderStatusHistoryTableName = $this->getTableName( 'sales_order_status_history', - 'Magento\Sales\Model\ResourceModel\Order\Status\History' + \Magento\Sales\Model\ResourceModel\Order\Status\History::class ); $eavEntityStoreTableName = $this->getTableName( 'eav_entity_store', - '\Magento\Eav\Model\ResourceModel\Entity\Store' + \Magento\Eav\Model\ResourceModel\Entity\Store::class ); /** @var \Magento\Store\Model\StoreManager $storeManager */ - $storeManager = $this->fixtureModel->getObjectManager()->create('Magento\Store\Model\StoreManager'); + $storeManager = $this->fixtureModel->getObjectManager()->create(\Magento\Store\Model\StoreManager::class); /** @var $category \Magento\Catalog\Model\Category */ - $category = $this->fixtureModel->getObjectManager()->get('Magento\Catalog\Model\Category'); + $category = $this->fixtureModel->getObjectManager()->get(\Magento\Catalog\Model\Category::class); /** @var $product \Magento\Catalog\Model\Product */ - $product = $this->fixtureModel->getObjectManager()->get('Magento\Catalog\Model\Product'); + $product = $this->fixtureModel->getObjectManager()->get(\Magento\Catalog\Model\Product::class); $result = []; $stores = $storeManager->getStores(); @@ -124,17 +125,14 @@ public function execute() } //Not use root categories if (trim($resultsCategoryName) != '') { - /** @var $productCategory \Magento\Catalog\Model\Category */ - $productCategory = $this->fixtureModel->getObjectManager()->get('Magento\Catalog\Model\Category'); - /** @var $simpleProductCollection \Magento\Catalog\Model\ResourceModel\Product\Collection */ $simpleProductCollection = $this->fixtureModel->getObjectManager()->create( - 'Magento\Catalog\Model\ResourceModel\Product\Collection' + \Magento\Catalog\Model\ResourceModel\Product\Collection::class ); $simpleProductCollection->addStoreFilter($storeId); $simpleProductCollection->addWebsiteFilter($websiteId); - $simpleProductCollection->addCategoryFilter($productCategory->load($resultsCategory)); + $simpleProductCollection->addCategoriesFilter(['eq' => $resultsCategory]); $simpleProductCollection->getSelect()->where(" type_id = 'simple' "); $simpleIds = $simpleProductCollection->getAllIds(2); $simpleProductsResult = []; @@ -316,7 +314,7 @@ public function getTableName($tableName, $resourceName) public function getConnection() { return $this->fixtureModel->getObjectManager()->get( - 'Magento\Framework\App\ResourceConnection' + \Magento\Framework\App\ResourceConnection::class )->getConnection(); } } diff --git a/setup/src/Magento/Setup/Test/Unit/Fixtures/OrdersFixtureTest.php b/setup/src/Magento/Setup/Test/Unit/Fixtures/OrdersFixtureTest.php index 498fe4b62767f..e56c0f4d6ed3b 100644 --- a/setup/src/Magento/Setup/Test/Unit/Fixtures/OrdersFixtureTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Fixtures/OrdersFixtureTest.php @@ -8,9 +8,12 @@ use \Magento\Setup\Fixtures\OrdersFixture; +/** + * Class OrdersFixtureTest + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class OrdersFixtureTest extends \PHPUnit_Framework_TestCase { - /** * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Setup\Fixtures\FixtureModel */ @@ -23,7 +26,7 @@ class OrdersFixtureTest extends \PHPUnit_Framework_TestCase public function setUp() { - $this->fixtureModelMock = $this->getMock('\Magento\Setup\Fixtures\FixtureModel', [], [], '', false); + $this->fixtureModelMock = $this->getMock(\Magento\Setup\Fixtures\FixtureModel::class, [], [], '', false); $this->model = new OrdersFixture($this->fixtureModelMock); } @@ -35,19 +38,19 @@ public function setUp() public function testExecute() { $mockObjectNames = [ - 'Magento\Quote\Model\ResourceModel\Quote', - 'Magento\Quote\Model\ResourceModel\Quote\Address', - 'Magento\Quote\Model\ResourceModel\Quote\Item', - 'Magento\Quote\Model\ResourceModel\Quote\Item\Option', - 'Magento\Quote\Model\ResourceModel\Quote\Payment', - 'Magento\Quote\Model\ResourceModel\Quote\Address\Rate', - 'Magento\Reports\Model\ResourceModel\Event', - 'Magento\Sales\Model\ResourceModel\Order', - 'Magento\Sales\Model\ResourceModel\Order\Grid', - 'Magento\Sales\Model\ResourceModel\Order\Item', - 'Magento\Sales\Model\ResourceModel\Order\Payment', - 'Magento\Sales\Model\ResourceModel\Order\Status\History', - '\Magento\Eav\Model\ResourceModel\Entity\Store' + \Magento\Quote\Model\ResourceModel\Quote::class, + \Magento\Quote\Model\ResourceModel\Quote\Address::class, + \Magento\Quote\Model\ResourceModel\Quote\Item::class, + \Magento\Quote\Model\ResourceModel\Quote\Item\Option::class, + \Magento\Quote\Model\ResourceModel\Quote\Payment::class, + \Magento\Quote\Model\ResourceModel\Quote\Address\Rate::class, + \Magento\Reports\Model\ResourceModel\Event::class, + \Magento\Sales\Model\ResourceModel\Order::class, + \Magento\Sales\Model\ResourceModel\Order\Grid::class, + \Magento\Sales\Model\ResourceModel\Order\Item::class, + \Magento\Sales\Model\ResourceModel\Order\Payment::class, + \Magento\Sales\Model\ResourceModel\Order\Status\History::class, + \Magento\Eav\Model\ResourceModel\Entity\Store::class ]; $mockObjects = []; @@ -55,7 +58,7 @@ public function testExecute() $mockObject = $this->getMock($mockObjectName, ['getTable'], [], '', false); $path = explode('\\', $mockObjectName); $name = array_pop($path); - if (strcasecmp($mockObjectName, 'Magento\Sales\Model\ResourceModel\Order') == 0) { + if (strcasecmp($mockObjectName, \Magento\Sales\Model\ResourceModel\Order::class) == 0) { $mockObject->expects($this->exactly(2)) ->method('getTable') ->willReturn(strtolower($name) . '_table_name'); @@ -68,7 +71,7 @@ public function testExecute() } $connectionInterfaceMock = $this->getMockForAbstractClass( - '\Magento\Framework\DB\Adapter\AdapterInterface', + \Magento\Framework\DB\Adapter\AdapterInterface::class, [], '', true, @@ -80,12 +83,12 @@ public function testExecute() ->method('getTableName') ->willReturn('table_name'); - $resourceMock = $this->getMock('Magento\Framework\App\ResourceConnection', [], [], '', false); + $resourceMock = $this->getMock(\Magento\Framework\App\ResourceConnection::class, [], [], '', false); $resourceMock->expects($this->exactly(15)) ->method('getConnection') ->willReturn($connectionInterfaceMock); - $websiteMock = $this->getMock('\Magento\Store\Model\Website', ['getId', 'getName'], [], '', false); + $websiteMock = $this->getMock(\Magento\Store\Model\Website::class, ['getId', 'getName'], [], '', false); $websiteMock->expects($this->once()) ->method('getId') ->willReturn('website_id'); @@ -93,13 +96,13 @@ public function testExecute() ->method('getName') ->willReturn('website_name'); - $groupMock = $this->getMock('\Magento\Store\Model\Group', ['getName'], [], '', false); + $groupMock = $this->getMock(\Magento\Store\Model\Group::class, ['getName'], [], '', false); $groupMock->expects($this->once()) ->method('getName') ->willReturn('group_name'); $storeMock = $this->getMock( - '\Magento\Store\Model\Store', + \Magento\Store\Model\Store::class, [ 'getStoreId', 'getWebsite', @@ -127,14 +130,14 @@ public function testExecute() ->method('getRootCategoryId') ->willReturn(1); - $storeManagerMock = $this->getMock('Magento\Store\Model\StoreManager', [], [], '', false); + $storeManagerMock = $this->getMock(\Magento\Store\Model\StoreManager::class, [], [], '', false); $storeManagerMock->expects($this->once()) ->method('getStores') ->willReturn([$storeMock]); - $contextMock = $this->getMock('\Magento\Framework\Model\ResourceModel\Db\Context', [], [], '', false); + $contextMock = $this->getMock(\Magento\Framework\Model\ResourceModel\Db\Context::class, [], [], '', false); $abstractDbMock = $this->getMockForAbstractClass( - '\Magento\Framework\Model\ResourceModel\Db\AbstractDb', + \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, [$contextMock], '', true, @@ -146,7 +149,7 @@ public function testExecute() ->method('getAllChildren') ->will($this->returnValue([1])); - $categoryMock = $this->getMock('Magento\Catalog\Model\Category', [], [], '', false); + $categoryMock = $this->getMock(\Magento\Catalog\Model\Category::class, [], [], '', false); $categoryMock->expects($this->once()) ->method('getResource') ->willReturn($abstractDbMock); @@ -156,11 +159,17 @@ public function testExecute() $categoryMock->expects($this->exactly(2)) ->method('getName') ->willReturn('category_name'); - $categoryMock->expects($this->exactly(5)) + $categoryMock->expects($this->exactly(4)) ->method('load') ->willReturnSelf(); - $productMock = $this->getMock('\Magento\Catalog\Model\Product', ['load', 'getSku', 'getName'], [], '', false); + $productMock = $this->getMock( + \Magento\Catalog\Model\Product::class, + ['load', 'getSku', 'getName'], + [], + '', + false + ); $productMock->expects($this->exactly(2)) ->method('load') ->willReturnSelf(); @@ -171,9 +180,15 @@ public function testExecute() ->method('getName') ->willReturn('product_name'); - $selectMock = $this->getMock('\Magento\Framework\DB\Select', [], [], '', false); + $selectMock = $this->getMock(\Magento\Framework\DB\Select::class, [], [], '', false); - $collectionMock = $this->getMock('\Magento\Catalog\Model\ResourceModel\Product\Collection', [], [], '', false); + $collectionMock = $this->getMock( + \Magento\Catalog\Model\ResourceModel\Product\Collection::class, + [], + [], + '', + false + ); $collectionMock->expects($this->once()) ->method('getSelect') ->willReturn($selectMock); @@ -183,15 +198,15 @@ public function testExecute() array_push( $mockObjects, - ['Magento\Store\Model\StoreManager', [], $storeManagerMock], - ['Magento\Catalog\Model\Category', $categoryMock], - ['Magento\Catalog\Model\Product', $productMock], - ['Magento\Framework\App\ResourceConnection', $resourceMock], - ['Magento\Catalog\Model\ResourceModel\Product\Collection', [], $collectionMock] + [\Magento\Store\Model\StoreManager::class, [], $storeManagerMock], + [\Magento\Catalog\Model\Category::class, $categoryMock], + [\Magento\Catalog\Model\Product::class, $productMock], + [\Magento\Framework\App\ResourceConnection::class, $resourceMock], + [\Magento\Catalog\Model\ResourceModel\Product\Collection::class, [], $collectionMock] ); - $objectManagerMock = $this->getMock('Magento\Framework\ObjectManager\ObjectManager', [], [], '', false); - $objectManagerMock->expects($this->exactly(32)) + $objectManagerMock = $this->getMock(\Magento\Framework\ObjectManager\ObjectManager::class, [], [], '', false); + $objectManagerMock->expects($this->exactly(31)) ->method('get') ->will($this->returnValueMap($mockObjects)); $objectManagerMock->expects($this->exactly(2)) @@ -203,7 +218,7 @@ public function testExecute() ->method('getValue') ->willReturn(1); $this->fixtureModelMock - ->expects($this->exactly(34)) + ->expects($this->exactly(33)) ->method('getObjectManager') ->willReturn($objectManagerMock); @@ -213,7 +228,7 @@ public function testExecute() public function testNoFixtureConfigValue() { $connectionMock = $this->getMockForAbstractClass( - '\Magento\Framework\DB\Adapter\AdapterInterface', + \Magento\Framework\DB\Adapter\AdapterInterface::class, [], '', true, @@ -224,16 +239,16 @@ public function testNoFixtureConfigValue() $connectionMock->expects($this->never()) ->method('query'); - $resourceMock = $this->getMock('Magento\Framework\App\ResourceConnection', [], [], '', false); + $resourceMock = $this->getMock(\Magento\Framework\App\ResourceConnection::class, [], [], '', false); $resourceMock->expects($this->never()) ->method('getConnection') ->with($this->equalTo('write')) ->willReturn($connectionMock); - $objectManagerMock = $this->getMock('Magento\Framework\ObjectManager\ObjectManager', [], [], '', false); + $objectManagerMock = $this->getMock(\Magento\Framework\ObjectManager\ObjectManager::class, [], [], '', false); $objectManagerMock->expects($this->never()) ->method('get') - ->with($this->equalTo('Magento\Framework\App\ResourceConnection')) + ->with($this->equalTo(\Magento\Framework\App\ResourceConnection::class)) ->willReturn($resourceMock); $this->fixtureModelMock