diff --git a/app/code/Magento/Catalog/Model/ResourceModel/AbstractResource.php b/app/code/Magento/Catalog/Model/ResourceModel/AbstractResource.php
index 0a7f9c2dd9634..b754e178d48c2 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/AbstractResource.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/AbstractResource.php
@@ -502,7 +502,7 @@ public function getAttributeRawValue($entityId, $attribute, $store)
$staticTable,
$staticAttributes
)->join(
- ['e' => $this->getTable('catalog_product_entity')],
+ ['e' => $this->getTable($this->getEntityTable())],
'e.' . $this->getLinkField() . ' = ' . $staticTable . '.' . $this->getLinkField()
)->where(
'e.entity_id = :entity_id'
@@ -523,7 +523,7 @@ public function getAttributeRawValue($entityId, $attribute, $store)
$select = $connection->select()
->from(['default_value' => $table], ['attribute_id'])
->join(
- ['e' => $this->getTable('catalog_product_entity')],
+ ['e' => $this->getTable($this->getEntityTable())],
'e.' . $this->getLinkField() . ' = ' . 'default_value.' . $this->getLinkField(),
''
)->where('default_value.attribute_id IN (?)', array_keys($_attributes))
diff --git a/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/Form/Modifier/AdvancedInventory.php b/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/Form/Modifier/AdvancedInventory.php
index 38032a1c2c5d2..546483a660bd7 100644
--- a/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/Form/Modifier/AdvancedInventory.php
+++ b/app/code/Magento/CatalogInventory/Ui/DataProvider/Product/Form/Modifier/AdvancedInventory.php
@@ -213,7 +213,6 @@ private function prepareMeta()
'dataScope' => 'qty',
'validation' => [
'validate-number' => true,
- 'validate-digits' => true,
'less-than-equals-to' => StockDataFilter::MAX_QTY_VALUE,
],
'imports' => [
diff --git a/app/code/Magento/CatalogInventory/view/adminhtml/ui_component/product_form.xml b/app/code/Magento/CatalogInventory/view/adminhtml/ui_component/product_form.xml
index d7de033ea3b76..362aac7c8cf30 100644
--- a/app/code/Magento/CatalogInventory/view/adminhtml/ui_component/product_form.xml
+++ b/app/code/Magento/CatalogInventory/view/adminhtml/ui_component/product_form.xml
@@ -95,7 +95,6 @@
- quantity_and_stock_status.qty
-
- true
- - true
- 99999999
- 200
diff --git a/app/code/Magento/CatalogInventory/view/adminhtml/web/js/components/qty-validator-changer.js b/app/code/Magento/CatalogInventory/view/adminhtml/web/js/components/qty-validator-changer.js
index b14527c9c9ec6..f45d32d6482d6 100644
--- a/app/code/Magento/CatalogInventory/view/adminhtml/web/js/components/qty-validator-changer.js
+++ b/app/code/Magento/CatalogInventory/view/adminhtml/web/js/components/qty-validator-changer.js
@@ -19,8 +19,7 @@ define([
handleChanges: function (value) {
var isDigits = value !== 1;
- this.validation['validate-number'] = !isDigits;
- this.validation['validate-digits'] = isDigits;
+ this.validation['validate-integer'] = isDigits;
this.validation['less-than-equals-to'] = isDigits ? 99999999 : 99999999.9999;
this.validate();
}
diff --git a/app/code/Magento/Cms/Controller/Adminhtml/Page/MassDelete.php b/app/code/Magento/Cms/Controller/Adminhtml/Page/MassDelete.php
index c357045a3d084..64f9b7e51769a 100644
--- a/app/code/Magento/Cms/Controller/Adminhtml/Page/MassDelete.php
+++ b/app/code/Magento/Cms/Controller/Adminhtml/Page/MassDelete.php
@@ -15,6 +15,13 @@
*/
class MassDelete extends \Magento\Backend\App\Action
{
+ /**
+ * Authorization level of a basic admin session
+ *
+ * @see _isAllowed()
+ */
+ const ADMIN_RESOURCE = 'Magento_Cms::page_delete';
+
/**
* @var Filter
*/
diff --git a/app/code/Magento/Cms/etc/frontend/page_types.xml b/app/code/Magento/Cms/etc/frontend/page_types.xml
index 76dec5cdcba6b..c5df71b7904ff 100644
--- a/app/code/Magento/Cms/etc/frontend/page_types.xml
+++ b/app/code/Magento/Cms/etc/frontend/page_types.xml
@@ -9,7 +9,6 @@
-
diff --git a/app/code/Magento/Developer/Model/Logger/Handler/Debug.php b/app/code/Magento/Developer/Model/Logger/Handler/Debug.php
new file mode 100644
index 0000000000000..e05f008f70aa8
--- /dev/null
+++ b/app/code/Magento/Developer/Model/Logger/Handler/Debug.php
@@ -0,0 +1,56 @@
+state = $state;
+ $this->scopeConfig = $scopeConfig;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isHandling(array $record)
+ {
+ return
+ parent::isHandling($record)
+ && $this->state->getMode() !== State::MODE_PRODUCTION
+ && $this->scopeConfig->getValue('dev/debug/debug_logging', ScopeInterface::SCOPE_STORE);
+ }
+}
\ No newline at end of file
diff --git a/app/code/Magento/Developer/Test/Unit/Model/Logger/Handler/DebugTest.php b/app/code/Magento/Developer/Test/Unit/Model/Logger/Handler/DebugTest.php
new file mode 100644
index 0000000000000..7eae4020e6768
--- /dev/null
+++ b/app/code/Magento/Developer/Test/Unit/Model/Logger/Handler/DebugTest.php
@@ -0,0 +1,117 @@
+filesystemMock = $this->getMockBuilder(DriverInterface::class)
+ ->getMockForAbstractClass();
+ $this->stateMock = $this->getMockBuilder(State::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->scopeConfigMock = $this->getMockBuilder(ScopeConfigInterface::class)
+ ->getMockForAbstractClass();
+ $this->formatterMock = $this->getMockBuilder(FormatterInterface::class)
+ ->getMockForAbstractClass();
+
+ $this->formatterMock->expects($this->any())
+ ->method('format')
+ ->willReturn(null);
+
+ $this->model = (new ObjectManager($this))->getObject(Debug::class, [
+ 'filesystem' => $this->filesystemMock,
+ 'state' => $this->stateMock,
+ 'scopeConfig' => $this->scopeConfigMock,
+ ]);
+ $this->model->setFormatter($this->formatterMock);
+ }
+
+ public function testHandle()
+ {
+ $this->stateMock->expects($this->once())
+ ->method('getMode')
+ ->willReturn(State::MODE_DEVELOPER);
+ $this->scopeConfigMock->expects($this->once())
+ ->method('getValue')
+ ->with('dev/debug/debug_logging', ScopeInterface::SCOPE_STORE, null)
+ ->willReturn(true);
+
+ $this->model->handle(['formatted' => false, 'level' => Logger::DEBUG]);
+ }
+
+ public function testHandleDisabledByProduction()
+ {
+ $this->stateMock->expects($this->once())
+ ->method('getMode')
+ ->willReturn(State::MODE_PRODUCTION);
+ $this->scopeConfigMock->expects($this->never())
+ ->method('getValue');
+
+ $this->model->handle(['formatted' => false, 'level' => Logger::DEBUG]);
+ }
+
+ public function testHandleDisabledByConfig()
+ {
+ $this->stateMock->expects($this->once())
+ ->method('getMode')
+ ->willReturn(State::MODE_DEVELOPER);
+ $this->scopeConfigMock->expects($this->once())
+ ->method('getValue')
+ ->with('dev/debug/debug_logging', ScopeInterface::SCOPE_STORE, null)
+ ->willReturn(false);
+
+ $this->model->handle(['formatted' => false, 'level' => Logger::DEBUG]);
+ }
+
+ public function testHandleDisabledByLevel()
+ {
+ $this->stateMock->expects($this->never())
+ ->method('getMode');
+ $this->scopeConfigMock->expects($this->never())
+ ->method('getValue');
+
+ $this->model->handle(['formatted' => false, 'level' => Logger::API]);
+ }
+}
diff --git a/app/code/Magento/Developer/etc/adminhtml/system.xml b/app/code/Magento/Developer/etc/adminhtml/system.xml
index 551704598ee70..11b07c2794baf 100644
--- a/app/code/Magento/Developer/etc/adminhtml/system.xml
+++ b/app/code/Magento/Developer/etc/adminhtml/system.xml
@@ -23,6 +23,13 @@
Magento\Developer\Model\Config\Backend\AllowedIps
+
+
+
+ Not available in production mode.
+ Magento\Config\Model\Config\Source\Yesno
+
+
diff --git a/app/code/Magento/Developer/etc/di.xml b/app/code/Magento/Developer/etc/di.xml
index a7fc549a0d993..90f63f93104b3 100644
--- a/app/code/Magento/Developer/etc/di.xml
+++ b/app/code/Magento/Developer/etc/di.xml
@@ -9,6 +9,7 @@
+
diff --git a/app/code/Magento/Paypal/etc/frontend/page_types.xml b/app/code/Magento/Paypal/etc/frontend/page_types.xml
index 1c8b200632ab5..1649f23ff4339 100644
--- a/app/code/Magento/Paypal/etc/frontend/page_types.xml
+++ b/app/code/Magento/Paypal/etc/frontend/page_types.xml
@@ -6,7 +6,7 @@
*/
-->
-
+
@@ -18,5 +18,5 @@
-
+
diff --git a/app/code/Magento/Sales/etc/frontend/page_types.xml b/app/code/Magento/Sales/etc/frontend/page_types.xml
index f4e7fa7035d75..d8069d7714fa6 100644
--- a/app/code/Magento/Sales/etc/frontend/page_types.xml
+++ b/app/code/Magento/Sales/etc/frontend/page_types.xml
@@ -6,24 +6,24 @@
*/
-->
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
+
+
diff --git a/app/code/Magento/Sitemap/Controller/Adminhtml/Sitemap/Delete.php b/app/code/Magento/Sitemap/Controller/Adminhtml/Sitemap/Delete.php
index bfd0985ee7e96..afc123590625a 100644
--- a/app/code/Magento/Sitemap/Controller/Adminhtml/Sitemap/Delete.php
+++ b/app/code/Magento/Sitemap/Controller/Adminhtml/Sitemap/Delete.php
@@ -11,6 +11,16 @@
class Delete extends \Magento\Sitemap\Controller\Adminhtml\Sitemap
{
+ /**
+ * @var \Magento\Framework\Filesystem
+ */
+ private $filesystem;
+
+ /**
+ * @var \Magento\Sitemap\Model\SitemapFactory
+ */
+ private $sitemapFactory;
+
/**
* Delete action
*
@@ -18,30 +28,24 @@ class Delete extends \Magento\Sitemap\Controller\Adminhtml\Sitemap
*/
public function execute()
{
- /** @var \Magento\Framework\Filesystem\Directory\Write $directory */
- $directory = $this->_objectManager->get(
- 'Magento\Framework\Filesystem'
- )->getDirectoryWrite(
- DirectoryList::ROOT
- );
-
+ $directory = $this->getFilesystem()->getDirectoryWrite(DirectoryList::ROOT);
// check if we know what should be deleted
$id = $this->getRequest()->getParam('sitemap_id');
if ($id) {
try {
// init model and delete
- $model = $this->_objectManager->create('Magento\Sitemap\Model\Sitemap');
- $model->setId($id);
- // init and load sitemap model
-
- /* @var $sitemap \Magento\Sitemap\Model\Sitemap */
- $model->load($id);
+ /** @var \Magento\Sitemap\Model\Sitemap $sitemap */
+ $sitemap = $this->getSitemapFactory()->create();
+ $sitemap->load($id);
// delete file
- $path = $directory->getRelativePath($model->getPreparedFilename());
- if ($model->getSitemapFilename() && $directory->isFile($path)) {
+ $sitemapPath = $sitemap->getSitemapPath();
+ $sitemapFilename = $sitemap->getSitemapFilename();
+
+ $path = $directory->getRelativePath($sitemapPath . $sitemapFilename);
+ if ($sitemap->getSitemapFilename() && $directory->isFile($path)) {
$directory->delete($path);
}
- $model->delete();
+ $sitemap->delete();
// display success message
$this->messageManager->addSuccess(__('You deleted the sitemap.'));
// go to grid
@@ -60,4 +64,38 @@ public function execute()
// go to grid
$this->_redirect('adminhtml/*/');
}
+
+ /**
+ * The getter function to get Filesystem object for real application code
+ *
+ * @return \Magento\Framework\Filesystem
+ *
+ * @deprecated
+ */
+ private function getFilesystem()
+ {
+ if ($this->filesystem === null) {
+ $this->filesystem = \Magento\Framework\App\ObjectManager::getInstance()->get(
+ \Magento\Framework\Filesystem::class
+ );
+ }
+ return $this->filesystem;
+ }
+
+ /**
+ * The getter function to get SitemapFactory object for real application code
+ *
+ * @return \Magento\Sitemap\Model\SitemapFactory
+ *
+ * @deprecated
+ */
+ private function getSitemapFactory()
+ {
+ if ($this->sitemapFactory === null) {
+ $this->sitemapFactory = \Magento\Framework\App\ObjectManager::getInstance()->get(
+ \Magento\Sitemap\Model\SitemapFactory::class
+ );
+ }
+ return $this->sitemapFactory;
+ }
}
diff --git a/app/code/Magento/Sitemap/Test/Unit/Controller/Adminhtml/Sitemap/DeleteTest.php b/app/code/Magento/Sitemap/Test/Unit/Controller/Adminhtml/Sitemap/DeleteTest.php
new file mode 100644
index 0000000000000..8035f057d6b66
--- /dev/null
+++ b/app/code/Magento/Sitemap/Test/Unit/Controller/Adminhtml/Sitemap/DeleteTest.php
@@ -0,0 +1,149 @@
+filesystemMock = $this->getMockBuilder(\Magento\Framework\Filesystem::class)
+ ->disableOriginalConstructor()
+ ->setMethods([])
+ ->getMock();
+ $this->sitemapFactoryMock = $this->getMockBuilder(\Magento\Sitemap\Model\SitemapFactory::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['create'])
+ ->getMock();
+ $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\RequestInterface::class)
+ ->disableOriginalConstructor()
+ ->setMethods([])
+ ->getMockForAbstractClass();
+ $this->responseMock = $this->getMockBuilder(\Magento\Framework\App\ResponseInterface::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['setRedirect'])
+ ->getMockForAbstractClass();
+ $this->messageManagerMock = $this->getMockBuilder(\Magento\Framework\Message\ManagerInterface::class)
+ ->disableOriginalConstructor()
+ ->setMethods([])
+ ->getMockForAbstractClass();
+
+ $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+
+ $this->deleteController = $objectManagerHelper->getObject(
+ \Magento\Sitemap\Controller\Adminhtml\Sitemap\Delete::class,
+ [
+ 'request' => $this->requestMock,
+ 'response' => $this->responseMock,
+ 'messageManager' => $this->messageManagerMock,
+ 'filesystem' => $this->filesystemMock,
+ 'sitemapFactory' => $this->sitemapFactoryMock
+ ]
+ );
+ }
+
+ public function testExecuteWithoutSitemapId()
+ {
+ $writeDirectoryMock = $this->getMockBuilder(\Magento\Framework\Filesystem\Directory\WriteInterface::class)
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $this->filesystemMock->expects($this->any())->method('getDirectoryWrite')->willReturn($writeDirectoryMock);
+ $this->requestMock->expects($this->any())->method('getParam')->with('sitemap_id')->willReturn(0);
+ $this->responseMock->expects($this->once())->method('setRedirect');
+ $this->messageManagerMock->expects($this->any())
+ ->method('addError')
+ ->with('We can\'t find a sitemap to delete.');
+
+ $this->deleteController->execute();
+ }
+
+ public function testExecuteCannotFindSitemap()
+ {
+ $id = 1;
+ $writeDirectoryMock = $this->getMockBuilder(\Magento\Framework\Filesystem\Directory\WriteInterface::class)
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $this->filesystemMock->expects($this->any())->method('getDirectoryWrite')->willReturn($writeDirectoryMock);
+ $this->requestMock->expects($this->any())->method('getParam')->with('sitemap_id')->willReturn($id);
+
+ $sitemapMock = $this->getMockBuilder(\Magento\Sitemap\Model\Sitemap::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['load'])
+ ->getMock();
+
+ $sitemapMock->expects($this->once())->method('load')->with($id)->willThrowException(new \Exception);
+ $this->sitemapFactoryMock->expects($this->once())->method('create')->willReturn($sitemapMock);
+ $this->responseMock->expects($this->once())->method('setRedirect');
+ $this->messageManagerMock->expects($this->any())
+ ->method('addError');
+
+ $this->deleteController->execute();
+ }
+
+ public function testExecute()
+ {
+ $id = 1;
+ $sitemapPath = '/';
+ $sitemapFilename = 'sitemap.xml';
+ $relativePath = '/sitemap.xml';
+ $writeDirectoryMock = $this->getMockBuilder(\Magento\Framework\Filesystem\Directory\WriteInterface::class)
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $this->filesystemMock->expects($this->any())->method('getDirectoryWrite')->willReturn($writeDirectoryMock);
+ $this->requestMock->expects($this->any())->method('getParam')->with('sitemap_id')->willReturn($id);
+
+ $sitemapMock = $this->getMockBuilder(\Magento\Sitemap\Model\Sitemap::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getSitemapPath', 'getSitemapFilename', 'load', 'delete'])
+ ->getMock();
+ $sitemapMock->expects($this->once())->method('load')->with($id);
+ $sitemapMock->expects($this->once())->method('delete');
+ $sitemapMock->expects($this->any())->method('getSitemapPath')->willReturn($sitemapPath);
+ $sitemapMock->expects($this->any())->method('getSitemapFilename')->willReturn($sitemapFilename);
+ $this->sitemapFactoryMock->expects($this->once())->method('create')->willReturn($sitemapMock);
+ $writeDirectoryMock->expects($this->any())
+ ->method('getRelativePath')
+ ->with($sitemapPath . $sitemapFilename)
+ ->willReturn($relativePath);
+ $writeDirectoryMock->expects($this->once())->method('isFile')->with($relativePath)->willReturn(true);
+ $writeDirectoryMock->expects($this->once())->method('delete')->with($relativePath)->willReturn(true);
+
+ $this->responseMock->expects($this->once())->method('setRedirect');
+ $this->messageManagerMock->expects($this->any())
+ ->method('addSuccess');
+
+ $this->deleteController->execute();
+ }
+}
diff --git a/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js b/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js
index 555c10ee04b70..ea6268789c059 100644
--- a/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js
+++ b/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js
@@ -572,6 +572,15 @@ define([
},
$.mage.__('Please enter a valid number in this field.')
],
+ 'validate-integer': [
+ function(value) {
+ return (
+ utils.isEmptyNoTrim(value)
+ || (!isNaN(utils.parseNumber(value)) && /^\s*-?\d*\s*$/.test(value))
+ );
+ },
+ $.mage.__('Please enter a valid integer in this field.')
+ ],
"validate-number-range": [
function(value, param) {
if (utils.isEmptyNoTrim(value)) {
diff --git a/app/code/Magento/Widget/Model/Widget.php b/app/code/Magento/Widget/Model/Widget.php
index 2235df9aff077..481e15f3122b5 100644
--- a/app/code/Magento/Widget/Model/Widget.php
+++ b/app/code/Magento/Widget/Model/Widget.php
@@ -313,13 +313,13 @@ public function getWidgetDeclaration($type, $params = [], $asIs = true)
$value = $parameters[$name]->getValue();
}
}
- if ($value) {
+
+ if (isset($value)) {
$directive .= sprintf(' %s="%s"', $name, $value);
}
}
$directive .= $this->getWidgetPageVarName($params);
-
$directive .= '}}';
if ($asIs) {
diff --git a/app/code/Magento/Widget/Test/Unit/Model/WidgetTest.php b/app/code/Magento/Widget/Test/Unit/Model/WidgetTest.php
index 2d03ac62c1563..be04a62830fd7 100644
--- a/app/code/Magento/Widget/Test/Unit/Model/WidgetTest.php
+++ b/app/code/Magento/Widget/Test/Unit/Model/WidgetTest.php
@@ -5,6 +5,8 @@
*/
namespace Magento\Widget\Test\Unit\Model;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
class WidgetTest extends \PHPUnit_Framework_TestCase
{
/**
@@ -101,7 +103,7 @@ public function testGetConfigAsObject()
$this->assertSame('Magento_Cms::images/widget_page_link.png', $resultObject->getPlaceholderImage());
$resultParameters = $resultObject->getParameters();
- $this->assertInstanceOf('Magento\Framework\DataObject', $resultParameters['page_id' ]);
+ $this->assertInstanceOf('Magento\Framework\DataObject', $resultParameters['page_id']);
$this->assertInstanceOf('Magento\Framework\DataObject', $resultParameters['anchor_text']);
$this->assertInstanceOf('Magento\Framework\DataObject', $resultParameters['template']);
@@ -162,4 +164,46 @@ public function testGetWidgetDeclaration()
$this->assertContains('conditions_encoded="encoded-conditions-string"', $result);
$this->assertContains('page_var_name="pasdf"}}', $result);
}
+
+ public function testGetWidgetDeclarationWithZeroValueParam()
+ {
+ $mathRandomMock = $this->getMock('\Magento\Framework\Math\Random', ['getRandomString'], [], '', false);
+ $mathRandomMock->expects($this->any())
+ ->method('getRandomString')
+ ->willReturn('asdf');
+
+ (new ObjectManager($this))->setBackwardCompatibleProperty(
+ $this->widget,
+ 'mathRandom',
+ $mathRandomMock
+ );
+
+ $conditions = [
+ [
+ 'type' => 'Magento\CatalogWidget\Model\Rule\Condition\Combine',
+ 'aggregator' => 'all',
+ 'value' => '1',
+ 'new_child' => ''
+ ]
+ ];
+ $params = [
+ 'title' => 'my widget',
+ 'show_pager' => '1',
+ 'products_per_page' => '5',
+ 'products_count' => '0',
+ 'template' => 'product/widget/content/grid.phtml',
+ 'conditions' => $conditions
+ ];
+
+ $this->conditionsHelper->expects($this->once())
+ ->method('encode')
+ ->with($conditions)
+ ->willReturn('encoded-conditions-string');
+
+ $result = $this->widget->getWidgetDeclaration('Magento\CatalogWidget\Block\Product\ProductsList', $params);
+ $this->assertContains('{{widget type="Magento\CatalogWidget\Block\Product\ProductsList"', $result);
+ $this->assertContains('conditions_encoded="encoded-conditions-string"', $result);
+ $this->assertContains('page_var_name="pasdf"}}', $result);
+ $this->assertContains('products_count="0"', $result);
+ }
}
diff --git a/dev/tests/functional/lib/Magento/Mtf/Client/Element/MultiselectgrouplistElement.php b/dev/tests/functional/lib/Magento/Mtf/Client/Element/MultiselectgrouplistElement.php
index cad083a69b854..f179d7d905340 100644
--- a/dev/tests/functional/lib/Magento/Mtf/Client/Element/MultiselectgrouplistElement.php
+++ b/dev/tests/functional/lib/Magento/Mtf/Client/Element/MultiselectgrouplistElement.php
@@ -324,4 +324,17 @@ protected function getSelectedOptions()
return $options;
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function deselectAll()
+ {
+ $options = $this->getSelectedOptions();
+
+ /** @var SimpleElement $option */
+ foreach ($options as $option) {
+ $option->click();
+ }
+ }
}
diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Block/Edit/CmsForm.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Block/Edit/CmsForm.xml
index 6f9a6354411f2..79b707b504abd 100644
--- a/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Block/Edit/CmsForm.xml
+++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Block/Edit/CmsForm.xml
@@ -12,7 +12,6 @@
multiselectgrouplist
- .admin__actions-switch-label
switcher
diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockNotOnCategoryPage.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockNotOnCategoryPage.php
index 1057e7d058f26..93ae1f121fbbd 100644
--- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockNotOnCategoryPage.php
+++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockNotOnCategoryPage.php
@@ -11,6 +11,7 @@
use Magento\Cms\Test\Page\CmsIndex;
use Magento\Mtf\Constraint\AbstractConstraint;
use Magento\Mtf\Fixture\FixtureFactory;
+use Magento\Catalog\Test\Fixture\Category;
/**
* Assert that created CMS block non visible on frontend category page.
@@ -25,25 +26,29 @@ class AssertCmsBlockNotOnCategoryPage extends AbstractConstraint
* @param CmsBlock $cmsBlock
* @param CatalogCategoryView $catalogCategoryView
* @param FixtureFactory $fixtureFactory
+ * @param Category|null $category [optional]
* @return void
*/
public function processAssert(
CmsIndex $cmsIndex,
CmsBlock $cmsBlock,
CatalogCategoryView $catalogCategoryView,
- FixtureFactory $fixtureFactory
+ FixtureFactory $fixtureFactory,
+ Category $category = null
) {
- $category = $fixtureFactory->createByCode(
- 'category',
- [
- 'dataset' => 'default_subcategory',
- 'data' => [
- 'display_mode' => 'Static block and products',
- 'landing_page' => $cmsBlock->getTitle(),
+ if ($category === null) {
+ $category = $fixtureFactory->createByCode(
+ 'category',
+ [
+ 'dataset' => 'default_subcategory',
+ 'data' => [
+ 'display_mode' => 'Static block and products',
+ 'landing_page' => $cmsBlock->getTitle(),
+ ]
]
- ]
- );
- $category->persist();
+ );
+ $category->persist();
+ }
$cmsIndex->open();
$cmsIndex->getTopmenu()->selectCategoryByName($category->getName());
diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/DeleteCmsBlockEntityTest.php b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/DeleteCmsBlockEntityTest.php
index 6c231797d89d5..c4897ea36269d 100644
--- a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/DeleteCmsBlockEntityTest.php
+++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/DeleteCmsBlockEntityTest.php
@@ -10,6 +10,8 @@
use Magento\Cms\Test\Page\Adminhtml\CmsBlockIndex;
use Magento\Cms\Test\Page\Adminhtml\CmsBlockNew;
use Magento\Mtf\TestCase\Injectable;
+use Magento\Mtf\Fixture\FixtureFactory;
+use Magento\Catalog\Test\Fixture\Category;
/**
* Preconditions:
@@ -46,37 +48,73 @@ class DeleteCmsBlockEntityTest extends Injectable
*/
protected $cmsBlockNew;
+ /**
+ * Fixture Factory.
+ *
+ * @var FixtureFactory
+ */
+ private $fixtureFactory;
+
/**
* Injection data.
*
* @param CmsBlockIndex $cmsBlockIndex
* @param CmsBlockNew $cmsBlockNew
+ * @param FixtureFactory $fixtureFactory
* @return void
*/
public function __inject(
CmsBlockIndex $cmsBlockIndex,
- CmsBlockNew $cmsBlockNew
+ CmsBlockNew $cmsBlockNew,
+ FixtureFactory $fixtureFactory
) {
$this->cmsBlockIndex = $cmsBlockIndex;
$this->cmsBlockNew = $cmsBlockNew;
+ $this->fixtureFactory = $fixtureFactory;
}
/**
* Delete CMS Block.
*
* @param CmsBlock $cmsBlock
- * @return void
+ * @return array
*/
public function test(CmsBlock $cmsBlock)
{
// Precondition
$cmsBlock->persist();
$filter = ['identifier' => $cmsBlock->getIdentifier()];
+ $category = $this->createCategory($cmsBlock);
// Steps
$this->cmsBlockIndex->open();
$this->cmsBlockIndex->getCmsBlockGrid()->searchAndOpen($filter);
$this->cmsBlockNew->getFormPageActions()->delete();
$this->cmsBlockNew->getModalBlock()->acceptAlert();
+
+ return ['category' => $category];
+ }
+
+ /**
+ * Create category.
+ *
+ * @param CmsBlock $cmsBlock
+ * @return Category
+ */
+ private function createCategory(CmsBlock $cmsBlock)
+ {
+ $category = $this->fixtureFactory->createByCode(
+ 'category',
+ [
+ 'dataset' => 'default_subcategory',
+ 'data' => [
+ 'display_mode' => 'Static block and products',
+ 'landing_page' => $cmsBlock->getTitle(),
+ ]
+ ]
+ );
+ $category->persist();
+
+ return $category;
}
}
diff --git a/lib/internal/Magento/Framework/App/Utility/Files.php b/lib/internal/Magento/Framework/App/Utility/Files.php
index cf5a8aae3b501..9c9ad3e44adf3 100644
--- a/lib/internal/Magento/Framework/App/Utility/Files.php
+++ b/lib/internal/Magento/Framework/App/Utility/Files.php
@@ -890,6 +890,16 @@ private function accumulateThemeStaticFiles($area, $locale, $filePattern, &$resu
throw new \UnexpectedValueException("Could not parse theme static file '$file'");
}
}
+
+ if (!$files) {
+ $result[] = [
+ $themeArea,
+ $themePackage->getVendor() . '/' . $themePackage->getName(),
+ null,
+ null,
+ null,
+ ];
+ }
}
}
}
diff --git a/lib/internal/Magento/Framework/Logger/Monolog.php b/lib/internal/Magento/Framework/Logger/Monolog.php
index 9840d61b1846a..bde27b2164cfb 100644
--- a/lib/internal/Magento/Framework/Logger/Monolog.php
+++ b/lib/internal/Magento/Framework/Logger/Monolog.php
@@ -10,12 +10,25 @@
class Monolog extends Logger
{
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct($name, array $handlers = [], array $processors = [])
+ {
+ /**
+ * TODO: This should be eliminated with MAGETWO-53989
+ */
+ $handlers = array_values($handlers);
+
+ parent::__construct($name, $handlers, $processors);
+ }
+
/**
* Adds a log record.
*
- * @param integer $level The logging level
- * @param string $message The log message
- * @param array $context The log context
+ * @param integer $level The logging level
+ * @param string $message The log message
+ * @param array $context The log context
* @return Boolean Whether the record has been processed
*/
public function addRecord($level, $message, array $context = [])
diff --git a/lib/internal/Magento/Framework/View/Element/AbstractBlock.php b/lib/internal/Magento/Framework/View/Element/AbstractBlock.php
index 1700186de7b20..6f979066d6fc2 100644
--- a/lib/internal/Magento/Framework/View/Element/AbstractBlock.php
+++ b/lib/internal/Magento/Framework/View/Element/AbstractBlock.php
@@ -167,6 +167,11 @@ abstract class AbstractBlock extends \Magento\Framework\DataObject implements Bl
*/
protected $_scopeConfig;
+ /**
+ * @var \Magento\Framework\App\CacheInterface
+ */
+ protected $_cache;
+
/**
* Constructor
*
@@ -1004,14 +1009,20 @@ protected function getCacheTags()
/**
* Get block cache life time
*
- * @return int
+ * @return int|bool|null
*/
protected function getCacheLifetime()
{
if (!$this->hasData('cache_lifetime')) {
return null;
}
- return $this->getData('cache_lifetime');
+
+ $cacheLifetime = $this->getData('cache_lifetime');
+ if (false === $cacheLifetime || null === $cacheLifetime) {
+ return $cacheLifetime;
+ }
+
+ return (int)$cacheLifetime;
}
/**
diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Element/AbstractBlockTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Element/AbstractBlockTest.php
index 0605210f360ee..dad0d22d188c9 100644
--- a/lib/internal/Magento/Framework/View/Test/Unit/Element/AbstractBlockTest.php
+++ b/lib/internal/Magento/Framework/View/Test/Unit/Element/AbstractBlockTest.php
@@ -12,20 +12,80 @@
use Magento\Framework\View\Element\Context;
use Magento\Framework\Config\View;
use Magento\Framework\View\ConfigInterface;
+use Magento\Framework\Event\ManagerInterface as EventManagerInterface;
+use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Framework\App\Cache\StateInterface as CacheStateInterface;
+use Magento\Framework\App\CacheInterface;
+use Magento\Framework\Session\SidResolverInterface;
+use Magento\Framework\Session\SessionManagerInterface;
class AbstractBlockTest extends \PHPUnit_Framework_TestCase
{
/**
* @var AbstractBlock
*/
- protected $block;
+ private $block;
+
+ /**
+ * @var EventManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $eventManagerMock;
+
+ /**
+ * @var ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $scopeConfigMock;
+
+ /**
+ * @var CacheStateInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $cacheStateMock;
+
+ /**
+ * @var CacheInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $cacheMock;
+
+ /**
+ * @var SidResolverInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $sidResolverMock;
+
+ /**
+ * @var SessionManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $sessionMock;
/**
* @return void
*/
protected function setUp()
{
+ $this->eventManagerMock = $this->getMockForAbstractClass(EventManagerInterface::class);
+ $this->scopeConfigMock = $this->getMockForAbstractClass(ScopeConfigInterface::class);
+ $this->cacheStateMock = $this->getMockForAbstractClass(CacheStateInterface::class);
+ $this->cacheMock = $this->getMockForAbstractClass(CacheInterface::class);
+ $this->sidResolverMock = $this->getMockForAbstractClass(SidResolverInterface::class);
+ $this->sessionMock = $this->getMockForAbstractClass(SessionManagerInterface::class);
$contextMock = $this->getMock(Context::class, [], [], '', false);
+ $contextMock->expects($this->once())
+ ->method('getEventManager')
+ ->willReturn($this->eventManagerMock);
+ $contextMock->expects($this->once())
+ ->method('getScopeConfig')
+ ->willReturn($this->scopeConfigMock);
+ $contextMock->expects($this->once())
+ ->method('getCacheState')
+ ->willReturn($this->cacheStateMock);
+ $contextMock->expects($this->once())
+ ->method('getCache')
+ ->willReturn($this->cacheMock);
+ $contextMock->expects($this->once())
+ ->method('getSidResolver')
+ ->willReturn($this->sidResolverMock);
+ $contextMock->expects($this->once())
+ ->method('getSession')
+ ->willReturn($this->sessionMock);
$this->block = $this->getMockForAbstractClass(
AbstractBlock::class,
['context' => $contextMock]
@@ -135,4 +195,125 @@ public function testGetCacheKeyByName()
$cacheKey = sha1($nameInLayout);
$this->assertEquals(AbstractBlock::CACHE_KEY_PREFIX . $cacheKey, $this->block->getCacheKey());
}
+
+ /**
+ * @return void
+ */
+ public function testToHtmlWhenModuleIsDisabled()
+ {
+ $moduleName = 'Test';
+ $this->block->setData('module_name', $moduleName);
+
+ $this->eventManagerMock->expects($this->once())
+ ->method('dispatch')
+ ->with('view_block_abstract_to_html_before', ['block' => $this->block]);
+ $this->scopeConfigMock->expects($this->once())
+ ->method('getValue')
+ ->with('advanced/modules_disable_output/' . $moduleName, \Magento\Store\Model\ScopeInterface::SCOPE_STORE)
+ ->willReturn(true);
+
+ $this->assertSame('', $this->block->toHtml());
+ }
+
+ /**
+ * @param string|bool $cacheLifetime
+ * @param string|bool $dataFromCache
+ * @param string $dataForSaveCache
+ * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $expectsCacheLoad
+ * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $expectsCacheSave
+ * @param string $expectedResult
+ * @return void
+ * @dataProvider getCacheLifetimeDataProvider
+ */
+ public function testGetCacheLifetimeViaToHtml(
+ $cacheLifetime,
+ $dataFromCache,
+ $dataForSaveCache,
+ $expectsCacheLoad,
+ $expectsCacheSave,
+ $expectedResult
+ ) {
+ $moduleName = 'Test';
+ $cacheKey = 'testKey';
+ $this->block->setData('cache_key', $cacheKey);
+ $this->block->setData('module_name', $moduleName);
+ $this->block->setData('cache_lifetime', $cacheLifetime);
+
+ $this->eventManagerMock->expects($this->once())
+ ->method('dispatch')
+ ->with('view_block_abstract_to_html_before', ['block' => $this->block]);
+ $this->scopeConfigMock->expects($this->once())
+ ->method('getValue')
+ ->with('advanced/modules_disable_output/' . $moduleName, \Magento\Store\Model\ScopeInterface::SCOPE_STORE)
+ ->willReturn(false);
+ $this->cacheStateMock->expects($this->any())
+ ->method('isEnabled')
+ ->with(AbstractBlock::CACHE_GROUP)
+ ->willReturn(true);
+ $this->cacheMock->expects($expectsCacheLoad)
+ ->method('load')
+ ->with(AbstractBlock::CACHE_KEY_PREFIX . $cacheKey)
+ ->willReturn($dataFromCache);
+ $this->cacheMock->expects($expectsCacheSave)
+ ->method('save')
+ ->with($dataForSaveCache, AbstractBlock::CACHE_KEY_PREFIX . $cacheKey);
+ $this->sidResolverMock->expects($this->any())
+ ->method('getSessionIdQueryParam')
+ ->with($this->sessionMock)
+ ->willReturn('sessionIdQueryParam');
+ $this->sessionMock->expects($this->any())
+ ->method('getSessionId')
+ ->willReturn('sessionId');
+
+ $this->assertSame($expectedResult, $this->block->toHtml());
+ }
+
+ /**
+ * @return array
+ */
+ public function getCacheLifetimeDataProvider()
+ {
+ return [
+ [
+ 'cacheLifetime' => null,
+ 'dataFromCache' => 'dataFromCache',
+ 'dataForSaveCache' => '',
+ 'expectsCacheLoad' => $this->never(),
+ 'expectsCacheSave' => $this->never(),
+ 'expectedResult' => '',
+ ],
+ [
+ 'cacheLifetime' => false,
+ 'dataFromCache' => 'dataFromCache',
+ 'dataForSaveCache' => '',
+ 'expectsCacheLoad' => $this->once(),
+ 'expectsCacheSave' => $this->never(),
+ 'expectedResult' => 'dataFromCache',
+ ],
+ [
+ 'cacheLifetime' => 120,
+ 'dataFromCache' => 'dataFromCache',
+ 'dataForSaveCache' => '',
+ 'expectsCacheLoad' => $this->once(),
+ 'expectsCacheSave' => $this->never(),
+ 'expectedResult' => 'dataFromCache',
+ ],
+ [
+ 'cacheLifetime' => '120string',
+ 'dataFromCache' => 'dataFromCache',
+ 'dataForSaveCache' => '',
+ 'expectsCacheLoad' => $this->once(),
+ 'expectsCacheSave' => $this->never(),
+ 'expectedResult' => 'dataFromCache',
+ ],
+ [
+ 'cacheLifetime' => 120,
+ 'dataFromCache' => false,
+ 'dataForSaveCache' => '',
+ 'expectsCacheLoad' => $this->once(),
+ 'expectsCacheSave' => $this->once(),
+ 'expectedResult' => '',
+ ],
+ ];
+ }
}
diff --git a/lib/web/mage/adminhtml/browser.js b/lib/web/mage/adminhtml/browser.js
index 7ddd91482210e..5089bde34912d 100644
--- a/lib/web/mage/adminhtml/browser.js
+++ b/lib/web/mage/adminhtml/browser.js
@@ -31,12 +31,14 @@ define([
},
openDialog: function(url, width, height, title, options) {
var windowId = this.windowId,
- content = '',
+ content = '',
self = this;
if (this.modal) {
this.modal.html($(content).html());
- this.modal.modal('option', 'closed', options.closed);
+ if (options && typeof options.closed !== 'undefined') {
+ this.modal.modal('option', 'closed', options.closed);
+ }
} else {
this.modal = $(content).modal($.extend({
title: title || 'Insert File...',
diff --git a/pub/errors/processor.php b/pub/errors/processor.php
index f5415d14ab534..218628f349e5e 100644
--- a/pub/errors/processor.php
+++ b/pub/errors/processor.php
@@ -568,7 +568,7 @@ protected function _validate()
*/
protected function _setSkin($value, \stdClass $config = null)
{
- if (preg_match('/^[a-z0-9_]+$/i', $value) && is_dir($this->_indexDir . self::ERROR_DIR . '/' . $value)) {
+ if (preg_match('/^[a-z0-9_]+$/i', $value) && is_dir($this->_errorDir . $value)) {
if (!$config) {
if ($this->_config) {
$config = $this->_config;