diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Edit.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Edit.php index 8e4b59d396986..38216ef98d2dd 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Edit.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Edit.php @@ -53,8 +53,10 @@ public function __construct( */ public function execute() { - $collection = $this->filter->getCollection($this->collectionFactory->create()); - $this->attributeHelper->setProductIds($collection->getAllIds()); + if ($this->getRequest()->getParam('filters')) { + $collection = $this->filter->getCollection($this->collectionFactory->create()); + $this->attributeHelper->setProductIds($collection->getAllIds()); + } if (!$this->_validateProducts()) { return $this->resultRedirectFactory->create()->setPath('catalog/product/', ['_current' => true]); diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Action/Attribute/EditTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Action/Attribute/EditTest.php new file mode 100644 index 0000000000000..9ce9d43db7b60 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Action/Attribute/EditTest.php @@ -0,0 +1,176 @@ +attributeHelper = $this->getMockBuilder('Magento\Catalog\Helper\Product\Edit\Action\Attribute') + ->setMethods(['getProductIds', 'setProductIds']) + ->disableOriginalConstructor()->getMock(); + + $this->resultRedirectFactory = $this->getMockBuilder('Magento\Backend\Model\View\Result\RedirectFactory') + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + + $this->filter = $this->getMockBuilder('Magento\Ui\Component\MassAction\Filter') + ->setMethods(['getCollection'])->disableOriginalConstructor()->getMock(); + + $this->collectionFactory = $this->getMockBuilder( + 'Magento\Catalog\Model\ResourceModel\Product\CollectionFactory' + )->setMethods(['create'])->disableOriginalConstructor()->getMock(); + + $this->resultPage = $this->getMockBuilder('Magento\Framework\View\Result\Page') + ->setMethods(['getConfig'])->disableOriginalConstructor()->getMock(); + + $resultPageFactory = $this->getMockBuilder('Magento\Framework\View\Result\PageFactory') + ->setMethods(['create'])->disableOriginalConstructor()->getMock(); + $resultPageFactory->expects($this->any())->method('create')->willReturn($this->resultPage); + + $this->prepareContext(); + + $this->object = (new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this))->getObject( + 'Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute\Edit', + [ + 'context' => $this->context, + 'attributeHelper' => $this->attributeHelper, + 'filter' => $this->filter, + 'resultPageFactory' => $resultPageFactory, + 'collectionFactory' => $this->collectionFactory + ] + ); + } + + private function prepareContext() + { + $this->request = $this->getMockBuilder('Magento\Framework\App\Request\Http') + ->setMethods(['getParam', 'getParams', 'setParams']) + ->disableOriginalConstructor()->getMock(); + + $objectManager = $this->getMock('Magento\Framework\ObjectManagerInterface'); + $product = $this->getMockBuilder('Magento\Catalog\Model\Product') + ->setMethods(['isProductsHasSku']) + ->disableOriginalConstructor()->getMock(); + $product->expects($this->any())->method('isProductsHasSku') + ->with([1, 2, 3]) + ->willReturn(true); + $objectManager->expects($this->any())->method('create') + ->with('Magento\Catalog\Model\Product') + ->willReturn($product); + $messageManager = $this->getMockBuilder('\Magento\Framework\Message\ManagerInterface') + ->setMethods([]) + ->disableOriginalConstructor()->getMock(); + $messageManager->expects($this->any())->method('addError')->willReturn(true); + $this->context = $this->getMockBuilder('Magento\Backend\App\Action\Context') + ->setMethods(['getRequest', 'getObjectManager', 'getMessageManager', 'getResultRedirectFactory']) + ->disableOriginalConstructor()->getMock(); + $this->context->expects($this->any())->method('getRequest')->willReturn($this->request); + $this->context->expects($this->any())->method('getObjectManager')->willReturn($objectManager); + $this->context->expects($this->any())->method('getMessageManager')->willReturn($messageManager); + $this->context->expects($this->any())->method('getResultRedirectFactory') + ->willReturn($this->resultRedirectFactory); + } + + public function testExecutePageRequested() + { + $this->request->expects($this->any())->method('getParam')->with('filters')->willReturn(['placeholder' => true]); + $this->request->expects($this->any())->method('getParams')->willReturn( + [ + 'namespace' => 'product_listing', + 'exclude' => true, + 'filters' => ['placeholder' => true] + ] + ); + + $this->attributeHelper->expects($this->any())->method('getProductIds')->willReturn([1, 2, 3]); + $this->attributeHelper->expects($this->any())->method('setProductIds')->with([1, 2, 3]); + + $collection = $this->getMockBuilder('Magento\Catalog\Model\ResourceModel\Product\Collection') + ->setMethods(['getAllIds']) + ->disableOriginalConstructor()->getMock(); + $collection->expects($this->any())->method('getAllIds')->willReturn([1, 2, 3]); + $this->filter->expects($this->any())->method('getCollection')->with($collection)->willReturn($collection); + $this->collectionFactory->expects($this->any())->method('create')->willReturn($collection); + + $title = $this->getMockBuilder('Magento\Framework\View\Page\Title') + ->setMethods(['prepend']) + ->disableOriginalConstructor()->getMock(); + $config = $this->getMockBuilder('Magento\Framework\View\Page\Config') + ->setMethods(['getTitle']) + ->disableOriginalConstructor()->getMock(); + $config->expects($this->any())->method('getTitle')->willReturn($title); + $this->resultPage->expects($this->any())->method('getConfig')->willReturn($config); + + $this->assertSame($this->resultPage, $this->object->execute()); + } + + public function testExecutePageReload() + { + $this->request->expects($this->any())->method('getParam')->with('filters')->willReturn(null); + $this->request->expects($this->any())->method('getParams')->willReturn([]); + + $this->attributeHelper->expects($this->any())->method('getProductIds')->willReturn([1, 2, 3]); + $this->attributeHelper->expects($this->any())->method('setProductIds')->with([1, 2, 3]); + + $title = $this->getMockBuilder('Magento\Framework\View\Page\Title') + ->setMethods(['prepend']) + ->disableOriginalConstructor()->getMock(); + $config = $this->getMockBuilder('Magento\Framework\View\Page\Config') + ->setMethods(['getTitle']) + ->disableOriginalConstructor()->getMock(); + $config->expects($this->any())->method('getTitle')->willReturn($title); + $this->resultPage->expects($this->any())->method('getConfig')->willReturn($config); + + $this->assertSame($this->resultPage, $this->object->execute()); + } + + public function testExecutePageDirectAccess() + { + $this->request->expects($this->any())->method('getParam')->with('filters')->willReturn(null); + $this->request->expects($this->any())->method('getParams')->willReturn([]); + $this->attributeHelper->expects($this->any())->method('getProductIds')->willReturn(null); + + $resultRedirect = $this->getMockBuilder('Magento\Backend\Model\View\Result\Redirect') + ->setMethods(['setPath']) + ->disableOriginalConstructor() + ->getMock(); + $resultRedirect->expects($this->any())->method('setPath') + ->with('catalog/product/', ['_current' => true]) + ->willReturnSelf(); + $this->resultRedirectFactory->expects($this->any()) + ->method('create') + ->willReturn($resultRedirect); + + $this->assertSame($resultRedirect, $this->object->execute()); + } +} diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/form/renderer/fieldset/element.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/form/renderer/fieldset/element.phtml index 5b50cdb8a1eaf..22f4385773240 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/form/renderer/fieldset/element.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/form/renderer/fieldset/element.phtml @@ -15,12 +15,12 @@ getElement(); -$note = $element->getNote() ? '
' . $element->getNote() . '
' : ''; +$note = $element->getNote() ? '
' . $element->getNote() . '
' : ''; $elementBeforeLabel = $element->getExtType() == 'checkbox' || $element->getExtType() == 'radio'; $addOn = $element->getBeforeElementHtml() || $element->getAfterElementHtml(); $fieldId = ($element->getHtmlId()) ? ' id="attribute-' . $element->getHtmlId() . '-container"' : ''; $entity = $element->getEntityAttribute(); -$fieldClass = "field field-{$element->getId()} {$element->getCssClass()}"; +$fieldClass = "admin__field field field-{$element->getId()} {$element->getCssClass()}"; $fieldClass .= ($elementBeforeLabel) ? ' choice' : ''; $fieldClass .= ($addOn) ? ' with-addon' : ''; $fieldClass .= ($element->getRequired()) ? ' required' : ''; @@ -51,7 +51,7 @@ $fieldAttributes = $fieldId . ' class="' . $fieldClass . '" ' getLabelHtml('', $block->getScopeLabel()) ?> -
+
' . $block->getElementHtml() . '
' : $block->getElementHtml(); ?>
diff --git a/app/code/Magento/CatalogImportExport/Model/Export/Product.php b/app/code/Magento/CatalogImportExport/Model/Export/Product.php index b6a68d413cab0..206b2d8b59d9d 100644 --- a/app/code/Magento/CatalogImportExport/Model/Export/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Export/Product.php @@ -762,6 +762,8 @@ protected function getItemsPerPage() $memoryUsagePercent = 0.8; // Minimum Products limit $minProductsLimit = 500; + // Maximal Products limit + $maxProductsLimit = 5000; $this->_itemsPerPage = intval( ($memoryLimit * $memoryUsagePercent - memory_get_usage(true)) / $memoryPerProduct @@ -769,6 +771,9 @@ protected function getItemsPerPage() if ($this->_itemsPerPage < $minProductsLimit) { $this->_itemsPerPage = $minProductsLimit; } + if ($this->_itemsPerPage > $maxProductsLimit) { + $this->_itemsPerPage = $maxProductsLimit; + } } return $this->_itemsPerPage; } @@ -850,8 +855,10 @@ protected function getExportData() if ($storeId == Store::DEFAULT_STORE_ID && isset($stockItemRows[$productId])) { $dataRow = array_merge($dataRow, $stockItemRows[$productId]); } - - $exportData = array_merge($exportData, $this->addMultirowData($dataRow, $multirawData)); + $this->appendMultirowData($dataRow, $multirawData); + if ($dataRow) { + $exportData[] = $dataRow; + } } } } catch (\Exception $e) { @@ -1053,9 +1060,8 @@ protected function isValidAttributeValue($code, $value) * @SuppressWarnings(PHPMD.NPathComplexity) * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ - protected function addMultirowData($dataRow, $multiRawData) + private function appendMultirowData(&$dataRow, &$multiRawData) { - $result = []; $productId = $dataRow['product_id']; $productLinkId = $dataRow['product_link_id']; $storeId = $dataRow['store_id']; @@ -1121,7 +1127,6 @@ protected function addMultirowData($dataRow, $multiRawData) } } $dataRow = $this->rowCustomizer->addData($dataRow, $productId); - } if (!empty($this->collectedMultiselectsData[$storeId][$productId])) { @@ -1144,7 +1149,7 @@ protected function addMultirowData($dataRow, $multiRawData) } if (empty($dataRow)) { - return $result; + return null; } elseif ($storeId != Store::DEFAULT_STORE_ID) { $dataRow[self::COL_STORE] = $this->_storeIdToCode[$storeId]; if (isset($productData[Store::DEFAULT_STORE_ID][self::COL_VISIBILITY])) { @@ -1152,9 +1157,19 @@ protected function addMultirowData($dataRow, $multiRawData) } } $dataRow[self::COL_SKU] = $sku; - $result[] = $dataRow; + return $dataRow; + } - return $result; + /** + * @deprecated + * @param array $dataRow + * @param array $multiRawData + * @return array + */ + protected function addMultirowData($dataRow, $multiRawData) + { + $data = $this->appendMultirowData($dataRow, $multiRawData); + return $data ? [$data] : []; } /** diff --git a/app/code/Magento/Checkout/Model/Cart.php b/app/code/Magento/Checkout/Model/Cart.php index 585a1ed5336cf..579eb998e06af 100644 --- a/app/code/Magento/Checkout/Model/Cart.php +++ b/app/code/Magento/Checkout/Model/Cart.php @@ -321,9 +321,6 @@ protected function _getProductRequest($requestInfo) $request = new \Magento\Framework\DataObject($requestInfo); } - if (!$request->hasQty()) { - $request->setQty(1); - } !$request->hasFormKey() ?: $request->unsFormKey(); return $request; @@ -350,7 +347,7 @@ public function addProduct($productInfo, $requestInfo = null) //If product was not found in cart and there is set minimal qty for it if ($minimumQty && $minimumQty > 0 - && $request->getQty() < $minimumQty + && !$request->getQty() && !$this->getQuote()->hasProductId($productId) ) { $request->setQty($minimumQty); @@ -690,7 +687,7 @@ public function updateItem($itemId, $requestInfo = null, $updatingParams = null) // If product was not found in cart and there is set minimal qty for it if ($minimumQty && $minimumQty > 0 - && $request->getQty() < $minimumQty + && !$request->getQty() && !$this->getQuote()->hasProductId($productId) ) { $request->setQty($minimumQty); diff --git a/app/code/Magento/Cms/Model/Page/DataProvider.php b/app/code/Magento/Cms/Model/Page/DataProvider.php index fb9a54be74457..3771d55535e06 100644 --- a/app/code/Magento/Cms/Model/Page/DataProvider.php +++ b/app/code/Magento/Cms/Model/Page/DataProvider.php @@ -49,6 +49,18 @@ public function __construct( $this->collection = $pageCollectionFactory->create(); $this->dataPersistor = $dataPersistor; parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data); + $this->meta = $this->prepareMeta($this->meta); + } + + /** + * Prepares Meta + * + * @param array $meta + * @return array + */ + public function prepareMeta(array $meta) + { + return $meta; } /** diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/Source/Table.php b/app/code/Magento/Eav/Model/Entity/Attribute/Source/Table.php index 04b414a70a245..bbad307d28f90 100644 --- a/app/code/Magento/Eav/Model/Entity/Attribute/Source/Table.php +++ b/app/code/Magento/Eav/Model/Entity/Attribute/Source/Table.php @@ -138,18 +138,20 @@ public function getOptionText($value) */ public function addValueSortToCollection($collection, $dir = \Magento\Framework\DB\Select::SQL_ASC) { - $valueTable1 = $this->getAttribute()->getAttributeCode() . '_t1'; - $valueTable2 = $this->getAttribute()->getAttributeCode() . '_t2'; + $attribute = $this->getAttribute(); + $valueTable1 = $attribute->getAttributeCode() . '_t1'; + $valueTable2 = $attribute->getAttributeCode() . '_t2'; + $linkField = $attribute->getEntity()->getLinkField(); $collection->getSelect()->joinLeft( - [$valueTable1 => $this->getAttribute()->getBackend()->getTable()], - "e.entity_id={$valueTable1}.entity_id" . - " AND {$valueTable1}.attribute_id='{$this->getAttribute()->getId()}'" . + [$valueTable1 => $attribute->getBackend()->getTable()], + "e.{$linkField}={$valueTable1}." . $linkField . + " AND {$valueTable1}.attribute_id='{$attribute->getId()}'" . " AND {$valueTable1}.store_id=0", [] )->joinLeft( - [$valueTable2 => $this->getAttribute()->getBackend()->getTable()], - "e.entity_id={$valueTable2}.entity_id" . - " AND {$valueTable2}.attribute_id='{$this->getAttribute()->getId()}'" . + [$valueTable2 => $attribute->getBackend()->getTable()], + "e.{$linkField}={$valueTable2}." . $linkField . + " AND {$valueTable2}.attribute_id='{$attribute->getId()}'" . " AND {$valueTable2}.store_id='{$collection->getStoreId()}'", [] ); @@ -161,11 +163,11 @@ public function addValueSortToCollection($collection, $dir = \Magento\Framework\ $this->_attrOptionFactory->create()->addOptionValueToCollection( $collection, - $this->getAttribute(), + $attribute, $valueExpr ); - $collection->getSelect()->order("{$this->getAttribute()->getAttributeCode()} {$dir}"); + $collection->getSelect()->order("{$attribute->getAttributeCode()} {$dir}"); return $this; } diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/Source/TableTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/Source/TableTest.php index de1a5e6cbae4d..3e7cdb9cc2500 100644 --- a/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/Source/TableTest.php +++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/Source/TableTest.php @@ -5,7 +5,6 @@ */ namespace Magento\Eav\Test\Unit\Model\Entity\Attribute\Source; -use Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\CollectionFactory; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; class TableTest extends \PHPUnit_Framework_TestCase @@ -13,12 +12,18 @@ class TableTest extends \PHPUnit_Framework_TestCase /** * @var \Magento\Eav\Model\Entity\Attribute\Source\Table */ - protected $_model; + private $model; /** - * @var CollectionFactory | \PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\CollectionFactory + * | \PHPUnit_Framework_MockObject_MockObject */ - protected $collectionFactory; + private $collectionFactory; + + /** + * @var \Magento\Eav\Model\ResourceModel\Entity\Attribute\OptionFactory | \PHPUnit_Framework_MockObject_MockObject + */ + private $attrOptionFactory; protected function setUp() { @@ -40,9 +45,19 @@ protected function setUp() false ); - $this->_model = $objectManager->getObject( + $this->attrOptionFactory = $this->getMockBuilder( + 'Magento\Eav\Model\ResourceModel\Entity\Attribute\OptionFactory' + ) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->model = $objectManager->getObject( 'Magento\Eav\Model\Entity\Attribute\Source\Table', - ['attrOptionCollectionFactory' => $this->collectionFactory] + [ + 'attrOptionCollectionFactory' => $this->collectionFactory, + 'attrOptionFactory' => $this->attrOptionFactory + ] ); } @@ -74,9 +89,9 @@ public function testGetFlatColumns() $abstractAttributeMock->expects($this->any())->method('getAttributeCode')->will($this->returnValue('code')); - $this->_model->setAttribute($abstractAttributeMock); + $this->model->setAttribute($abstractAttributeMock); - $flatColumns = $this->_model->getFlatColumns(); + $flatColumns = $this->model->getFlatColumns(); $this->assertTrue(is_array($flatColumns), 'FlatColumns must be an array value'); $this->assertTrue(!empty($flatColumns), 'FlatColumns must be not empty'); @@ -117,7 +132,7 @@ public function testGetSpecificOptions($optionIds, $withEmpty) ->method('getStoreId') ->willReturn($storeId); - $this->_model->setAttribute($attribute); + $this->model->setAttribute($attribute); $this->collectionFactory->expects($this->once()) ->method('create') @@ -148,7 +163,7 @@ public function testGetSpecificOptions($optionIds, $withEmpty) array_unshift($options, ['label' => '', 'value' => '']); } - $this->assertEquals($options, $this->_model->getSpecificOptions($optionIds, $withEmpty)); + $this->assertEquals($options, $this->model->getSpecificOptions($optionIds, $withEmpty)); } public function specificOptionsProvider() @@ -184,7 +199,7 @@ public function testGetOptionText($optionsIds, $value, $options, $expectedResult ->method('getStoreId') ->willReturn($storeId); - $this->_model->setAttribute($attribute); + $this->model->setAttribute($attribute); $this->collectionFactory->expects($this->once()) ->method('create') @@ -211,7 +226,7 @@ public function testGetOptionText($optionsIds, $value, $options, $expectedResult ->method('toOptionArray') ->willReturn($options); - $this->assertEquals($expectedResult, $this->_model->getOptionText($value)); + $this->assertEquals($expectedResult, $this->model->getOptionText($value)); } public function getOptionTextProvider() @@ -227,4 +242,57 @@ public function getOptionTextProvider() ['5', '5', [['label' => 'test label', 'value' => '5']], 'test label'] ]; } + + public function testAddValueSortToCollection() + { + $attributeCode = 'attribute_code'; + $dir = \Magento\Framework\DB\Select::SQL_ASC; + $collection = $this->getMockBuilder('Magento\Eav\Model\Entity\Collection\AbstractCollection') + ->setMethods([ 'getSelect', 'getStoreId']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $attribute = $this->getMockBuilder('Magento\Eav\Model\Entity\Attribute\AbstractAttribute') + ->setMethods(['getAttributeCode', 'getEntity', 'getBackend', 'getId']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $attribute->expects($this->any())->method('getAttributeCode')->willReturn($attributeCode); + $entity = $this->getMockBuilder('Magento\Eav\Model\Entity\AbstractEntity') + ->setMethods(['getLinkField']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $attribute->expects($this->once())->method('getEntity')->willReturn($entity); + $entity->expects($this->once())->method('getLinkField')->willReturn('entity_id'); + $select = $this->getMockBuilder('Magento\Framework\DB\Select') + ->setMethods(['joinLeft', 'getConnection', 'order']) + ->disableOriginalConstructor() + ->getMock(); + $collection->expects($this->any())->method('getSelect')->willReturn($select); + $select->expects($this->any())->method('joinLeft')->willReturnSelf(); + $backend = $this->getMockBuilder('Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend') + ->setMethods(['getTable']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $attribute->expects($this->any())->method('getBackend')->willReturn($backend); + $backend->expects($this->any())->method('getTable')->willReturn('table_name'); + $attribute->expects($this->any())->method('getId')->willReturn(1); + $collection->expects($this->once())->method('getStoreId')->willReturn(1); + $connection = $this->getMockBuilder('Magento\Framework\DB\Adapter\AdapterInterface') + ->disableOriginalConstructor() + ->getMock(); + $expr = $this->getMockBuilder('Zend_Db_Expr') + ->disableOriginalConstructor() + ->getMock(); + $connection->expects($this->once())->method('getCheckSql')->willReturn($expr); + $select->expects($this->once())->method('getConnection')->willReturn($connection); + $attrOption = $this->getMockBuilder('Magento\Eav\Model\ResourceModel\Entity\Attribute\Option') + ->disableOriginalConstructor() + ->getMock(); + $this->attrOptionFactory->expects($this->once())->method('create')->willReturn($attrOption); + $attrOption->expects($this->once())->method('addOptionValueToCollection')->with($collection, $attribute, $expr) + ->willReturnSelf(); + $select->expects($this->once())->method('order')->with("{$attributeCode} {$dir}"); + + $this->model->setAttribute($attribute); + $this->assertEquals($this->model, $this->model->addValueSortToCollection($collection, $dir)); + } } diff --git a/app/code/Magento/GoogleOptimizer/Block/Adminhtml/Cms/Page/Edit/Tab/Googleoptimizer.php b/app/code/Magento/GoogleOptimizer/Block/Adminhtml/Cms/Page/Edit/Tab/Googleoptimizer.php index bf903745f9fb8..be1ead2238080 100644 --- a/app/code/Magento/GoogleOptimizer/Block/Adminhtml/Cms/Page/Edit/Tab/Googleoptimizer.php +++ b/app/code/Magento/GoogleOptimizer/Block/Adminhtml/Cms/Page/Edit/Tab/Googleoptimizer.php @@ -7,6 +7,9 @@ */ namespace Magento\GoogleOptimizer\Block\Adminhtml\Cms\Page\Edit\Tab; +/** + * @deprecated + */ class Googleoptimizer extends \Magento\GoogleOptimizer\Block\Adminhtml\AbstractTab { /** diff --git a/app/code/Magento/GoogleOptimizer/Block/Adminhtml/Cms/Page/EntityCmsPage.php b/app/code/Magento/GoogleOptimizer/Block/Adminhtml/Cms/Page/EntityCmsPage.php new file mode 100644 index 0000000000000..6d4c96172d164 --- /dev/null +++ b/app/code/Magento/GoogleOptimizer/Block/Adminhtml/Cms/Page/EntityCmsPage.php @@ -0,0 +1,81 @@ +coreRegistry = $registry; + $this->codeModel = $code; + parent::__construct($data); + } + + /** + * Returns Code Model + * + * @return GoogleOptimizerCode|null + * @throws NoSuchEntityException + */ + public function getCode() + { + $code = null; + $entity = $this->getEntity(); + if ($entity->getId()) { + $this->codeModel->loadByEntityIdAndType($entity->getId(), GoogleOptimizerCode::ENTITY_TYPE_PAGE); + $code = $this->codeModel; + } + return $code; + } + + /** + * Retrieves Google Optimizer binded entity + * + * @return \Magento\Cms\Model\Page|mixed + * @throws NoSuchEntityException + */ + private function getEntity() + { + if (!$this->entity) { + $this->entity = $this->coreRegistry->registry('cms_page'); + if (!$this->entity) { + throw new NoSuchEntityException(); + } + } + return $this->entity; + } +} diff --git a/app/code/Magento/GoogleOptimizer/Block/Adminhtml/Form.php b/app/code/Magento/GoogleOptimizer/Block/Adminhtml/Form.php new file mode 100644 index 0000000000000..40a50e3c87e69 --- /dev/null +++ b/app/code/Magento/GoogleOptimizer/Block/Adminhtml/Form.php @@ -0,0 +1,63 @@ +formHelper = $formHelper; + $this->setForm($formFactory->create()); + } + + /** + * @inheritdoc + */ + protected function _prepareForm() + { + $entityClass = $this->getData('code-entity'); + $formName = $this->getData('form-name'); + if (!$entityClass) { + throw new ConfigurationMismatchException(__('Data key is missing: %1', ['code-entity'])); + } + if (!$formName) { + throw new ConfigurationMismatchException(__('Data key is missing: %1', ['form-name'])); + } + + $entity = ObjectManager::getInstance()->create($entityClass); + + $this->formHelper->addGoogleoptimizerFields($this->getForm(), $entity->getCode(), $formName); + $this->getForm()->getElement('googleoptimizer_fields')->setData(['legend' => null]); + return parent::_prepareForm(); + } +} diff --git a/app/code/Magento/GoogleOptimizer/Model/Plugin/Cms/Page/DataProvider.php b/app/code/Magento/GoogleOptimizer/Model/Plugin/Cms/Page/DataProvider.php new file mode 100644 index 0000000000000..26fd70e747417 --- /dev/null +++ b/app/code/Magento/GoogleOptimizer/Model/Plugin/Cms/Page/DataProvider.php @@ -0,0 +1,40 @@ +helper = $helper; + } + + /** + * @param \Magento\Cms\Model\Page\DataProvider $subject + * @param array $result + * @return mixed + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterPrepareMeta(\Magento\Cms\Model\Page\DataProvider $subject, $result) + { + $result['page_view_optimization']['arguments']['data']['disabled'] = !$this->helper->isGoogleExperimentActive(); + $result['page_view_optimization']['arguments']['data']['config']['componentType'] = + \Magento\Ui\Component\Form\Fieldset::NAME; + $result['page_view_optimization']['arguments']['data']['config']['label'] = __('Page View Optimization'); + return $result; + } +} diff --git a/app/code/Magento/GoogleOptimizer/etc/adminhtml/di.xml b/app/code/Magento/GoogleOptimizer/etc/adminhtml/di.xml index 1b7aa152f6ed6..af6326d312ff9 100644 --- a/app/code/Magento/GoogleOptimizer/etc/adminhtml/di.xml +++ b/app/code/Magento/GoogleOptimizer/etc/adminhtml/di.xml @@ -16,6 +16,17 @@ + + + + Magento\GoogleOptimizer\Block\Adminhtml\Cms\Page\EntityCmsPage + cms_page_form + + + + + + diff --git a/app/code/Magento/GoogleOptimizer/view/adminhtml/ui_component/cms_page_form.xml b/app/code/Magento/GoogleOptimizer/view/adminhtml/ui_component/cms_page_form.xml new file mode 100644 index 0000000000000..c27ea723a0570 --- /dev/null +++ b/app/code/Magento/GoogleOptimizer/view/adminhtml/ui_component/cms_page_form.xml @@ -0,0 +1,28 @@ + + +
+
+ + + Page View Optimization + true + + + + + + 250 + + + + Magento\GoogleOptimizer\Block\Adminhtml\Form\CmsPage + + +
+
diff --git a/app/code/Magento/ImportExport/Model/Import/ErrorProcessing/ProcessingErrorAggregator.php b/app/code/Magento/ImportExport/Model/Import/ErrorProcessing/ProcessingErrorAggregator.php index 35bda74df5237..262b773165b85 100644 --- a/app/code/Magento/ImportExport/Model/Import/ErrorProcessing/ProcessingErrorAggregator.php +++ b/app/code/Magento/ImportExport/Model/Import/ErrorProcessing/ProcessingErrorAggregator.php @@ -89,8 +89,9 @@ public function addError( /** @var ProcessingError $newError */ $newError = $this->errorFactory->create(); $newError->init($errorCode, $errorLevel, $rowNumber, $columnName, $errorMessage, $errorDescription); - $this->items[] = $newError; - + $this->items['rows'][$rowNumber][] = $newError; + $this->items['codes'][$errorCode][] = $newError; + $this->items['messages'][$errorMessage][] = $newError; return $this; } @@ -209,13 +210,21 @@ public function hasFatalExceptions() return (bool)$this->getErrorsCount([ProcessingError::ERROR_LEVEL_CRITICAL]); } - /** * @return ProcessingError[] */ public function getAllErrors() { - return $this->items; + $result = []; + if (empty($this->items)) { + return $result; + } + + foreach (array_values($this->items['rows']) as $errors) { + $result = array_merge($result, $errors); + } + + return $result; } /** @@ -225,9 +234,9 @@ public function getAllErrors() public function getErrorsByCode(array $codes) { $result = []; - foreach ($this->items as $error) { - if (in_array($error->getErrorCode(), $codes)) { - $result[] = $error; + foreach ($codes as $code) { + if (isset($this->items['codes'][$code])) { + $result = array_merge($result, $this->items['codes'][$code]); } } @@ -241,10 +250,8 @@ public function getErrorsByCode(array $codes) public function getErrorByRowNumber($rowNumber) { $result = []; - foreach ($this->items as $error) { - if ($error->getRowNumber() == (int)$rowNumber) { - $result[] = $error; - } + if (isset($this->items['rows'][$rowNumber])) { + $result = $this->items['rows'][$rowNumber]; } return $result; @@ -261,16 +268,26 @@ public function getRowsGroupedByErrorCode( array $excludedCodes = [], $replaceCodeWithMessage = true ) { + if (empty($this->items)) { + return []; + } + $allCodes = array_keys($this->items['codes']); + if (!empty($excludedCodes)) { + $allCodes = array_diff($allCodes, $excludedCodes); + } + if (!empty($errorCode)) { + $allCodes = array_intersect($errorCode, $allCodes); + } + $result = []; - foreach ($this->items as $error) { - if ((!empty($errorCode) && in_array($error->getErrorCode(), $errorCode)) - || in_array($error->getErrorCode(), $excludedCodes) - ) { - continue; + foreach ($allCodes as $code) { + $errors = $this->getErrorsByCode([$code]); + foreach ($errors as $error) { + $key = $replaceCodeWithMessage ? $error->getErrorMessage() : $code; + $result[$key][] = $error->getRowNumber() + 1; } - $message = $replaceCodeWithMessage ? $error->getErrorMessage() : $error->getErrorCode(); - $result[$message][] = $error->getRowNumber()+1; } + return $result; } diff --git a/app/code/Magento/ImportExport/Test/Unit/Model/Import/ErrorProcessing/ProcessingErrorAggregatorTest.php b/app/code/Magento/ImportExport/Test/Unit/Model/Import/ErrorProcessing/ProcessingErrorAggregatorTest.php index 3a534ce5adcf8..f8859da4f6f8a 100644 --- a/app/code/Magento/ImportExport/Test/Unit/Model/Import/ErrorProcessing/ProcessingErrorAggregatorTest.php +++ b/app/code/Magento/ImportExport/Test/Unit/Model/Import/ErrorProcessing/ProcessingErrorAggregatorTest.php @@ -117,10 +117,7 @@ public function testAddErrorMessageTemplate() $this->model->addError('columnNotFound', 'critical', 7, 'Some column name', null, 'Description'); $this->model->addError('columnEmptyHeader', 'not-critical', 4, 'Some column name', 'No header', 'Description'); $result = $this->model->getRowsGroupedByErrorCode(['systemException']); - $expectedResult = [ - 'Template: No column' => [8], - 'No header' => [5] - ]; + $expectedResult = ['systemException' => [0 => 1]]; $this->assertEquals($expectedResult, $result); } @@ -348,20 +345,73 @@ public function testGetErrorsByCodeNotInArray() /** * Test for method getRowsGroupedByErrorCode. Expects errors. + * + * @param array $params + * @param array $expectedResult + * + * @dataProvider getRowsGroupedByErrorCodeWithErrorsDataProvider */ - public function testGetRowsGroupedByErrorCodeWithErrors() + public function testGetRowsGroupedByErrorCodeWithErrors(array $params = [], array $expectedResult = []) { $this->model->addError('systemException'); $this->model->addError('columnNotFound', 'critical', 7, 'Some column name', 'No column', 'Description'); $this->model->addError('columnEmptyHeader', 'not-critical', 4, 'Some column name', 'No header', 'Description'); - $result = $this->model->getRowsGroupedByErrorCode(['systemException']); - $expectedResult = [ - 'No column' => [8], - 'No header' => [5] - ]; + + $result = call_user_func_array([$this->model, 'getRowsGroupedByErrorCode'], $params); + $this->assertEquals($expectedResult, $result); } + /** + * @return array + */ + public function getRowsGroupedByErrorCodeWithErrorsDataProvider() + { + $errorCode1 = 'systemException'; + $errorCode2 = 'columnNotFound'; + $errorCode3 = 'columnEmptyHeader'; + + $message1 = 'systemException'; + $message2 = 'No column'; + $message3 = 'No header'; + + return [ + [ + [[$errorCode1]], + [$message1 => [1]] + ], + [ + [[], [$errorCode2]], + [$message1 => [1], $message3 => [5]] + ], + [ + [[$errorCode3, $errorCode2], [$errorCode2]], + [$message3 => [5]] + ], + [ + [[], []], + [$message1 => [1], $message2 => [8], $message3 => [5]] + ], + + [ + [[$errorCode1], [], false], + [$errorCode1 => [1]] + ], + [ + [[], [$errorCode2], false], + [$errorCode1 => [1], $errorCode3 => [5]] + ], + [ + [[$errorCode3, $errorCode2], [$errorCode2], false], + [$errorCode3 => [5]] + ], + [ + [[], [], false], + [$errorCode1 => [1], $errorCode2 => [8], $errorCode3 => [5]] + ], + ]; + } + /** * Test for method getRowsGroupedByErrorCode. Unexpects errors. */ diff --git a/app/code/Magento/Rss/view/frontend/templates/feeds.phtml b/app/code/Magento/Rss/view/frontend/templates/feeds.phtml index 86211e9977d7b..81ac6fd803259 100644 --- a/app/code/Magento/Rss/view/frontend/templates/feeds.phtml +++ b/app/code/Magento/Rss/view/frontend/templates/feeds.phtml @@ -14,7 +14,7 @@ getFeeds() as $feed): ?> - + escapeHtml($feed['label']) ?> @@ -23,7 +23,7 @@ - + escapeHtml($item['label']) ?> diff --git a/app/code/Magento/Swatches/Block/Product/Renderer/Configurable.php b/app/code/Magento/Swatches/Block/Product/Renderer/Configurable.php index 0d06c0176980a..4546a01529d33 100644 --- a/app/code/Magento/Swatches/Block/Product/Renderer/Configurable.php +++ b/app/code/Magento/Swatches/Block/Product/Renderer/Configurable.php @@ -404,7 +404,7 @@ protected function getHtmlOutput() */ public function getMediaCallback() { - return $this->getBaseUrl() . self::MEDIA_CALLBACK_ACTION; + return $this->getUrl(self::MEDIA_CALLBACK_ACTION, ['_secure' => $this->getRequest()->isSecure()]); } /** diff --git a/app/code/Magento/Swatches/Model/Plugin/Configurable.php b/app/code/Magento/Swatches/Model/Plugin/Configurable.php new file mode 100644 index 0000000000000..05a575b820816 --- /dev/null +++ b/app/code/Magento/Swatches/Model/Plugin/Configurable.php @@ -0,0 +1,61 @@ +eavConfig = $eavConfig; + $this->swatchHelper = $swatchHelper; + } + + /** + * Returns Configurable Products Collection with added swatch attributes + * + * @param ConfigurableProduct $subject + * @param Collection $result + * @return Collection + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterGetUsedProductCollection( + ConfigurableProductType $subject, + Collection $result + ) { + $attributeCodes = ['image']; + $entityType = $result->getEntity()->getType(); + + foreach ($this->eavConfig->getEntityAttributeCodes($entityType) as $code) { + $attribute = $this->eavConfig->getAttribute($entityType, $code); + if ($this->swatchHelper->isVisualSwatch($attribute) || $this->swatchHelper->isTextSwatch($attribute)) { + $attributeCodes[] = $code; + } + } + $result->addAttributeToSelect($attributeCodes); + return $result; + } +} diff --git a/app/code/Magento/Swatches/Test/Unit/Block/Product/Renderer/ConfigurableTest.php b/app/code/Magento/Swatches/Test/Unit/Block/Product/Renderer/ConfigurableTest.php index e32e263391cb1..44ea9663bc86c 100644 --- a/app/code/Magento/Swatches/Test/Unit/Block/Product/Renderer/ConfigurableTest.php +++ b/app/code/Magento/Swatches/Test/Unit/Block/Product/Renderer/ConfigurableTest.php @@ -323,7 +323,13 @@ public function testGetJsonSwatchConfigWithoutVisualImageType() public function testGetMediaCallback() { - $this->urlBuilder->expects($this->once())->method('getBaseUrl')->willReturn('http://magento.com/'); - $this->assertContains(Configurable::MEDIA_CALLBACK_ACTION, $this->configurable->getMediaCallback()); + $url = 'http://localhost/' . Configurable::MEDIA_CALLBACK_ACTION; + + $this->urlBuilder->expects($this->once()) + ->method('getUrl') + ->with(Configurable::MEDIA_CALLBACK_ACTION) + ->willReturn($url); + + $this->assertEquals($url, $this->configurable->getMediaCallback()); } } diff --git a/app/code/Magento/Swatches/Test/Unit/Model/Plugin/ConfigurableTest.php b/app/code/Magento/Swatches/Test/Unit/Model/Plugin/ConfigurableTest.php new file mode 100644 index 0000000000000..f4a657b453c57 --- /dev/null +++ b/app/code/Magento/Swatches/Test/Unit/Model/Plugin/ConfigurableTest.php @@ -0,0 +1,86 @@ +eavConfig = $this->getMock( + '\Magento\Eav\Model\Config', + ['getEntityAttributeCodes', 'getAttribute'], + [], + '', + false + ); + $this->swatchHelper = $this->getMock( + '\Magento\Swatches\Helper\Data', + ['isVisualSwatch', 'isTextSwatch'], + [], + '', + false + ); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->pluginModel = $objectManager->getObject( + '\Magento\Swatches\Model\Plugin\Configurable', + [ + 'eavConfig' => $this->eavConfig, + 'swatchHelper' => $this->swatchHelper, + ] + ); + } + + public function testAfterGetUsedProductCollection() + { + $subject = $this->getMock('\Magento\ConfigurableProduct\Model\Product\Type\Configurable', [], [], '', false); + $result = $this->getMock( + '\Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\Collection', + ['getEntity', 'addAttributeToSelect'], + [], + '', + false + ); + + $collectionEntity = $this->getMock( + '\Magento\Eav\Model\Entity\Collection\AbstractCollection', + ['getType'], + [], + '', + false + ); + $collectionEntity->expects($this->once())->method('getType')->willReturn('catalog'); + $result->expects($this->once())->method('getEntity')->willReturn($collectionEntity); + + $attribute = $this->getMock('\Magento\Catalog\Model\ResourceModel\Eav\Attribute', [], [], '', false); + + $this->eavConfig->expects($this->once())->method('getEntityAttributeCodes')->with('catalog') + ->willReturn(['size', 'color', 'swatch1']); + + $this->eavConfig->expects($this->exactly(3))->method('getAttribute')->willReturn($attribute); + + $this->swatchHelper->expects($this->exactly(3))->method('isVisualSwatch')->with($attribute)->willReturn(true); + + $result->expects($this->once())->method('addAttributeToSelect') + ->with($this->identicalTo(['image', 'size', 'color', 'swatch1']))->willReturn($result); + + $result = $this->pluginModel->afterGetUsedProductCollection($subject, $result); + $this->assertInstanceOf( + '\Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\Collection', + $result + ); + } +} diff --git a/app/code/Magento/Swatches/etc/di.xml b/app/code/Magento/Swatches/etc/di.xml index f73753acfb714..f91a525777606 100644 --- a/app/code/Magento/Swatches/etc/di.xml +++ b/app/code/Magento/Swatches/etc/di.xml @@ -18,6 +18,9 @@ + + + diff --git a/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js b/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js index e3e7ccb848782..17f52b5d5f68f 100644 --- a/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js +++ b/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js @@ -106,14 +106,6 @@ define([ this.backendType.val('int'); } - if (this.frontendInput.is(':visible') && - (this.frontendInput.val() === 'swatch_text' || this.frontendInput.val() === 'swatch_visual') - ) { - this.usedInProductListing.val(1); - this.isVisibleOnFront.val(1); - this.updateProductPreviewImage.val(1); - } - if (this.frontendInput.val() === 'multiselect' || this.frontendInput.val() === 'gallery' || this.frontendInput.val() === 'textarea' diff --git a/app/code/Magento/Swatches/view/frontend/templates/product/layered/renderer.phtml b/app/code/Magento/Swatches/view/frontend/templates/product/layered/renderer.phtml index 5f26d947a5d4f..2b3c9f148360f 100644 --- a/app/code/Magento/Swatches/view/frontend/templates/product/layered/renderer.phtml +++ b/app/code/Magento/Swatches/view/frontend/templates/product/layered/renderer.phtml @@ -69,7 +69,7 @@