diff --git a/app/code/Magento/Backend/Block/Widget/Grid.php b/app/code/Magento/Backend/Block/Widget/Grid.php index ee8b36cdea847789cdde5e7876e7d5609a586848..66bc193719784b684d6b7b212790aa49686b831e 100644 --- a/app/code/Magento/Backend/Block/Widget/Grid.php +++ b/app/code/Magento/Backend/Block/Widget/Grid.php @@ -760,7 +760,7 @@ class Grid extends \Magento\Backend\Block\Widget */ public function getJsObjectName() { - return $this->getId() . 'JsObject'; + return preg_replace("~[^a-z0-9_]*~i", '', $this->getId()) . 'JsObject'; } /** diff --git a/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/AbstractFilter.php b/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/AbstractFilter.php index 0a0e612eab9ced6d7cdcaa0715cc28a9f4b6f535..a512da3522c4229e7b41114a2559879f4f5993a7 100644 --- a/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/AbstractFilter.php +++ b/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/AbstractFilter.php @@ -67,7 +67,7 @@ class AbstractFilter extends \Magento\Backend\Block\AbstractBlock implements */ protected function _getHtmlName() { - return $this->getColumn()->getId(); + return $this->escapeHtml($this->getColumn()->getId()); } /** @@ -77,7 +77,7 @@ class AbstractFilter extends \Magento\Backend\Block\AbstractBlock implements */ protected function _getHtmlId() { - return $this->getColumn()->getHtmlId(); + return $this->escapeHtml($this->getColumn()->getHtmlId()); } /** @@ -88,7 +88,7 @@ class AbstractFilter extends \Magento\Backend\Block\AbstractBlock implements */ public function getEscapedValue($index = null) { - return htmlspecialchars((string)$this->getValue($index)); + return $this->escapeHtml((string)$this->getValue($index)); } /** diff --git a/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/TextTest.php b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/TextTest.php new file mode 100644 index 0000000000000000000000000000000000000000..a59b23f8d3ca722854983f16833b773dd432f87a --- /dev/null +++ b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/TextTest.php @@ -0,0 +1,68 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Backend\Test\Unit\Block\Widget\Grid\Column\Filter; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; + +class TextTest extends \PHPUnit_Framework_TestCase +{ + /** @var \Magento\Backend\Block\Widget\Grid\Column\Filter\Text*/ + protected $block; + + /** @var ObjectManagerHelper */ + protected $objectManagerHelper; + + /** @var \Magento\Backend\Block\Context|\PHPUnit_Framework_MockObject_MockObject */ + protected $context; + + /** @var \Magento\Framework\DB\Helper|\PHPUnit_Framework_MockObject_MockObject */ + protected $helper; + + /** @var \Magento\Framework\Escaper|\PHPUnit_Framework_MockObject_MockObject */ + protected $escaper; + + protected function setUp() + { + $this->context = $this->getMockBuilder('Magento\Backend\Block\Context') + ->setMethods(['getEscaper']) + ->disableOriginalConstructor() + ->getMock(); + $this->escaper = $this->getMock('Magento\Framework\Escaper', ['escapeHtml'], [], '', false); + $this->helper = $this->getMock('Magento\Framework\DB\Helper', [], [], '', false); + + $this->context->expects($this->once())->method('getEscaper')->willReturn($this->escaper); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->block = $this->objectManagerHelper->getObject( + 'Magento\Backend\Block\Widget\Grid\Column\Filter\Text', + [ + 'context' => $this->context, + 'resourceHelper' => $this->helper + ] + ); + } + + public function testGetHtml() + { + $resultHtml = '<input type="text" name="escapedHtml" ' . + 'id="escapedHtml" value="escapedHtml" ' . + 'class="input-text admin__control-text no-changes" data-ui-id="filter-escapedhtml" />'; + + $column = $this->getMockBuilder('Magento\Backend\Block\Widget\Grid\Column') + ->setMethods(['getId', 'getHtmlId']) + ->disableOriginalConstructor() + ->getMock(); + + $this->block->setColumn($column); + + $this->escaper->expects($this->any())->method('escapeHtml')->willReturn('escapedHtml'); + $column->expects($this->any())->method('getId')->willReturn('id'); + $column->expects($this->once())->method('getHtmlId')->willReturn('htmlId'); + + $this->assertEquals($resultHtml, $this->block->getHtml()); + } +} diff --git a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml index 12dcacd1a035648d05e278c7da386e971d7686a6..6e32f5eed660512ef634b71aceb5443e08ee48a1 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml @@ -24,7 +24,7 @@ $numColumns = sizeof($block->getColumns()); <?php if ($block->getCollection()): ?> <?php if ($block->canDisplayContainer()): ?> -<div id="<?php /* @escapeNotVerified */ echo $block->getId() ?>" data-grid-id="<?php /* @escapeNotVerified */ echo $block->getId() ?>"> +<div id="<?php echo $block->escapeHtml($block->getId()) ?>" data-grid-id="<?php echo $block->escapeHtml($block->getId()) ?>"> <?php else: ?> <?php echo $block->getLayout()->getMessagesBlock()->getGroupedHtml() ?> <?php endif; ?> @@ -50,17 +50,17 @@ $numColumns = sizeof($block->getColumns()); <?php endif; ?> <?php $countRecords = $block->getCollection()->getSize(); ?> <div class="admin__control-support-text"> - <span id="<?php echo $block->getHtmlId() ?>-total-count" <?php /* @escapeNotVerified */ echo $block->getUiId('total-count') ?>> + <span id="<?php echo $block->escapeHtml($block->getHtmlId()) ?>-total-count" <?php /* @escapeNotVerified */ echo $block->getUiId('total-count') ?>> <?php /* @escapeNotVerified */ echo $countRecords ?> </span> <?php /* @escapeNotVerified */ echo __('records found') ?> - <span id="<?php echo $block->getHtmlId() ?>_massaction-count" + <span id="<?php echo $block->escapeHtml($block->getHtmlId()) ?>_massaction-count" class="mass-select-info _empty"><strong data-role="counter">0</strong> <span><?php /* @escapeNotVerified */ echo __('selected') ?></span></span> </div> <?php if ($block->getPagerVisibility()): ?> <div class="admin__data-grid-pager-wrap"> <select name="<?php /* @escapeNotVerified */ echo $block->getVarNameLimit() ?>" - id="<?php echo $block->getHtmlId()?>_page-limit" + id="<?php echo $block->escapeHtml($block->getHtmlId())?>_page-limit" onchange="<?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.loadByElement(this)" <?php /* @escapeNotVerified */ echo $block->getUiId('per-page') ?> class="admin__control-select"> <option value="20"<?php if ($block->getCollection()->getPageSize() == 20): ?> @@ -79,7 +79,7 @@ $numColumns = sizeof($block->getColumns()); selected="selected"<?php endif; ?>>200 </option> </select> - <label for="<?php echo $block->getHtmlId()?>_page-limit" + <label for="<?php echo $block->escapeHtml($block->getHtmlId())?>_page-limit" class="admin__control-support-text"><?php /* @escapeNotVerified */ echo __('per page') ?></label> <div class="admin__data-grid-pager"> <?php $_curPage = $block->getCollection()->getCurPage() ?> @@ -96,13 +96,13 @@ $numColumns = sizeof($block->getColumns()); <?php endif; ?> <input type="text" - id="<?php echo $block->getHtmlId()?>_page-current" + id="<?php echo $block->escapeHtml($block->getHtmlId())?>_page-current" name="<?php /* @escapeNotVerified */ echo $block->getVarNamePage() ?>" value="<?php /* @escapeNotVerified */ echo $_curPage ?>" class="admin__control-text" onkeypress="<?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.inputPage(event, '<?php /* @escapeNotVerified */ echo $_lastPage ?>')" <?php /* @escapeNotVerified */ echo $block->getUiId('current-page') ?> /> - <label class="admin__control-support-text" for="<?php echo $block->getHtmlId() + <label class="admin__control-support-text" for="<?php echo $block->escapeHtml($block->getHtmlId()) ?>_page-current"> <?php /* @escapeNotVerified */ echo __('of %1', '<span>' . $block->getCollection()->getLastPageNumber() . '</span>') ?> </label> @@ -122,13 +122,13 @@ $numColumns = sizeof($block->getColumns()); </div> <div class="admin__data-grid-wrap admin__data-grid-wrap-static"> <?php if ($block->getGridCssClass()): ?> - <table class="<?php /* @escapeNotVerified */ echo $block->getGridCssClass() ?> data-grid" id="<?php /* @escapeNotVerified */ echo $block->getId() ?>_table"> + <table class="<?php /* @escapeNotVerified */ echo $block->getGridCssClass() ?> data-grid" id="<?php echo $block->escapeHtml($block->getId()) ?>_table"> <!-- Rendering column set --> <?php echo $block->getChildHtml('grid.columnSet'); ?> </table> <?php else: ?> - <table class="data-grid" id="<?php /* @escapeNotVerified */ echo $block->getId() ?>_table"> + <table class="data-grid" id="<?php echo $block->escapeHtml($block->getId()) ?>_table"> <!-- Rendering column set --> <?php echo $block->getChildHtml('grid.columnSet'); ?> </table> @@ -161,7 +161,7 @@ $numColumns = sizeof($block->getColumns()); registry.get('<?php /* @escapeNotVerified */ echo $block->getDependencyJsObject() ?>', function (<?php /* @escapeNotVerified */ echo $block->getDependencyJsObject() ?>) { <?php endif; ?> - <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?> = new varienGrid('<?php /* @escapeNotVerified */ echo $block->getId() ?>', '<?php /* @escapeNotVerified */ echo $block->getGridUrl() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNamePage() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameSort() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameDir() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameFilter() ?>'); + <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?> = new varienGrid('<?php echo $block->escapeHtml($block->getId()) ?>', '<?php /* @escapeNotVerified */ echo $block->getGridUrl() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNamePage() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameSort() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameDir() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameFilter() ?>'); <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.useAjax = <?php /* @escapeNotVerified */ echo $block->getUseAjax() ? 'true' : 'false' ?>; <?php if ($block->getRowClickCallback()): ?> <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.rowClickCallback = <?php /* @escapeNotVerified */ echo $block->getRowClickCallback() ?>; diff --git a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml index 385a5a1393c16698ed543ce292d3e18c398ca8ec..ddd9fa5f2f18ae565d365c090d2ad2c8dd35f55a 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml @@ -26,7 +26,7 @@ $numColumns = sizeof($block->getColumns()); <?php if ($block->getCollection()): ?> <?php if ($block->canDisplayContainer()): ?> - <div id="<?php /* @escapeNotVerified */ echo $block->getId() ?>" data-grid-id="<?php /* @escapeNotVerified */ echo $block->getId() ?>"> + <div id="<?php echo $block->escapeHtml($block->getId()) ?>" data-grid-id="<?php echo $block->escapeHtml($block->getId()) ?>"> <?php else: ?> <?php echo $block->getLayout()->getMessagesBlock()->getGroupedHtml() ?> <?php endif; ?> @@ -41,8 +41,8 @@ $numColumns = sizeof($block->getColumns()); <div class="admin__data-grid-export"> <label class="admin__control-support-text" - for="<?php /* @escapeNotVerified */ echo $block->getId() ?>_export"><?php /* @escapeNotVerified */ echo __('Export to:') ?></label> - <select name="<?php /* @escapeNotVerified */ echo $block->getId() ?>_export" id="<?php /* @escapeNotVerified */ echo $block->getId() ?>_export" + for="<?php echo $block->escapeHtml($block->getId()) ?>_export"><?php /* @escapeNotVerified */ echo __('Export to:') ?></label> + <select name="<?php echo $block->escapeHtml($block->getId()) ?>_export" id="<?php echo $block->escapeHtml($block->getId()) ?>_export" class="admin__control-select"> <?php foreach ($block->getExportTypes() as $_type): ?> <option value="<?php /* @escapeNotVerified */ echo $_type->getUrl() ?>"><?php /* @escapeNotVerified */ echo $_type->getLabel() ?></option> @@ -61,18 +61,18 @@ $numColumns = sizeof($block->getColumns()); <?php endif; ?> <?php $countRecords = $block->getCollection()->getSize(); ?> <div class="admin__control-support-text"> - <span id="<?php echo $block->getHtmlId() ?>-total-count" <?php /* @escapeNotVerified */ echo $block->getUiId('total-count') ?>> + <span id="<?php echo $block->escapeHtml($block->getHtmlId()) ?>-total-count" <?php /* @escapeNotVerified */ echo $block->getUiId('total-count') ?>> <?php /* @escapeNotVerified */ echo $countRecords ?> </span> <?php /* @escapeNotVerified */ echo __('records found') ?> - <span id="<?php echo $block->getHtmlId() ?>_massaction-count" + <span id="<?php echo $block->escapeHtml($block->getHtmlId()) ?>_massaction-count" class="mass-select-info _empty"><strong data-role="counter">0</strong> <span><?php /* @escapeNotVerified */ echo __('selected') ?></span></span> </div> <?php if ($block->getPagerVisibility()): ?> <div class="admin__data-grid-pager-wrap"> <select name="<?php /* @escapeNotVerified */ echo $block->getVarNameLimit() ?>" - id="<?php echo $block->getHtmlId()?>_page-limit" + id="<?php echo $block->escapeHTML($block->getHtmlId())?>_page-limit" onchange="<?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.loadByElement(this)" class="admin__control-select"> <option value="20"<?php if ($block->getCollection()->getPageSize() == 20): ?> @@ -91,7 +91,7 @@ $numColumns = sizeof($block->getColumns()); selected="selected"<?php endif; ?>>200 </option> </select> - <label for="<?php echo $block->getHtmlId()?><?php echo $block->getHtmlId()?>_page-limit" + <label for="<?php echo $block->escapeHTML($block->getHtmlId())?><?php echo $block->escapeHTML($block->getHtmlId())?>_page-limit" class="admin__control-support-text"><?php /* @escapeNotVerified */ echo __('per page') ?></label> <div class="admin__data-grid-pager"> @@ -107,12 +107,12 @@ $numColumns = sizeof($block->getColumns()); <button type="button" class="action-previous disabled"><span><?php /* @escapeNotVerified */ echo __('Previous page') ?></span></button> <?php endif; ?> <input type="text" - id="<?php echo $block->getHtmlId()?>_page-current" + id="<?php echo $block->escapeHTML($block->getHtmlId())?>_page-current" name="<?php /* @escapeNotVerified */ echo $block->getVarNamePage() ?>" value="<?php /* @escapeNotVerified */ echo $_curPage ?>" class="admin__control-text" onkeypress="<?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.inputPage(event, '<?php /* @escapeNotVerified */ echo $_lastPage ?>')" <?php /* @escapeNotVerified */ echo $block->getUiId('current-page') ?> /> - <label class="admin__control-support-text" for="<?php echo $block->getHtmlId()?>_page-current"> + <label class="admin__control-support-text" for="<?php echo $block->escapeHTML($block->getHtmlId())?>_page-current"> <?php /* @escapeNotVerified */ echo __('of %1', '<span>' . $block->getCollection()->getLastPageNumber() . '</span>') ?> </label> <?php if ($_curPage < $_lastPage): ?> @@ -133,7 +133,7 @@ $numColumns = sizeof($block->getColumns()); <?php endif; ?> <div class="admin__data-grid-wrap admin__data-grid-wrap-static"> - <table class="data-grid" id="<?php /* @escapeNotVerified */ echo $block->getId() ?>_table"> + <table class="data-grid" id="<?php echo $block->escapeHtml($block->getId()) ?>_table"> <?php /* This part is commented to remove all <col> tags from the code. */ /* foreach ($block->getColumns() as $_column): ?> @@ -263,7 +263,7 @@ $numColumns = sizeof($block->getColumns()); registry.get('<?php /* @escapeNotVerified */ echo $block->getDependencyJsObject() ?>', function (<?php /* @escapeNotVerified */ echo $block->getDependencyJsObject() ?>) { <?php endif; ?> - <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?> = new varienGrid('<?php /* @escapeNotVerified */ echo $block->getId() ?>', '<?php /* @escapeNotVerified */ echo $block->getGridUrl() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNamePage() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameSort() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameDir() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameFilter() ?>'); + <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?> = new varienGrid(<?php /* @noEscape */ echo $this->helper('Magento\Framework\Json\Helper\Data')->jsonEncode($block->getId()) ?>, '<?php /* @escapeNotVerified */ echo $block->getGridUrl() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNamePage() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameSort() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameDir() ?>', '<?php /* @escapeNotVerified */ echo $block->getVarNameFilter() ?>'); <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.useAjax = '<?php /* @escapeNotVerified */ echo $block->getUseAjax() ?>'; <?php if ($block->getRowClickCallback()): ?> <?php /* @escapeNotVerified */ echo $block->getJsObjectName() ?>.rowClickCallback = <?php /* @escapeNotVerified */ echo $block->getRowClickCallback() ?>; diff --git a/app/code/Magento/Bundle/Controller/Adminhtml/Bundle/Selection/Grid.php b/app/code/Magento/Bundle/Controller/Adminhtml/Bundle/Selection/Grid.php index 85ce181f5eb1957de3c5c205593d496931caf82e..684eb43e4ad6019b28243f9ef932f74d4e7f16e9 100644 --- a/app/code/Magento/Bundle/Controller/Adminhtml/Bundle/Selection/Grid.php +++ b/app/code/Magento/Bundle/Controller/Adminhtml/Bundle/Selection/Grid.php @@ -13,13 +13,16 @@ class Grid extends \Magento\Backend\App\Action */ public function execute() { + $index = $this->getRequest()->getParam('index'); + if (!preg_match('/^[a-z0-9_.]*$/i', $index)) { + throw new \InvalidArgumentException('Invalid parameter "index"'); + } + return $this->getResponse()->setBody( $this->_view->getLayout()->createBlock( 'Magento\Bundle\Block\Adminhtml\Catalog\Product\Edit\Tab\Bundle\Option\Search\Grid', 'adminhtml.catalog.product.edit.tab.bundle.option.search.grid' - )->setIndex( - $this->getRequest()->getParam('index') - )->toHtml() + )->setIndex($index)->toHtml() ); } } diff --git a/app/code/Magento/Bundle/Test/Unit/Controller/Adminhtml/Bundle/Selection/GridTest.php b/app/code/Magento/Bundle/Test/Unit/Controller/Adminhtml/Bundle/Selection/GridTest.php index 267dade65be131b972fdaa5e9254603cc8ef9bc6..c0a7342f8249fe51452f5b762116455f814a9581 100644 --- a/app/code/Magento/Bundle/Test/Unit/Controller/Adminhtml/Bundle/Selection/GridTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Controller/Adminhtml/Bundle/Selection/GridTest.php @@ -90,4 +90,15 @@ class GridTest extends \PHPUnit_Framework_TestCase $this->assertEquals($this->response, $this->controller->execute()); } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Invalid parameter "index" + */ + public function testExecuteWithException() + { + $this->request->expects($this->once())->method('getParam')->with('index')->willReturn('<index"'); + + $this->controller->execute(); + } } diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Inventory.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Inventory.php index 72ad16576f1ca238d01a068f5cf53be714755b30..5cf7b922ac980d1a20c5be02b284b946dc109d22 100644 --- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Inventory.php +++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Inventory.php @@ -134,13 +134,14 @@ class Inventory extends \Magento\Backend\Block\Widget public function getFieldValue($field) { $stockItem = $this->getStockItem(); + $value = null; if ($stockItem->getItemId()) { $method = 'get' . SimpleDataObjectConverter::snakeCaseToUpperCamelCase($field); - if (method_exists($stockItem, $method)) { - return $stockItem->{$method}(); + if (is_callable([$stockItem, $method])) { + $value = $stockItem->{$method}(); } } - return $this->stockConfiguration->getDefaultConfigValue($field); + return $value === null ? $this->stockConfiguration->getDefaultConfigValue($field) : $value; } /** diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tabs.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tabs.php index 2f99d45e092e8458fd1c6d6c38eb9cd26becd14c..4276ab20af7d39f4abd3fc5da3d2728de6683045 100644 --- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tabs.php +++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tabs.php @@ -189,15 +189,15 @@ class Tabs extends \Magento\Backend\Block\Widget\Tabs unset($advancedGroups['advanced-pricing']); } - if ($this->_moduleManager->isEnabled('Magento_CatalogInventory')) { + if ($this->_moduleManager->isEnabled('Magento_CatalogInventory') + && $this->getChildBlock('advanced-inventory') + ) { $this->addTab( 'advanced-inventory', [ 'label' => __('Advanced Inventory'), 'content' => $this->_translateHtml( - $this->getLayout()->createBlock( - 'Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Inventory' - )->toHtml() + $this->getChildHtml('advanced-inventory') ), 'group_code' => self::ADVANCED_TAB_GROUP_CODE ] diff --git a/app/code/Magento/Catalog/Model/Product.php b/app/code/Magento/Catalog/Model/Product.php index dd0f5ec4ead4f93ae5a12313ada595359471ef03..2453c4395345b2b20bbfc1ee09ab3a7e29c5171d 100644 --- a/app/code/Magento/Catalog/Model/Product.php +++ b/app/code/Magento/Catalog/Model/Product.php @@ -2504,6 +2504,9 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements */ public function setTypeId($typeId) { + if ($typeId !== $this->_getData('type_id')) { + $this->_typeInstance = null; + } return $this->setData(self::TYPE_ID, $typeId); } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php index 97f42ea1d09ab40dba23ae24684f516fb520b74d..9cbc587f0cb84a8f347e3feb9c35553969bb5272 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php @@ -1407,4 +1407,19 @@ class ProductTest extends \PHPUnit_Framework_TestCase $this->productTypeInstanceMock->expects($this->never())->method('priceFactory'); $this->assertEquals($finalPrice, $this->model->getFinalPrice($qty)); } + + public function testGetTypeId() + { + $productType = $this->getMockBuilder('Magento\Catalog\Model\Product\Type\Virtual') + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->productTypeInstanceMock->expects($this->exactly(2))->method('factory')->will( + $this->returnValue($productType) + ); + + $this->model->getTypeInstance(); + $this->model->setTypeId('typeId'); + $this->model->getTypeInstance(); + } } diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_new.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_new.xml index 55e9ebee91f5bcbbcc6b77c4d81fd3638dec7592..4377b74674bd39520293cbab250d994fe33be3e6 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_new.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_new.xml @@ -37,6 +37,12 @@ <argument name="class" xsi:type="string">ajax</argument> </arguments> </block> + <block class="Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Inventory" name="product_tabs.advanced-inventory" as="advanced-inventory"> + <arguments> + <argument name="label" xsi:type="string" translate="true">Advanced Inventory</argument> + <argument name="group_code" xsi:type="string">advanced</argument> + </arguments> + </block> <block class="Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Alerts" name="product_tabs.product-alerts" as="product-alerts"> <arguments> <argument name="label" xsi:type="string" translate="true">Product Alerts</argument> diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/product/edit/attribute/search.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/product/edit/attribute/search.phtml index 3f6215626ad827c7a2791828b4886b958ce4bfc4..d3c382f9276b8a2d9df9ec1473fbe1707779fc42 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/product/edit/attribute/search.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/product/edit/attribute/search.phtml @@ -63,7 +63,7 @@ data: {attribute_id: ui.item.id, template_id: templateId, group: $(this).data('group')}, showLoader: true }).done(function() { - setTimeout(function() { //do defered + setTimeout(function() { //do deferred $('[data-form=edit-product]').trigger('changeAttributeSet', {id: templateId}); }, 10); }); diff --git a/app/code/Magento/CatalogInventory/Model/Resource/QtyCounterInterface.php b/app/code/Magento/CatalogInventory/Model/Resource/QtyCounterInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..e36a04a2b3d40630ee819410f7f86aa4c283f6dd --- /dev/null +++ b/app/code/Magento/CatalogInventory/Model/Resource/QtyCounterInterface.php @@ -0,0 +1,22 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\CatalogInventory\Model\Resource; + +/** + * Correct particular stock products qty + */ +interface QtyCounterInterface +{ + /** + * Correct particular stock products qty based on operator + * + * @param int[] $items + * @param int $websiteId + * @param string $operator +/- + * @return void + */ + public function correctItemsQty(array $items, $websiteId, $operator); +} diff --git a/app/code/Magento/CatalogInventory/Model/Resource/Stock.php b/app/code/Magento/CatalogInventory/Model/Resource/Stock.php index e5c9c696404fb1dcd6b1a096be6190f09b16822f..6948b642136d19844f92273987dcf9c8ee3b299d 100644 --- a/app/code/Magento/CatalogInventory/Model/Resource/Stock.php +++ b/app/code/Magento/CatalogInventory/Model/Resource/Stock.php @@ -12,7 +12,7 @@ use Magento\Store\Model\StoreManagerInterface; /** * Stock resource model */ -class Stock extends \Magento\Framework\Model\Resource\Db\AbstractDb +class Stock extends \Magento\Framework\Model\Resource\Db\AbstractDb implements QtyCounterInterface { /** * @var StockConfigurationInterface @@ -134,14 +134,9 @@ class Stock extends \Magento\Framework\Model\Resource\Db\AbstractDb } /** - * Correct particular stock products qty based on operator - * - * @param array $items - * @param int $websiteId - * @param string $operator +/- - * @return $this + * {@inheritdoc} */ - public function correctItemsQty(array $items, $websiteId, $operator = '-') + public function correctItemsQty(array $items, $websiteId, $operator) { if (empty($items)) { return $this; @@ -161,8 +156,6 @@ class Stock extends \Magento\Framework\Model\Resource\Db\AbstractDb $connection->beginTransaction(); $connection->update($this->getTable('cataloginventory_stock_item'), ['qty' => $value], $where); $connection->commit(); - - return $this; } /** diff --git a/app/code/Magento/CatalogInventory/Model/StockManagement.php b/app/code/Magento/CatalogInventory/Model/StockManagement.php index 3d5fee6d9cef90eb8bfcf98d78b6c45e68c0bca2..c487ab15394e79dce91848c9fa45dafddef19161 100644 --- a/app/code/Magento/CatalogInventory/Model/StockManagement.php +++ b/app/code/Magento/CatalogInventory/Model/StockManagement.php @@ -9,6 +9,7 @@ use Magento\Catalog\Model\ProductFactory; use Magento\CatalogInventory\Api\Data\StockItemInterface; use Magento\CatalogInventory\Api\StockConfigurationInterface; use Magento\CatalogInventory\Api\StockManagementInterface; +use Magento\CatalogInventory\Model\Resource\QtyCounterInterface; use Magento\CatalogInventory\Model\Spi\StockRegistryProviderInterface; use Magento\Catalog\Api\ProductRepositoryInterface; @@ -38,26 +39,37 @@ class StockManagement implements StockManagementInterface protected $productRepository; /** - * @var \Magento\CatalogInventory\Model\Resource\Stock + * @var Resource\Stock */ protected $resource; /** + * @var QtyCounterInterface + */ + private $qtyCounter; + + /** + * @param Resource\Stock $stockResource * @param StockRegistryProviderInterface $stockRegistryProvider * @param StockState $stockState * @param StockConfigurationInterface $stockConfiguration * @param ProductRepositoryInterface $productRepository + * @param Resource\QtyCounterInterface $qtyCounter */ public function __construct( + Resource\Stock $stockResource, StockRegistryProviderInterface $stockRegistryProvider, StockState $stockState, StockConfigurationInterface $stockConfiguration, - ProductRepositoryInterface $productRepository + ProductRepositoryInterface $productRepository, + QtyCounterInterface $qtyCounter ) { $this->stockRegistryProvider = $stockRegistryProvider; $this->stockState = $stockState; $this->stockConfiguration = $stockConfiguration; $this->productRepository = $productRepository; + $this->qtyCounter = $qtyCounter; + $this->resource = $stockResource; } /** @@ -108,7 +120,7 @@ class StockManagement implements StockManagementInterface $fullSaveItems[] = $stockItem; } } - $this->getResource()->correctItemsQty($registeredItems, $websiteId, '-'); + $this->qtyCounter->correctItemsQty($registeredItems, $websiteId, '-'); $this->getResource()->commit(); return $fullSaveItems; } @@ -123,7 +135,7 @@ class StockManagement implements StockManagementInterface //if (!$websiteId) { $websiteId = $this->stockConfiguration->getDefaultWebsiteId(); //} - $this->getResource()->correctItemsQty($items, $websiteId, '+'); + $this->qtyCounter->correctItemsQty($items, $websiteId, '+'); return true; } @@ -168,15 +180,10 @@ class StockManagement implements StockManagementInterface } /** - * @return \Magento\CatalogInventory\Model\Resource\Stock + * @return Stock */ protected function getResource() { - if (empty($this->resource)) { - $this->resource = \Magento\Framework\App\ObjectManager::getInstance()->get( - 'Magento\CatalogInventory\Model\Resource\Stock' - ); - } return $this->resource; } diff --git a/app/code/Magento/CatalogInventory/Observer/SaveInventoryDataObserver.php b/app/code/Magento/CatalogInventory/Observer/SaveInventoryDataObserver.php index 789fc3748dcd9a32b78b5cd3333020992c4d0e71..653f77000c8c45be8f4333f02d42b0501b5f9f3d 100644 --- a/app/code/Magento/CatalogInventory/Observer/SaveInventoryDataObserver.php +++ b/app/code/Magento/CatalogInventory/Observer/SaveInventoryDataObserver.php @@ -8,6 +8,7 @@ namespace Magento\CatalogInventory\Observer; use Magento\CatalogInventory\Api\StockConfigurationInterface; use Magento\CatalogInventory\Api\StockIndexInterface; +use Magento\CatalogInventory\Api\StockItemRepositoryInterface; use Magento\CatalogInventory\Api\StockRegistryInterface; use Magento\Framework\Event\Observer as EventObserver; @@ -32,7 +33,7 @@ class SaveInventoryDataObserver protected $stockRegistry; /** - * @var \Magento\CatalogInventory\Api\StockItemRepositoryInterface + * @var StockItemRepositoryInterface */ protected $stockItemRepository; @@ -74,13 +75,13 @@ class SaveInventoryDataObserver * @param StockIndexInterface $stockIndex * @param StockConfigurationInterface $stockConfiguration * @param StockRegistryInterface $stockRegistry - * @param \Magento\CatalogInventory\Api\StockItemRepositoryInterface $stockItemRepository + * @param StockItemRepositoryInterface $stockItemRepository */ public function __construct( StockIndexInterface $stockIndex, StockConfigurationInterface $stockConfiguration, StockRegistryInterface $stockRegistry, - \Magento\CatalogInventory\Api\StockItemRepositoryInterface $stockItemRepository + StockItemRepositoryInterface $stockItemRepository ) { $this->stockIndex = $stockIndex; $this->stockConfiguration = $stockConfiguration; diff --git a/app/code/Magento/CatalogInventory/etc/di.xml b/app/code/Magento/CatalogInventory/etc/di.xml index a57b542a0b12cf390a47524aaedd62f1100041bb..4332e525c3260619830f2e5f2102759edf2e346e 100644 --- a/app/code/Magento/CatalogInventory/etc/di.xml +++ b/app/code/Magento/CatalogInventory/etc/di.xml @@ -30,6 +30,8 @@ <preference for="Magento\CatalogInventory\Model\Spi\StockRegistryProviderInterface" type="Magento\CatalogInventory\Model\StockRegistryProvider" /> <preference for="Magento\CatalogInventory\Model\Spi\StockStateProviderInterface" type="Magento\CatalogInventory\Model\StockStateProvider" /> + + <preference for="Magento\CatalogInventory\Model\Resource\QtyCounterInterface" type="\Magento\CatalogInventory\Model\Resource\Stock" /> <type name="Magento\CatalogInventory\Observer\UpdateItemsStockUponConfigChangeObserver"> <arguments> diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/Preprocessor.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/Preprocessor.php index 037e4c3629e034b6ef57564abbcf8daa025f8644..8f8fb11c19d8513f40427af224ee2fe6921cb783 100644 --- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/Preprocessor.php +++ b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/Preprocessor.php @@ -97,29 +97,26 @@ class Preprocessor implements PreprocessorInterface */ private function processQueryWithField(FilterInterface $filter, $isNegation, $query) { - $currentStoreId = $this->scopeResolver->getScope()->getId(); - $select = null; /** @var \Magento\Catalog\Model\Resource\Eav\Attribute $attribute */ $attribute = $this->config->getAttribute(Product::ENTITY, $filter->getField()); - $table = $attribute->getBackendTable(); if ($filter->getField() === 'price') { - $filterQuery = str_replace( + $resultQuery = str_replace( $this->connection->quoteIdentifier('price'), $this->connection->quoteIdentifier('price_index.min_price'), $query ); - return $filterQuery; } elseif ($filter->getField() === 'category_ids') { return 'category_ids_index.category_id = ' . $filter->getValue(); } elseif ($attribute->isStatic()) { $alias = $this->tableMapper->getMappingAlias($filter); - $filterQuery = str_replace( + $resultQuery = str_replace( $this->connection->quoteIdentifier($attribute->getAttributeCode()), $this->connection->quoteIdentifier($alias . '.' . $attribute->getAttributeCode()), $query ); - return $filterQuery; - } elseif ($filter->getType() === FilterInterface::TYPE_TERM) { + } elseif ($filter->getType() === FilterInterface::TYPE_TERM + && in_array($attribute->getFrontendInput(), ['select', 'multiselect'], true) + ) { $alias = $this->tableMapper->getMappingAlias($filter); if (is_array($filter->getValue())) { $value = sprintf( @@ -130,16 +127,18 @@ class Preprocessor implements PreprocessorInterface } else { $value = ($isNegation ? '!' : '') . '= ' . $filter->getValue(); } - $filterQuery = sprintf( + $resultQuery = sprintf( '%1$s.value %2$s', $alias, $value ); - return $filterQuery; } else { + $table = $attribute->getBackendTable(); $select = $this->connection->select(); $ifNullCondition = $this->connection->getIfNullSql('current_store.value', 'main_table.value'); + $currentStoreId = $this->scopeResolver->getScope()->getId(); + $select->from(['main_table' => $table], 'entity_id') ->joinLeft( ['current_store' => $table], @@ -154,10 +153,12 @@ class Preprocessor implements PreprocessorInterface ) ->where('main_table.store_id = ?', Store::DEFAULT_STORE_ID) ->having($query); - } - return 'search_index.entity_id IN ( - select entity_id from ' . $this->conditionManager->wrapBrackets($select) . ' as filter + $resultQuery = 'search_index.entity_id IN ( + select entity_id from ' . $this->conditionManager->wrapBrackets($select) . ' as filter )'; + } + + return $resultQuery; } } diff --git a/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php b/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php index c951e9b538f12e22367e682ce335742c3c2cccdf..5dd7633026068b4dea7253e9d5d36e1611a265c0 100644 --- a/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php +++ b/app/code/Magento/CatalogSearch/Model/Search/TableMapper.php @@ -103,9 +103,10 @@ class TableMapper if ($fieldToTableMap) { list($alias, $table, $mapOn, $mappedFields) = $fieldToTableMap; $table = $this->resource->getTableName($table); - } elseif ($filter->getType() === FilterInterface::TYPE_TERM) { - $attribute = $this->getAttributeByCode($field); - if ($attribute) { + } elseif ($attribute = $this->getAttributeByCode($field)) { + if ($filter->getType() === FilterInterface::TYPE_TERM + && in_array($attribute->getFrontendInput(), ['select', 'multiselect'], true) + ) { $table = $this->resource->getTableName('catalog_product_index_eav'); $alias = $field . '_filter'; $mapOn = sprintf( @@ -115,21 +116,14 @@ class TableMapper $this->getStoreId() ); $mappedFields = []; - } - } else { - $attribute = $this->getAttributeByCode($field); - if ($attribute && $attribute->getBackendType() === AbstractAttribute::TYPE_STATIC) { + } elseif ($attribute->getBackendType() === AbstractAttribute::TYPE_STATIC) { $table = $attribute->getBackendTable(); - $alias = $this->getTableAlias($table); + $alias = $field . '_filter'; $mapOn = 'search_index.entity_id = ' . $alias . '.entity_id'; $mappedFields = null; } } - if (!$alias && $table) { - $alias = $this->getTableAlias($table); - } - return [$alias, $table, $mapOn, $mappedFields]; } @@ -242,15 +236,6 @@ class TableMapper return array_key_exists($field, $fieldToTableMap) ? $fieldToTableMap[$field] : null; } - /** - * @param string $table - * @return string - */ - private function getTableAlias($table) - { - return md5($table); - } - /** * @param string $field * @return \Magento\Catalog\Model\Resource\Eav\Attribute diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Filter/PreprocessorTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Filter/PreprocessorTest.php index 2e5241e8e91f028334a05d333f623bc7981b473f..1208bf32c77a01fe1c692b7142660570be305b38 100644 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Filter/PreprocessorTest.php +++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Filter/PreprocessorTest.php @@ -7,6 +7,7 @@ namespace Magento\CatalogSearch\Test\Unit\Model\Adapter\Mysql\Filter; use Magento\Framework\DB\Select; +use Magento\Framework\Search\Request\FilterInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; use PHPUnit_Framework_MockObject_MockObject as MockObject; @@ -46,7 +47,7 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase private $select; /** - * @var \Magento\Framework\Search\Request\FilterInterface|MockObject + * @var FilterInterface|MockObject */ private $filter; @@ -86,7 +87,7 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase ->disableOriginalConstructor() ->setMethods(['getId']) ->getMockForAbstractClass(); - $this->scopeResolver->expects($this->once()) + $this->scopeResolver->expects($this->any()) ->method('getScope') ->will($this->returnValue($this->scope)); $this->config = $this->getMockBuilder('\Magento\Eav\Model\Config') @@ -95,7 +96,7 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase ->getMock(); $this->attribute = $this->getMockBuilder('\Magento\Eav\Model\Entity\Attribute\AbstractAttribute') ->disableOriginalConstructor() - ->setMethods(['getBackendTable', 'isStatic', 'getAttributeId', 'getAttributeCode']) + ->setMethods(['getBackendTable', 'isStatic', 'getAttributeId', 'getAttributeCode', 'getFrontendInput']) ->getMockForAbstractClass(); $this->resource = $resource = $this->getMockBuilder('\Magento\Framework\App\Resource') ->disableOriginalConstructor() @@ -120,7 +121,7 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase ->will($this->returnValue($this->connection)); $this->filter = $this->getMockBuilder('\Magento\Framework\Search\Request\FilterInterface') ->disableOriginalConstructor() - ->setMethods(['getField', 'getValue']) + ->setMethods(['getField', 'getValue', 'getType']) ->getMockForAbstractClass(); $this->conditionManager->expects($this->any()) @@ -154,11 +155,9 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase public function testProcessPrice() { $expectedResult = 'price_index.min_price = 23'; - $scopeId = 0; $isNegation = false; $query = 'price = 23'; - $this->scope->expects($this->once())->method('getId')->will($this->returnValue($scopeId)); $this->filter->expects($this->exactly(2)) ->method('getField') ->will($this->returnValue('price')); @@ -174,11 +173,9 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase public function testProcessCategoryIds() { $expectedResult = 'category_ids_index.category_id = FilterValue'; - $scopeId = 0; $isNegation = false; $query = 'SELECT category_ids FROM catalog_product_entity'; - $this->scope->expects($this->once())->method('getId')->will($this->returnValue($scopeId)); $this->filter->expects($this->exactly(3)) ->method('getField') ->will($this->returnValue('category_ids')); @@ -199,7 +196,6 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase public function testProcessStaticAttribute() { $expectedResult = 'attr_table_alias.static_attribute LIKE %name%'; - $scopeId = 0; $isNegation = false; $query = 'static_attribute LIKE %name%'; @@ -207,7 +203,6 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase ->willReturn('static_attribute'); $this->tableMapper->expects($this->once())->method('getMappingAlias') ->willReturn('attr_table_alias'); - $this->scope->expects($this->once())->method('getId')->will($this->returnValue($scopeId)); $this->filter->expects($this->exactly(3)) ->method('getField') ->will($this->returnValue('static_attribute')); @@ -218,14 +213,100 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase $this->attribute->expects($this->once()) ->method('isStatic') ->will($this->returnValue(true)); - $this->attribute->expects($this->once()) - ->method('getBackendTable') - ->will($this->returnValue('backend_table')); $actualResult = $this->target->process($this->filter, $isNegation, $query); $this->assertSame($expectedResult, $this->removeWhitespaces($actualResult)); } + /** + * @dataProvider testTermFilterDataProvider + */ + public function testProcessTermFilter($frontendInput, $fieldValue, $isNegation, $expected) + { + $this->config->expects($this->exactly(1)) + ->method('getAttribute') + ->with(\Magento\Catalog\Model\Product::ENTITY, 'termField') + ->will($this->returnValue($this->attribute)); + + $this->attribute->expects($this->once()) + ->method('isStatic') + ->will($this->returnValue(false)); + + $this->filter->expects($this->once()) + ->method('getType') + ->willReturn(FilterInterface::TYPE_TERM); + $this->attribute->expects($this->once()) + ->method('getFrontendInput') + ->willReturn($frontendInput); + + $this->tableMapper->expects($this->once())->method('getMappingAlias') + ->willReturn('termAttrAlias'); + + $this->filter->expects($this->exactly(3)) + ->method('getField') + ->willReturn('termField'); + $this->filter->expects($this->exactly(2)) + ->method('getValue') + ->willReturn($fieldValue); + + $actualResult = $this->target->process($this->filter, $isNegation, 'This filter is not depends on used query'); + $this->assertSame($expected, $this->removeWhitespaces($actualResult)); + } + + public function testTermFilterDataProvider() + { + return [ + 'selectPositiveEqual' => [ + 'frontendInput' => 'select', + 'fieldValue' => 'positiveValue', + 'isNegation' => false, + 'expected' => 'termAttrAlias.value = positiveValue', + ], + 'selectPositiveArray' => [ + 'frontendInput' => 'select', + 'fieldValue' => [2, 3, 15], + 'isNegation' => false, + 'expected' => 'termAttrAlias.value IN (2,3,15)', + ], + 'selectNegativeEqual' => [ + 'frontendInput' => 'select', + 'fieldValue' => 'positiveValue', + 'isNegation' => true, + 'expected' => 'termAttrAlias.value != positiveValue', + ], + 'selectNegativeArray' => [ + 'frontendInput' => 'select', + 'fieldValue' => [4, 3, 42], + 'isNegation' => true, + 'expected' => 'termAttrAlias.value NOT IN (4,3,42)', + ], + 'multiSelectPositiveEqual' => [ + 'frontendInput' => 'multiselect', + 'fieldValue' => 'positiveValue', + 'isNegation' => false, + 'expected' => 'termAttrAlias.value = positiveValue', + ], + 'multiSelectPositiveArray' => [ + 'frontendInput' => 'multiselect', + 'fieldValue' => [2, 3, 15], + 'isNegation' => false, + 'expected' => 'termAttrAlias.value IN (2,3,15)', + ], + 'multiSelectNegativeEqual' => [ + 'frontendInput' => 'multiselect', + 'fieldValue' => 'negativeValue', + 'isNegation' => true, + 'expected' => 'termAttrAlias.value != negativeValue', + ], + 'multiSelectNegativeArray' => [ + 'frontendInput' => 'multiselect', + 'fieldValue' => [4, 3, 42], + 'isNegation' => true, + 'expected' => 'termAttrAlias.value NOT IN (4,3,42)', + ], + ]; + } + public function testProcessNotStaticAttribute() { $expectedResult = 'search_index.entity_id IN (select entity_id from (TEST QUERY PART) as filter)'; diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/TableMapperTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/TableMapperTest.php index 60a8bbbd47b827d32b4dc7c0994cb4422e66742b..f888803a1db621e6c9af3c07da658a9a8d32b5ee 100644 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/TableMapperTest.php +++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/TableMapperTest.php @@ -167,15 +167,15 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase { $priceFilter = $this->createRangeFilter('static'); $query = $this->createFilterQuery($priceFilter); - $this->createAttributeMock('static', 'static', 'backend_table', 0); + $this->createAttributeMock('static', 'static', 'backend_table', 0, 'select'); $this->request->expects($this->once()) ->method('getQuery') ->willReturn($query); $this->select->expects($this->once()) ->method('joinLeft') ->with( - ['4111c4a3daddb5c5dba31cdac705114b' => 'backend_table'], - 'search_index.entity_id = 4111c4a3daddb5c5dba31cdac705114b.entity_id', + ['static_filter' => 'backend_table'], + 'search_index.entity_id = static_filter.entity_id', null ) ->willReturnSelf(); @@ -204,7 +204,7 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase public function testAddTermFilter() { - $this->createAttributeMock('color', null, null, 132, 0); + $this->createAttributeMock('color', null, null, 132, 'select', 0); $categoryIdsFilter = $this->createTermFilter('color'); $query = $this->createFilterQuery($categoryIdsFilter); $this->request->expects($this->once()) @@ -226,9 +226,9 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase public function testAddBoolQueryWithTermFiltersInside() { - $this->createAttributeMock('must1', null, null, 101, 0); - $this->createAttributeMock('should1', null, null, 102, 1); - $this->createAttributeMock('mustNot1', null, null, 103, 2); + $this->createAttributeMock('must1', null, null, 101, 'select', 0); + $this->createAttributeMock('should1', null, null, 102, 'select', 1); + $this->createAttributeMock('mustNot1', null, null, 103, 'select', 2); $query = $this->createBoolQuery( [ @@ -280,9 +280,9 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase public function testAddBoolQueryWithTermAndPriceFiltersInside() { - $this->createAttributeMock('must1', null, null, 101, 0); - $this->createAttributeMock('should1', null, null, 102, 1); - $this->createAttributeMock('mustNot1', null, null, 103, 2); + $this->createAttributeMock('must1', null, null, 101, 'select', 0); + $this->createAttributeMock('should1', null, null, 102, 'select', 1); + $this->createAttributeMock('mustNot1', null, null, 103, 'select', 2); $query = $this->createBoolQuery( [ $this->createFilterQuery($this->createTermFilter('must1')), @@ -342,9 +342,9 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase public function testAddBoolFilterWithTermFiltersInside() { - $this->createAttributeMock('must1', null, null, 101, 0); - $this->createAttributeMock('should1', null, null, 102, 1); - $this->createAttributeMock('mustNot1', null, null, 103, 2); + $this->createAttributeMock('must1', null, null, 101, 'select', 0); + $this->createAttributeMock('should1', null, null, 102, 'select', 1); + $this->createAttributeMock('mustNot1', null, null, 103, 'select', 2); $query = $this->createFilterQuery( $this->createBoolFilter( [ @@ -397,9 +397,9 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase public function testAddBoolFilterWithBoolFiltersInside() { - $this->createAttributeMock('must1', null, null, 101, 0); - $this->createAttributeMock('should1', null, null, 102, 1); - $this->createAttributeMock('mustNot1', null, null, 103, 2); + $this->createAttributeMock('must1', null, null, 101, 'select', 0); + $this->createAttributeMock('should1', null, null, 102, 'select', 1); + $this->createAttributeMock('mustNot1', null, null, 103, 'select', 2); $query = $this->createFilterQuery( $this->createBoolFilter( [ @@ -563,6 +563,7 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase * @param string $backendType * @param string $backendTable * @param int $attributeId + * @param string $frontendInput * @param int $positionInCollection */ private function createAttributeMock( @@ -570,10 +571,11 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase $backendType = null, $backendTable = null, $attributeId = 120, + $frontendInput = 'select', $positionInCollection = 0 ) { $attribute = $this->getMockBuilder('\Magento\Catalog\Model\Resource\Eav\Attribute') - ->setMethods(['getBackendType', 'getBackendTable', 'getId']) + ->setMethods(['getBackendType', 'getBackendTable', 'getId', 'getFrontendInput']) ->disableOriginalConstructor() ->getMock(); $attribute->method('getId') @@ -582,6 +584,8 @@ class TableMapperTest extends \PHPUnit_Framework_TestCase ->willReturn($backendType); $attribute->method('getBackendTable') ->willReturn($backendTable); + $attribute->method('getFrontendInput') + ->willReturn($frontendInput); $this->attributeCollection->expects($this->at($positionInCollection)) ->method('getItemByColumnValue') ->with('attribute_code', $code) diff --git a/app/code/Magento/Config/Model/Config/Structure/Mapper/Sorting.php b/app/code/Magento/Config/Model/Config/Structure/Mapper/Sorting.php index 118108189fd5f6052a607e85b7824f38e72a7a56..a7271b7441e2609acb4c54e5f1a0fe9aa0c989df 100644 --- a/app/code/Magento/Config/Model/Config/Structure/Mapper/Sorting.php +++ b/app/code/Magento/Config/Model/Config/Structure/Mapper/Sorting.php @@ -51,11 +51,11 @@ class Sorting extends \Magento\Config\Model\Config\Structure\AbstractMapper { $sortIndexA = 0; if ($this->_hasValue('sortOrder', $elementA)) { - $sortIndexA = intval($elementA['sortOrder']); + $sortIndexA = floatval($elementA['sortOrder']); } $sortIndexB = 0; if ($this->_hasValue('sortOrder', $elementB)) { - $sortIndexB = intval($elementB['sortOrder']); + $sortIndexB = floatval($elementB['sortOrder']); } if ($sortIndexA == $sortIndexB) { diff --git a/app/code/Magento/Config/etc/system.xsd b/app/code/Magento/Config/etc/system.xsd index 4703d178f1a9e5c0c18df0eb67063d5bc9b310c5..3585f499ddc2429197369c0babbb8de74927ba40 100644 --- a/app/code/Magento/Config/etc/system.xsd +++ b/app/code/Magento/Config/etc/system.xsd @@ -48,7 +48,7 @@ <xs:attributeGroup name="tabAttributeGroup"> <xs:attribute name="id" type="typeId" use="required" /> <xs:attribute name="translate" type="xs:string" use="optional" /> - <xs:attribute name="sortOrder" type="xs:int" use="optional" /> + <xs:attribute name="sortOrder" type="xs:float" use="optional" /> <xs:attribute name="class" type="xs:string" use="optional" /> </xs:attributeGroup> @@ -56,7 +56,7 @@ <xs:attribute name="id" type="typeId" use="required" /> <xs:attribute name="translate" type="xs:string" use="optional" /> <xs:attribute name="type" type="xs:string" use="optional" /> - <xs:attribute name="sortOrder" type="xs:int" use="optional" /> + <xs:attribute name="sortOrder" type="xs:float" use="optional" /> <xs:attribute name="showInDefault" type="xs:int" use="optional" /> <xs:attribute name="showInStore" type="xs:int" use="optional" /> <xs:attribute name="showInWebsite" type="xs:int" use="optional" /> diff --git a/app/code/Magento/Config/etc/system_file.xsd b/app/code/Magento/Config/etc/system_file.xsd index 89c8f2db61d9d649255c44d261a128cb98ee384f..0bbc99c6a07f7da7e44237e4f8bc716bf47bde92 100644 --- a/app/code/Magento/Config/etc/system_file.xsd +++ b/app/code/Magento/Config/etc/system_file.xsd @@ -49,7 +49,7 @@ <xs:attributeGroup name="tabAttributeGroup"> <xs:attribute name="id" type="typeId" use="required" /> <xs:attribute name="translate" type="xs:string" use="optional" /> - <xs:attribute name="sortOrder" type="xs:int" use="optional" /> + <xs:attribute name="sortOrder" type="xs:float" use="optional" /> <xs:attribute name="class" type="xs:string" use="optional" /> </xs:attributeGroup> @@ -57,7 +57,7 @@ <xs:attribute name="id" type="typeId" use="required" /> <xs:attribute name="translate" type="xs:string" use="optional" /> <xs:attribute name="type" type="xs:string" use="optional" /> - <xs:attribute name="sortOrder" type="xs:int" use="optional" /> + <xs:attribute name="sortOrder" type="xs:float" use="optional" /> <xs:attribute name="showInDefault" type="xs:int" use="optional" /> <xs:attribute name="showInStore" type="xs:int" use="optional" /> <xs:attribute name="showInWebsite" type="xs:int" use="optional" /> diff --git a/app/code/Magento/Customer/Model/AccountManagement.php b/app/code/Magento/Customer/Model/AccountManagement.php old mode 100644 new mode 100755 diff --git a/app/code/Magento/Customer/Model/Resource/CustomerRepository.php b/app/code/Magento/Customer/Model/Resource/CustomerRepository.php index 45bca42044092acc519258e045ebcdd864e70782..429210512de90ab81b93290918b34e533ba1d879 100644 --- a/app/code/Magento/Customer/Model/Resource/CustomerRepository.php +++ b/app/code/Magento/Customer/Model/Resource/CustomerRepository.php @@ -340,8 +340,7 @@ class CustomerRepository implements \Magento\Customer\Api\CustomerRepositoryInte $isEmailAddress = \Zend_Validate::is( $customer->getEmail(), - 'EmailAddress', - ['allow' => ['allow' => \Zend_Validate_Hostname::ALLOW_ALL, 'tld' => false]] + 'EmailAddress' ); if (!$isEmailAddress) { diff --git a/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php b/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php old mode 100644 new mode 100755 diff --git a/app/code/Magento/Store/etc/cache.xml b/app/code/Magento/Store/etc/cache.xml index 6dae6b683b09121e6bc3820d0d797fda2d7877bc..715a5a12e55b2534294eb688907d3522cbfa5e5e 100644 --- a/app/code/Magento/Store/etc/cache.xml +++ b/app/code/Magento/Store/etc/cache.xml @@ -22,6 +22,10 @@ <label>Collections Data</label> <description>Collection data files.</description> </type> + <type name="reflection" translate="label,description" instance="Magento\Framework\App\Cache\Type\Reflection"> + <label>Reflection Data</label> + <description>API interfaces reflection data.</description> + </type> <type name="db_ddl" translate="label,description" instance="Magento\Framework\DB\Adapter\DdlCache"> <label>Database DDL operations</label> <description>Results of DDL queries, such as describing tables or indexes.</description> diff --git a/app/code/Magento/Store/etc/di.xml b/app/code/Magento/Store/etc/di.xml index c8bc755197c49bb0f7aa5e0351784fe7a8b04ef9..617fefa4091297f0d0ef9cd76b8a3f97d309b2bc 100644 --- a/app/code/Magento/Store/etc/di.xml +++ b/app/code/Magento/Store/etc/di.xml @@ -225,6 +225,11 @@ </argument> </arguments> </type> + <type name="Magento\Framework\Reflection\MethodsMap"> + <arguments> + <argument name="cache" xsi:type="object">Magento\Framework\App\Cache\Type\Reflection</argument> + </arguments> + </type> <type name="Magento\Framework\Url"> <arguments> <argument name="scopeType" xsi:type="const">Magento\Store\Model\ScopeInterface::SCOPE_STORE</argument> diff --git a/app/code/Magento/User/Model/Resource/User.php b/app/code/Magento/User/Model/Resource/User.php index 9f2bf7f3d36599da3d9a48a0e6cd7291f89ef5dd..dc2f9c55f35ec5bcec961f881d6ed42c1129424e 100644 --- a/app/code/Magento/User/Model/Resource/User.php +++ b/app/code/Magento/User/Model/Resource/User.php @@ -522,8 +522,8 @@ class User extends \Magento\Framework\Model\Resource\Db\AbstractDb * Increment failures count along with updating lock expire and first failure dates * * @param ModelUser $user - * @param int|false $setLockExpires - * @param int|false $setFirstFailure + * @param int|bool $setLockExpires + * @param int|bool $setFirstFailure * @return void */ public function updateFailure($user, $setLockExpires = false, $setFirstFailure = false) diff --git a/app/code/Magento/User/Test/Unit/Model/Resource/UserTest.php b/app/code/Magento/User/Test/Unit/Model/Resource/UserTest.php new file mode 100755 index 0000000000000000000000000000000000000000..961cc40d5f3304599b2610c780d2d2774424af3b --- /dev/null +++ b/app/code/Magento/User/Test/Unit/Model/Resource/UserTest.php @@ -0,0 +1,442 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\User\Test\Unit\Model\Resource; + +/** + * Test class for \Magento\User\Model\Resource\User testing + */ +class UserTest extends \PHPUnit_Framework_TestCase +{ + /** @var \Magento\User\Model\Resource\User */ + protected $model; + + /** @var \Magento\User\Model\User|\PHPUnit_framework_MockObject_MockObject */ + protected $userMock; + + /** @var \Magento\Framework\Acl\CacheInterface|\PHPUnit_Framework_MockObject_MockObject */ + protected $aclCacheMock; + + /** @var \Magento\Framework\Model\Resource\Db\Context|\PHPUnit_Framework_MockObject_MockObject */ + protected $contextMock; + + /** @var \Magento\Authorization\Model\RoleFactory|\PHPUnit_Framework_MockObject_MockObject */ + protected $roleFactoryMock; + + /** @var \Magento\Framework\Stdlib\DateTime|\PHPUnit_Framework_MockObject_MockObject */ + protected $dateTimeMock; + + /** @var \Magento\Framework\App\Resource|\PHPUnit_Framework_MockObject_MockObject */ + protected $resourceMock; + + /** @var \Magento\Framework\DB\Adapter\AdapterInterface|\PHPUnit_Framework_MockObject_MockObject */ + protected $dbAdapterMock; + + /** @var \Magento\Framework\DB\Select|\PHPUnit_Framework_MockObject_MockObject */ + protected $selectMock; + + /** @var \Magento\Authorization\Model\Role|\PHPUnit_Framework_MockObject_MockObject */ + protected $roleMock; + + protected function setUp() + { + $this->userMock = $this->getMockBuilder('Magento\User\Model\User') + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $this->resourceMock = $this->getMockBuilder('Magento\Framework\App\Resource') + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $this->aclCacheMock = $this->getMockBuilder('Magento\Framework\Acl\CacheInterface') + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $this->roleFactoryMock = $this->getMockBuilder('Magento\Authorization\Model\RoleFactory') + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + + $this->roleMock = $this->getMockBuilder('Magento\Authorization\Model\Role') + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + + $this->dateTimeMock = $this->getMockBuilder('Magento\Framework\Stdlib\DateTime') + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $this->selectMock = $this->getMockBuilder('Magento\Framework\DB\Select') + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $this->dbAdapterMock = $this->getMockBuilder('Magento\Framework\DB\Adapter\AdapterInterface') + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->model = $helper->getObject( + 'Magento\User\Model\Resource\User', + [ + 'resource' => $this->resourceMock, + 'aclCache' => $this->aclCacheMock, + 'roleFactory' => $this->roleFactoryMock, + 'dateTime' => $this->dateTimeMock + ] + ); + } + + public function testIsUserUnique() + { + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock); + $this->selectMock->expects($this->once())->method('from')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('where')->willReturn($this->selectMock); + $this->dbAdapterMock->expects($this->once())->method('fetchRow')->willReturn([true]); + + $this->assertFalse($this->model->isUserUnique($this->userMock)); + } + + public function testRecordLogin() + { + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('update'); + + $this->assertInstanceOf('Magento\User\Model\Resource\User', $this->model->recordLogin($this->userMock)); + } + + public function testLoadByUsername() + { + $returnData = [1, 2, 3]; + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock); + $this->selectMock->expects($this->once())->method('from')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('where')->willReturn($this->selectMock); + $this->dbAdapterMock->expects($this->once())->method('fetchRow')->willReturn($returnData); + + $this->assertEquals($returnData, $this->model->loadByUsername('user1')); + } + + + public function testHasAssigned2Role() + { + $returnData = [1, 2, 3]; + $uid = 1234; + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->selectMock->expects($this->once())->method('from')->willReturn($this->selectMock); + $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('where')->willReturn($this->selectMock); + $this->dbAdapterMock->expects($this->once())->method('fetchAll')->willReturn($returnData); + + $this->assertEquals($returnData, $this->model->hasAssigned2Role($uid)); + $this->assertNull($this->model->hasAssigned2Role(0)); + } + + public function testHasAssigned2RolePassAnObject() + { + $methodUserMock = $this->getMockBuilder('\Magento\Framework\Model\AbstractModel') + ->disableOriginalConstructor() + ->setMethods(['getUserId']) + ->getMock(); + $returnData = [1, 2, 3]; + $uid = 1234; + $methodUserMock->expects($this->once())->method('getUserId')->willReturn($uid); + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock); + $this->selectMock->expects($this->once())->method('from')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('where')->willReturn($this->selectMock); + $this->dbAdapterMock->expects($this->once())->method('fetchAll')->willReturn($returnData); + + $this->assertEquals($returnData, $this->model->hasAssigned2Role($methodUserMock)); + } + + public function testClearUserRoles() + { + $uid = 123; + $this->userMock->expects($this->once())->method('getId')->willReturn($uid); + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('delete'); + $this->model->_clearUserRoles($this->userMock); + } + + public function testDeleteSucess() + { + $uid = 123; + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('beginTransaction'); + $this->userMock->expects($this->once())->method('getId')->willReturn($uid); + $this->dbAdapterMock->expects($this->atLeastOnce())->method('delete'); + + $this->assertTrue($this->model->delete($this->userMock)); + } + + public function testGetRolesEmptyId() + { + $this->assertEquals([], $this->model->getRoles($this->userMock)); + } + + public function testGetRolesReturnFilledArray() + { + $uid = 123; + $this->userMock->expects($this->atLeastOnce())->method('getId')->willReturn($uid); + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock); + $this->selectMock->expects($this->once())->method('from')->willReturn($this->selectMock); + $this->selectMock->expects($this->once())->method('joinLeft')->willReturn($this->selectMock); + $this->selectMock->expects($this->once())->method('where')->willReturn($this->selectMock); + $this->dbAdapterMock->expects($this->once())->method('fetchCol')->willReturn([1, 2, 3]); + $this->assertEquals([1, 2, 3], $this->model->getRoles($this->userMock)); + } + + public function testGetRolesFetchRowFailure() + { + $uid = 123; + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->userMock->expects($this->atLeastOnce())->method('getId')->willReturn($uid); + $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock); + $this->selectMock->expects($this->once())->method('from')->willReturn($this->selectMock); + $this->selectMock->expects($this->once())->method('joinLeft')->willReturn($this->selectMock); + $this->selectMock->expects($this->once())->method('where')->willReturn($this->selectMock); + $this->dbAdapterMock->expects($this->once())->method('fetchCol')->willReturn(false); + $this->assertEquals([], $this->model->getRoles($this->userMock)); + } + + public function testSaveExtraEmptyId() + { + $this->resourceMock->expects($this->never())->method('getConnection'); + $this->assertInstanceOf( + 'Magento\User\Model\Resource\User', + $this->model->saveExtra($this->userMock, [1, 2, 3]) + ); + } + + public function testSaveExtraFilledId() + { + $uid = 123; + $this->userMock->expects($this->atLeastOnce())->method('getId')->willReturn($uid); + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('update'); + $this->assertInstanceOf( + 'Magento\User\Model\Resource\User', + $this->model->saveExtra($this->userMock, [1, 2, 3]) + ); + } + + public function testCountAll() + { + $returnData = 123; + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock); + $this->dbAdapterMock->expects($this->once())->method('fetchOne')->willReturn($returnData); + $this->assertEquals($returnData, $this->model->countAll()); + } + + public function testUpdateRoleUsersAclWithUsers() + { + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->roleMock->expects($this->once())->method('getRoleUsers')->willReturn(['user1', 'user2']); + $this->dbAdapterMock->expects($this->once())->method('update')->willReturn(1); + $this->assertTrue($this->model->updateRoleUsersAcl($this->roleMock)); + } + + public function testUpdateRoleUsersAclNoUsers() + { + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->roleMock->expects($this->once())->method('getRoleUsers')->willReturn([]); + $this->dbAdapterMock->expects($this->never())->method('update'); + $this->assertFalse($this->model->updateRoleUsersAcl($this->roleMock)); + } + + public function testUpdateRoleUsersAclUpdateFail() + { + $this->resourceMock->expects($this->once())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->roleMock->expects($this->once())->method('getRoleUsers')->willReturn(['user1', 'user2']); + $this->dbAdapterMock->expects($this->once())->method('update')->willReturn(0); + $this->assertFalse($this->model->updateRoleUsersAcl($this->roleMock)); + } + + public function testUnlock() + { + $inputData = [1, 2, 3]; + $returnData = 5; + $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('update')->willReturn($returnData); + $this->assertEquals($returnData, $this->model->unlock($inputData)); + } + + public function testUnlockWithInteger() + { + $inputData = 123; + $returnData = 5; + $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('update')->willReturn($returnData); + $this->assertEquals($returnData, $this->model->unlock($inputData)); + } + + public function testLock() + { + $inputData = [1, 2, 3]; + $returnData = 5; + $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('update')->willReturn($returnData); + $this->assertEquals($returnData, $this->model->lock($inputData, 1, 1)); + } + + public function testLockWithInteger() + { + $inputData = 123; + $returnData = 5; + $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('update')->willReturn($returnData); + $this->assertEquals($returnData, $this->model->lock($inputData, 1, 1)); + } + + public function testGetOldPassword() + { + $returnData = ['password1', 'password2']; + $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->atLeastOnce())->method('select')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('from')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('order')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('where')->willReturn($this->selectMock); + $this->dbAdapterMock->expects($this->atLeastOnce())->method('fetchCol')->willReturn($returnData); + $this->assertEquals($returnData, $this->model->getOldPasswords($this->userMock)); + } + + public function testDeleteFromRole() + { + $methodUserMock = $this->getMockBuilder('\Magento\Framework\Model\AbstractModel') + ->disableOriginalConstructor() + ->setMethods(['getUserId', 'getRoleId']) + ->getMock(); + $uid = 1234; + $roleId = 44; + $methodUserMock->expects($this->once())->method('getUserId')->willReturn($uid); + $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock); + $methodUserMock->expects($this->atleastOnce())->method('getRoleId')->willReturn($roleId); + $this->dbAdapterMock->expects($this->once())->method('delete'); + + $this->assertInstanceOf('\Magento\User\Model\Resource\User', $this->model->deleteFromRole($methodUserMock)); + } + + public function testRoleUserExists() + { + $methodUserMock = $this->getMockBuilder('\Magento\Framework\Model\AbstractModel') + ->disableOriginalConstructor() + ->setMethods(['getUserId', 'getRoleId']) + ->getMock(); + $uid = 1234; + $roleId = 44; + $returnData = [1, 2, 3]; + $methodUserMock->expects($this->atLeastOnce())->method('getUserId')->willReturn($uid); + $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock); + $methodUserMock->expects($this->once())->method('getRoleId')->willReturn($roleId); + $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('from')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('where')->willReturn($this->selectMock); + $this->dbAdapterMock->expects($this->once())->method('fetchCol')->willReturn($returnData); + + $this->assertEquals($returnData, $this->model->roleUserExists($methodUserMock)); + $this->assertEquals([], $this->model->roleUserExists($this->userMock)); + } + + public function testGetValidationBeforeSave() + { + $this->assertInstanceOf('\Zend_Validate_Callback', $this->model->getValidationRulesBeforeSave()); + } + + public function testUpdateFailure() + { + $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('update')->willReturn($this->selectMock); + $this->dbAdapterMock->expects($this->once())->method('quoteInto')->willReturn($this->selectMock); + $this->model->updateFailure($this->userMock, 1, 1); + } + + public function testTrackPassword() + { + $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('insert')->willReturn($this->selectMock); + $this->model->trackPassword($this->userMock, "myPas#w0rd", 1); + } + + public function testGetLatestPassword() + { + $uid = 123; + $returnData = ['password1', 'password2']; + $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->dbAdapterMock->expects($this->once())->method('fetchRow')->willReturn($returnData); + $this->dbAdapterMock->expects($this->once())->method('select')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('from')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('where')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('order')->willReturn($this->selectMock); + $this->selectMock->expects($this->atLeastOnce())->method('limit')->willReturn($this->selectMock); + $this->assertEquals($returnData, $this->model->getLatestPassword($uid)); + } + + public function testInitUniqueFields() + { + $this->assertInstanceOf( + '\Magento\User\Model\Resource\User', + $this->invokeMethod($this->model, '_initUniqueFields', []) + ); + } + + public function testBeforeSave() + { + $this->userMock->expects($this->once())->method('isObjectNew')->willReturn(true); + + $this->assertInstanceOf( + '\Magento\User\Model\Resource\User', + $this->invokeMethod($this->model, '_beforeSave', [$this->userMock]) + ); + } + + public function testAfterSave() + { + $roleId = 123; + $methodUserMock = $this->getMockBuilder('\Magento\User\Model\User') + ->disableOriginalConstructor() + ->setMethods(['hasRoleId', 'getRoleId']) + ->getMock(); + $methodUserMock->expects($this->once())->method('hasRoleId')->willReturn(true); + $methodUserMock->expects($this->once())->method('getRoleId')->willReturn($roleId); + $this->resourceMock->expects($this->atLeastOnce())->method('getConnection')->willReturn($this->dbAdapterMock); + $this->roleFactoryMock->expects($this->once())->method('create')->willReturn($this->roleMock); + $this->roleMock->expects($this->once())->method('load')->willReturn($this->roleMock); + $this->roleMock->expects($this->atLeastOnce())->method('getId')->willReturn($roleId); + $this->dbAdapterMock->expects($this->once())->method('describeTable')->willReturn([1, 2, 3]); + + $this->assertInstanceOf( + '\Magento\User\Model\Resource\User', + $this->invokeMethod($this->model, '_afterSave', [$methodUserMock]) + ); + } + + /** + * Call protected/private method of a class. + * + * @param $object + * @param $methodName + * @param array $parameters + * @return mixed + */ + public function invokeMethod(&$object, $methodName, array $parameters = []) + { + $reflection = new \ReflectionClass(get_class($object)); + $method = $reflection->getMethod($methodName); + $method->setAccessible(true); + + return $method->invokeArgs($object, $parameters); + } +} diff --git a/app/code/Magento/Webapi/etc/di.xml b/app/code/Magento/Webapi/etc/di.xml index 28d00c467ea83ed0f8973860c67544efaef81294..593ef6427082d1d149c84a4d761567e28a7594e4 100644 --- a/app/code/Magento/Webapi/etc/di.xml +++ b/app/code/Magento/Webapi/etc/di.xml @@ -21,18 +21,6 @@ <type name="Magento\Framework\Xml\Generator" shared="false" /> <type name="Magento\Framework\Xml\Parser" shared="false" /> <type name="Magento\Framework\Code\Scanner\DirectoryScanner" shared="false" /> - <type name="Magento\Server\Reflection" shared="false" /> - <type name="Magento\Framework\Reflection\MethodsMap"> - <arguments> - <argument name="cache" xsi:type="object">Magento\Framework\App\Cache\Type\Webapi</argument> - </arguments> - </type> - <type name="Magento\Framework\Reflection\DataObjectProcessor"> - <arguments> - <argument name="extensionAttributesProcessor" xsi:type="object">Magento\Framework\Reflection\ExtensionAttributesProcessor\Proxy</argument> - <argument name="customAttributesProcessor" xsi:type="object">Magento\Framework\Reflection\CustomAttributesProcessor\Proxy</argument> - </arguments> - </type> <type name="Magento\Integration\Model\ConfigBasedIntegrationManager"> <plugin name="webapiSetup" type="Magento\Webapi\Model\Plugin\Manager" /> </type> diff --git a/app/etc/di.xml b/app/etc/di.xml index fbb7c6946ce3cb006f2be5c1d76476b3e5f05f53..e26240c8b6c8cb6200191e0c245d5f371e1b90c9 100755 --- a/app/etc/di.xml +++ b/app/etc/di.xml @@ -1048,6 +1048,13 @@ </argument> </arguments> </type> + <type name="Magento\Server\Reflection" shared="false" /> + <type name="Magento\Framework\Reflection\DataObjectProcessor"> + <arguments> + <argument name="extensionAttributesProcessor" xsi:type="object">Magento\Framework\Reflection\ExtensionAttributesProcessor\Proxy</argument> + <argument name="customAttributesProcessor" xsi:type="object">Magento\Framework\Reflection\CustomAttributesProcessor\Proxy</argument> + </arguments> + </type> <type name="Magento\Framework\Url\Decoder"> <arguments> <argument name="urlBuilder" xsi:type="object">Magento\Framework\UrlInterface</argument> diff --git a/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/StockItemTest.php b/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/StockItemTest.php index 0f49b8bef0ae3f56dfff91db4c9ae8cc25f371c4..606c42e6b1269fa16cd5fc1c279fb7f561232425 100644 --- a/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/StockItemTest.php +++ b/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/StockItemTest.php @@ -90,7 +90,7 @@ class StockItemTest extends WebapiAbstract $arguments = ['productSku' => $productSku]; $apiResult = $this->_webApiCall($serviceInfo, $arguments); $result['item_id'] = $apiResult['item_id']; - $this->assertEquals($result, $apiResult, 'The stock data does not match.'); + $this->assertEquals($result, array_intersect_key($apiResult, $result), 'The stock data does not match.'); return $apiResult; } @@ -140,7 +140,7 @@ class StockItemTest extends WebapiAbstract $stockItemResource = $this->objectManager->get('Magento\CatalogInventory\Model\Resource\Stock\Item'); $stockItemResource->loadByProductId($stockItem, $stockItemOld['product_id'], $stockItemOld['website_id']); $expectedResult['item_id'] = $stockItem->getItemId(); - $this->assertEquals($expectedResult, $stockItem->getData()); + $this->assertEquals($expectedResult, array_intersect_key($stockItem->getData(), $expectedResult)); } /** @@ -234,7 +234,7 @@ class StockItemTest extends WebapiAbstract 'manage_stock' => 1, 'low_stock_date' => '', 'is_decimal_divided' => '', - 'stock_status_changed_auto' => 0 + 'stock_status_changed_auto' => 0, ], ], ]; diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Layer/Filter/_files/attribute_with_option_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Layer/Filter/_files/attribute_with_option_rollback.php index 1f31bde19a817f5c4888d8fe3faee5edbf6d67be..172ba1389b391a03d3d0da01d79f83e321eb5c29 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Layer/Filter/_files/attribute_with_option_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Layer/Filter/_files/attribute_with_option_rollback.php @@ -11,7 +11,31 @@ $installer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create $attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( 'Magento\Catalog\Model\Resource\Eav\Attribute' ); -$attribute->loadByCode($installer->getEntityTypeId('catalog_product'), 'attribute_with_option'); +$attribute->loadByCode(\Magento\Catalog\Model\Product::ENTITY, 'attribute_with_option'); + +/* Delete simple products per each option */ +/** @var $options \Magento\Eav\Model\Resource\Entity\Attribute\Option\Collection */ +$options = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + 'Magento\Eav\Model\Resource\Entity\Attribute\Option\Collection' +); +$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get('Magento\Framework\Registry'); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); +$options->setAttributeFilter($attribute->getId()); + +foreach ($options as $option) { + /** @var $product \Magento\Catalog\Model\Product */ + $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product'); + $product = $product->loadByAttribute('sku', 'simple_product_' . $option->getId()); + if ($product->getId()) { + $product->delete(); + } +} + if ($attribute->getId()) { $attribute->delete(); } + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartTest.php b/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartTest.php index d719463f60ad96888d041073905bc7092420ed74..01b7f93ad982137e8d62277d45d8eb86919275cf 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartTest.php @@ -99,7 +99,7 @@ class CartTest extends \PHPUnit_Framework_TestCase $html = $this->_block->toHtml(); $this->assertContains("<div id=\"customer_cart_grid\"", $html); $this->assertContains("<div class=\"admin__data-grid-header admin__data-grid-toolbar\"", $html); - $this->assertContains("customer_cart_gridJsObject = new varienGrid('customer_cart_grid',", $html); + $this->assertContains("customer_cart_gridJsObject = new varienGrid(\"customer_cart_grid\",", $html); $this->assertContains( "backend/customer/cart_product_composite_cart/configure/customer_id/" . self::CUSTOMER_ID_VALUE, $html diff --git a/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartsTest.php b/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartsTest.php index 5bbdca87782a224ea4e59558e12e1231b5c26ddd..5e7361b26cfda79f70348f48503466e9d9f0b390 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartsTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartsTest.php @@ -61,7 +61,7 @@ class CartsTest extends \PHPUnit_Framework_TestCase '/<div class=".*admin__data-grid-toolbar"/', $html ); - $this->assertContains("customer_cart_grid1JsObject = new varienGrid('customer_cart_grid1',", $html); + $this->assertContains("customer_cart_grid1JsObject = new varienGrid(\"customer_cart_grid1\",", $html); $this->assertContains("backend/customer/cart_product_composite_cart/configure/website_id/1", $html); } @@ -84,7 +84,7 @@ class CartsTest extends \PHPUnit_Framework_TestCase '/<div class=".*admin__data-grid-toolbar"/', $html ); - $this->assertContains("customer_cart_gridJsObject = new varienGrid('customer_cart_grid',", $html); + $this->assertContains("customer_cart_gridJsObject = new varienGrid(\"customer_cart_grid\",", $html); $this->assertContains("backend/customer/cart_product_composite_cart/configure/key/", $html); } } diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/filterable_attribute_rollback.php b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/filterable_attribute_rollback.php index 04a82aafb8219f3114aa0266fe6ef2ec24f147bb..24cf533ddf5ca4517b325491545b4a0026bb9561 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/filterable_attribute_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/filterable_attribute_rollback.php @@ -14,7 +14,27 @@ $installer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create $attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( 'Magento\Catalog\Model\Resource\Eav\Attribute' ); -$attribute->loadByCode($installer->getEntityTypeId('catalog_product'), 'select_attribute'); +$attribute->loadByCode(\Magento\Catalog\Model\Product::ENTITY, 'select_attribute'); + +/** @var $selectOptions \Magento\Eav\Model\Resource\Entity\Attribute\Option\Collection */ +$selectOptions = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + 'Magento\Eav\Model\Resource\Entity\Attribute\Option\Collection' +); +$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get('Magento\Framework\Registry'); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +$selectOptions->setAttributeFilter($attribute->getId()); +/* Delete simple products per each select(dropdown) option */ +foreach ($selectOptions as $option) { + /** @var $product \Magento\Catalog\Model\Product */ + $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product'); + $product = $product->loadByAttribute('sku', 'simple_product_' . $option->getId()); + if ($product->getId()) { + $product->delete(); + } +} if ($attribute->getId()) { $attribute->delete(); } @@ -23,3 +43,6 @@ $attribute->loadByCode($installer->getEntityTypeId('catalog_product'), 'multisel if ($attribute->getId()) { $attribute->delete(); } + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Resource/Product/Type/Grouped/AssociatedProductsCollectionTest.php b/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Resource/Product/Type/Grouped/AssociatedProductsCollectionTest.php index 416e72ed185bd35179b80ab8699a8c343899bd7d..bee5e691d76d85b59bedb2c0e8df0b5b8c62368d 100644 --- a/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Resource/Product/Type/Grouped/AssociatedProductsCollectionTest.php +++ b/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/Resource/Product/Type/Grouped/AssociatedProductsCollectionTest.php @@ -10,6 +10,7 @@ class AssociatedProductsCollectionTest extends \PHPUnit_Framework_TestCase /** * @magentoDataFixture Magento/GroupedProduct/_files/product_grouped.php * @magentoAppIsolation enabled + * @magentoDbIsolation disabled */ public function testGetColumnValues() { diff --git a/lib/internal/Magento/Framework/App/Cache/Type/Reflection.php b/lib/internal/Magento/Framework/App/Cache/Type/Reflection.php new file mode 100644 index 0000000000000000000000000000000000000000..5ad5d1e30a8cc7e9a2b4543199db7570ec50e30c --- /dev/null +++ b/lib/internal/Magento/Framework/App/Cache/Type/Reflection.php @@ -0,0 +1,30 @@ +<?php +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\App\Cache\Type; + +/** + * System / Cache Management / Cache type "Reflection Data" + */ +class Reflection extends \Magento\Framework\Cache\Frontend\Decorator\TagScope +{ + /** + * Cache type code unique among all cache types + */ + const TYPE_IDENTIFIER = 'reflection'; + + /** + * Cache tag used to distinguish the cache type from all other cache + */ + const CACHE_TAG = 'REFLECTION'; + + /** + * @param \Magento\Framework\App\Cache\Type\FrontendPool $cacheFrontendPool + */ + public function __construct(\Magento\Framework\App\Cache\Type\FrontendPool $cacheFrontendPool) + { + parent::__construct($cacheFrontendPool->get(self::TYPE_IDENTIFIER), self::CACHE_TAG); + } +}