diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Eav/AbstractAction.php b/app/code/Magento/Catalog/Model/Indexer/Product/Eav/AbstractAction.php
index b6206f96b91e0..6101e5cd362e4 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Product/Eav/AbstractAction.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Eav/AbstractAction.php
@@ -3,6 +3,8 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\Catalog\Model\Indexer\Product\Eav;
use Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\AbstractEav;
@@ -12,6 +14,11 @@
*/
abstract class AbstractAction
{
+ /**
+ * Config path for enable EAV indexer
+ */
+ const ENABLE_EAV_INDEXER = 'catalog/search/enable_eav_indexer';
+
/**
* EAV Indexers by type
*
@@ -29,17 +36,27 @@ abstract class AbstractAction
*/
protected $_eavDecimalFactory;
+ /**
+ * @var \Magento\Framework\App\Config\ScopeConfigInterface
+ */
+ private $scopeConfig;
+
/**
* AbstractAction constructor.
* @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory $eavDecimalFactory
* @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory $eavSourceFactory
+ * @param \Magento\Framework\App\Config\ScopeConfigInterface|null $scopeConfig
*/
public function __construct(
\Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory $eavDecimalFactory,
- \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory $eavSourceFactory
+ \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory $eavSourceFactory,
+ \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig = null
) {
$this->_eavDecimalFactory = $eavDecimalFactory;
$this->_eavSourceFactory = $eavSourceFactory;
+ $this->scopeConfig = $scopeConfig ?: \Magento\Framework\App\ObjectManager::getInstance()->get(
+ \Magento\Framework\App\Config\ScopeConfigInterface::class
+ );
}
/**
@@ -92,6 +109,9 @@ public function getIndexer($type)
*/
public function reindex($ids = null)
{
+ if (!$this->isEavIndexerEnabled()) {
+ return;
+ }
foreach ($this->getIndexers() as $indexer) {
if ($ids === null) {
$indexer->reindexAll();
@@ -149,4 +169,19 @@ protected function processRelations(AbstractEav $indexer, array $ids, bool $only
return array_unique(array_merge($ids, $childIds, $parentIds));
}
+
+ /**
+ * Get EAV indexer status
+ *
+ * @return bool
+ */
+ private function isEavIndexerEnabled(): bool
+ {
+ $eavIndexerStatus = $this->scopeConfig->getValue(
+ self::ENABLE_EAV_INDEXER,
+ \Magento\Store\Model\ScopeInterface::SCOPE_STORE
+ );
+
+ return (bool)$eavIndexerStatus;
+ }
}
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Eav/Action/Full.php b/app/code/Magento/Catalog/Model/Indexer/Product/Eav/Action/Full.php
index bc747e62f641e..802176092d147 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Product/Eav/Action/Full.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Eav/Action/Full.php
@@ -3,12 +3,15 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\Catalog\Model\Indexer\Product\Eav\Action;
use Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher;
/**
* Class Full reindex action
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class Full extends \Magento\Catalog\Model\Indexer\Product\Eav\AbstractAction
{
@@ -32,6 +35,11 @@ class Full extends \Magento\Catalog\Model\Indexer\Product\Eav\AbstractAction
*/
private $activeTableSwitcher;
+ /**
+ * @var \Magento\Framework\App\Config\ScopeConfigInterface
+ */
+ private $scopeConfig;
+
/**
* @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory $eavDecimalFactory
* @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory $eavSourceFactory
@@ -39,6 +47,7 @@ class Full extends \Magento\Catalog\Model\Indexer\Product\Eav\AbstractAction
* @param \Magento\Framework\Indexer\BatchProviderInterface|null $batchProvider
* @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\BatchSizeCalculator $batchSizeCalculator
* @param ActiveTableSwitcher|null $activeTableSwitcher
+ * @param \Magento\Framework\App\Config\ScopeConfigInterface|null $scopeConfig
*/
public function __construct(
\Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory $eavDecimalFactory,
@@ -46,9 +55,13 @@ public function __construct(
\Magento\Framework\EntityManager\MetadataPool $metadataPool = null,
\Magento\Framework\Indexer\BatchProviderInterface $batchProvider = null,
\Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\BatchSizeCalculator $batchSizeCalculator = null,
- ActiveTableSwitcher $activeTableSwitcher = null
+ ActiveTableSwitcher $activeTableSwitcher = null,
+ \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig = null
) {
- parent::__construct($eavDecimalFactory, $eavSourceFactory);
+ $this->scopeConfig = $scopeConfig ?: \Magento\Framework\App\ObjectManager::getInstance()->get(
+ \Magento\Framework\App\Config\ScopeConfigInterface::class
+ );
+ parent::__construct($eavDecimalFactory, $eavSourceFactory, $scopeConfig);
$this->metadataPool = $metadataPool ?: \Magento\Framework\App\ObjectManager::getInstance()->get(
\Magento\Framework\EntityManager\MetadataPool::class
);
@@ -73,6 +86,9 @@ public function __construct(
*/
public function execute($ids = null)
{
+ if (!$this->isEavIndexerEnabled()) {
+ return;
+ }
try {
foreach ($this->getIndexers() as $indexerName => $indexer) {
$connection = $indexer->getConnection();
@@ -129,4 +145,19 @@ protected function syncData($indexer, $destinationTable, $ids = null)
throw $e;
}
}
+
+ /**
+ * Get EAV indexer status
+ *
+ * @return bool
+ */
+ private function isEavIndexerEnabled(): bool
+ {
+ $eavIndexerStatus = $this->scopeConfig->getValue(
+ self::ENABLE_EAV_INDEXER,
+ \Magento\Store\Model\ScopeInterface::SCOPE_STORE
+ );
+
+ return (bool)$eavIndexerStatus;
+ }
}
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/AbstractActionTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/AbstractActionTest.php
index 9d58822fb6073..6ad14af44304e 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/AbstractActionTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/AbstractActionTest.php
@@ -22,6 +22,14 @@ class AbstractActionTest extends \PHPUnit\Framework\TestCase
*/
protected $_eavSourceFactoryMock;
+ /**
+ * @var \Magento\Framework\App\Config\ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $scopeConfig;
+
+ /**
+ * @return void
+ */
protected function setUp()
{
$this->_eavDecimalFactoryMock = $this->createPartialMock(
@@ -32,12 +40,22 @@ protected function setUp()
\Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory::class,
['create']
);
+ $this->scopeConfig = $this->getMockBuilder(\Magento\Framework\App\Config\ScopeConfigInterface::class)
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
$this->_model = $this->getMockForAbstractClass(
\Magento\Catalog\Model\Indexer\Product\Eav\AbstractAction::class,
- [$this->_eavDecimalFactoryMock, $this->_eavSourceFactoryMock, []]
+ [
+ $this->_eavDecimalFactoryMock,
+ $this->_eavSourceFactoryMock,
+ $this->scopeConfig
+ ]
);
}
+ /**
+ * @return void
+ */
public function testGetIndexers()
{
$expectedIndexers = [
@@ -73,6 +91,10 @@ public function testGetIndexerWithUnknownTypeThrowsException()
$this->_model->getIndexer('unknown_type');
}
+ /**
+ * @return void
+ * @throws \Magento\Framework\Exception\LocalizedException
+ */
public function testGetIndexer()
{
$this->_eavSourceFactoryMock->expects($this->once())
@@ -86,6 +108,10 @@ public function testGetIndexer()
$this->assertEquals('source_return_value', $this->_model->getIndexer('source'));
}
+ /**
+ * @return void
+ * @throws \Exception
+ */
public function testReindexWithoutArgumentsExecutesReindexAll()
{
$eavSource = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\Source::class)
@@ -110,6 +136,10 @@ public function testReindexWithoutArgumentsExecutesReindexAll()
->method('create')
->will($this->returnValue($eavDecimal));
+ $this->scopeConfig->expects($this->once())
+ ->method('getValue')
+ ->willReturn(1);
+
$this->_model->reindex();
}
@@ -174,9 +204,25 @@ public function testReindexWithNotNullArgumentExecutesReindexEntities(
->method('create')
->will($this->returnValue($eavDecimal));
+ $this->scopeConfig->expects($this->once())
+ ->method('getValue')
+ ->willReturn(1);
+
$this->_model->reindex($ids);
}
+ /**
+ * @return void
+ * @throws \Exception
+ */
+ public function testReindexWithDisabledEavIndexer()
+ {
+ $this->scopeConfig->expects($this->once())->method('getValue')->willReturn(0);
+ $this->_eavSourceFactoryMock->expects($this->never())->method('create');
+ $this->_eavDecimalFactoryMock->expects($this->never())->method('create');
+ $this->_model->reindex();
+ }
+
/**
* @return array
*/
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/Action/FullTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/Action/FullTest.php
index c254557904da1..90c3f999a6a8b 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/Action/FullTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/Action/FullTest.php
@@ -5,53 +5,87 @@
*/
namespace Magento\Catalog\Test\Unit\Model\Indexer\Product\Eav\Action;
+use Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory;
+use Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory;
+use Magento\Framework\EntityManager\MetadataPool;
+use Magento\Framework\Indexer\BatchProviderInterface;
+use Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\BatchSizeCalculator;
+
/**
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class FullTest extends \PHPUnit\Framework\TestCase
{
- public function testExecuteWithAdapterErrorThrowsException()
- {
- $eavDecimalFactory = $this->createPartialMock(
- \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory::class,
- ['create']
- );
- $eavSourceFactory = $this->createPartialMock(
- \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory::class,
- ['create']
- );
+ /**
+ * @var \Magento\Catalog\Model\Indexer\Product\Eav\Action\Full|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $model;
- $exceptionMessage = 'exception message';
- $exception = new \Exception($exceptionMessage);
+ /**
+ * @var DecimalFactory|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $eavDecimalFactory;
- $eavDecimalFactory->expects($this->once())
- ->method('create')
- ->will($this->throwException($exception));
+ /**
+ * @var SourceFactory|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $eavSourceFactory;
- $metadataMock = $this->createMock(\Magento\Framework\EntityManager\MetadataPool::class);
- $batchProviderMock = $this->createMock(\Magento\Framework\Indexer\BatchProviderInterface::class);
+ /**
+ * @var MetadataPool|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $metadataPool;
- $batchManagementMock = $this->createMock(
- \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\BatchSizeCalculator::class
- );
+ /**
+ * @var BatchProviderInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $batchProvider;
- $tableSwitcherMock = $this->getMockBuilder(
- \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher::class
- )->disableOriginalConstructor()->getMock();
-
- $model = new \Magento\Catalog\Model\Indexer\Product\Eav\Action\Full(
- $eavDecimalFactory,
- $eavSourceFactory,
- $metadataMock,
- $batchProviderMock,
- $batchManagementMock,
- $tableSwitcherMock
- );
+ /**
+ * @var BatchSizeCalculator|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $batchSizeCalculator;
+
+ /**
+ * @var ActiveTableSwitcher|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $activeTableSwitcher;
+
+ /**
+ * @var \Magento\Framework\App\Config\ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $scopeConfig;
- $this->expectException(\Magento\Framework\Exception\LocalizedException::class);
- $this->expectExceptionMessage($exceptionMessage);
+ /**
+ * @return void
+ */
+ protected function setUp()
+ {
+ $this->eavDecimalFactory = $this->createPartialMock(DecimalFactory::class, ['create']);
+ $this->eavSourceFactory = $this->createPartialMock(SourceFactory::class, ['create']);
+ $this->metadataPool = $this->createMock(MetadataPool::class);
+ $this->batchProvider = $this->getMockForAbstractClass(BatchProviderInterface::class);
+ $this->batchSizeCalculator = $this->createMock(BatchSizeCalculator::class);
+ $this->activeTableSwitcher = $this->createMock(ActiveTableSwitcher::class);
+ $this->scopeConfig = $this->getMockBuilder(\Magento\Framework\App\Config\ScopeConfigInterface::class)
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
- $model->execute();
+ $objectManager = new ObjectManager($this);
+ $this->model = $objectManager->getObject(
+ \Magento\Catalog\Model\Indexer\Product\Eav\Action\Full::class,
+ [
+ 'eavDecimalFactory' => $this->eavDecimalFactory,
+ 'eavSourceFactory' => $this->eavSourceFactory,
+ 'metadataPool' => $this->metadataPool,
+ 'batchProvider' => $this->batchProvider,
+ 'batchSizeCalculator' => $this->batchSizeCalculator,
+ 'activeTableSwitcher' => $this->activeTableSwitcher,
+ 'scopeConfig' => $this->scopeConfig
+ ]
+ );
}
/**
@@ -59,14 +93,7 @@ public function testExecuteWithAdapterErrorThrowsException()
*/
public function testExecute()
{
- $eavDecimalFactory = $this->createPartialMock(
- \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory::class,
- ['create']
- );
- $eavSourceFactory = $this->createPartialMock(
- \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory::class,
- ['create']
- );
+ $this->scopeConfig->expects($this->once())->method('getValue')->willReturn(1);
$ids = [1, 2, 3];
$connectionMock = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class)
@@ -90,42 +117,29 @@ public function testExecute()
$eavSource->expects($this->atLeastOnce())->method('getConnection')->willReturn($connectionMock);
$eavDecimal->expects($this->atLeastOnce())->method('getConnection')->willReturn($connectionMock);
- $eavDecimal->expects($this->once())
- ->method('reindexEntities')
- ->with($ids);
+ $eavDecimal->expects($this->once())->method('reindexEntities')->with($ids);
- $eavSource->expects($this->once())
- ->method('reindexEntities')
- ->with($ids);
+ $eavSource->expects($this->once())->method('reindexEntities')->with($ids);
- $eavDecimalFactory->expects($this->once())
- ->method('create')
- ->will($this->returnValue($eavSource));
+ $this->eavDecimalFactory->expects($this->once())->method('create')->will($this->returnValue($eavSource));
- $eavSourceFactory->expects($this->once())
- ->method('create')
- ->will($this->returnValue($eavDecimal));
+ $this->eavSourceFactory->expects($this->once())->method('create')->will($this->returnValue($eavDecimal));
- $metadataMock = $this->createMock(\Magento\Framework\EntityManager\MetadataPool::class);
$entityMetadataMock = $this->getMockBuilder(\Magento\Framework\EntityManager\EntityMetadataInterface::class)
->getMockForAbstractClass();
- $metadataMock->expects($this->atLeastOnce())
+ $this->metadataPool->expects($this->atLeastOnce())
->method('getMetadata')
->with(\Magento\Catalog\Api\Data\ProductInterface::class)
->willReturn($entityMetadataMock);
- $batchProviderMock = $this->createMock(\Magento\Framework\Indexer\BatchProviderInterface::class);
- $batchProviderMock->expects($this->atLeastOnce())
+ $this->batchProvider->expects($this->atLeastOnce())
->method('getBatches')
->willReturn([['from' => 10, 'to' => 100]]);
- $batchProviderMock->expects($this->atLeastOnce())
+ $this->batchProvider->expects($this->atLeastOnce())
->method('getBatchIds')
->willReturn($ids);
- $batchManagementMock = $this->createMock(
- \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\BatchSizeCalculator::class
- );
$selectMock = $this->getMockBuilder(\Magento\Framework\DB\Select::class)
->disableOriginalConstructor()
->getMock();
@@ -134,19 +148,17 @@ public function testExecute()
$selectMock->expects($this->atLeastOnce())->method('distinct')->willReturnSelf();
$selectMock->expects($this->atLeastOnce())->method('from')->willReturnSelf();
- $tableSwitcherMock = $this->getMockBuilder(
- \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher::class
- )->disableOriginalConstructor()->getMock();
-
- $model = new \Magento\Catalog\Model\Indexer\Product\Eav\Action\Full(
- $eavDecimalFactory,
- $eavSourceFactory,
- $metadataMock,
- $batchProviderMock,
- $batchManagementMock,
- $tableSwitcherMock
- );
+ $this->model->execute();
+ }
- $model->execute();
+ /**
+ * @return void
+ * @throws \Magento\Framework\Exception\LocalizedException
+ */
+ public function testExecuteWithDisabledEavIndexer()
+ {
+ $this->scopeConfig->expects($this->once())->method('getValue')->willReturn(0);
+ $this->metadataPool->expects($this->never())->method('getMetadata');
+ $this->model->execute();
}
}
diff --git a/app/code/Magento/CatalogSearch/Plugin/EnableEavIndexer.php b/app/code/Magento/CatalogSearch/Plugin/EnableEavIndexer.php
new file mode 100644
index 0000000000000..c624f9d1c2e52
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/Plugin/EnableEavIndexer.php
@@ -0,0 +1,33 @@
+getData(self::SEARCH_ENGINE_VALUE_PATH);
+ if ($searchEngine === 'mysql') {
+ $data = $subject->getData();
+ $data['groups']['search']['fields']['enable_eav_indexer']['value'] = 1;
+
+ $subject->setData($data);
+ }
+ }
+}
diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Plugin/EnableEavIndexerTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Plugin/EnableEavIndexerTest.php
new file mode 100644
index 0000000000000..0eac2e3309aec
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/Test/Unit/Plugin/EnableEavIndexerTest.php
@@ -0,0 +1,68 @@
+config = $this->getMockBuilder(\Magento\Config\Model\Config::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getData', 'setData'])
+ ->getMock();
+
+ $objectManagerHelper = new ObjectManagerHelper($this);
+ $this->model = $objectManagerHelper->getObject(
+ \Magento\CatalogSearch\Plugin\EnableEavIndexer::class
+ );
+ }
+
+ /**
+ * Test with other search engine (not MySQL) selected in config
+ *
+ * @return void
+ */
+ public function testBeforeSave()
+ {
+ $this->config->expects($this->once())->method('getData')->willReturn('elasticsearch');
+ $this->config->expects($this->never())->method('setData')->willReturnSelf();
+
+ $this->model->beforeSave($this->config);
+ }
+
+ /**
+ * Test with MySQL search engine selected in config
+ *
+ * @return void
+ */
+ public function testBeforeSaveMysqlSearchEngine()
+ {
+ $this->config->expects($this->at(0))->method('getData')->willReturn('mysql');
+ $this->config->expects($this->at(1))->method('getData')->willReturn([]);
+ $this->config->expects($this->once())->method('setData')->willReturnSelf();
+
+ $this->model->beforeSave($this->config);
+ }
+}
diff --git a/app/code/Magento/CatalogSearch/composer.json b/app/code/Magento/CatalogSearch/composer.json
index 298511ef428a9..1000e349b6f9a 100644
--- a/app/code/Magento/CatalogSearch/composer.json
+++ b/app/code/Magento/CatalogSearch/composer.json
@@ -9,7 +9,7 @@
"magento/framework": "*",
"magento/module-backend": "*",
"magento/module-catalog": "*",
- "magento/module-indexer": "100.2.*",
+ "magento/module-indexer": "*",
"magento/module-catalog-inventory": "*",
"magento/module-customer": "*",
"magento/module-directory": "*",
@@ -19,6 +19,9 @@
"magento/module-theme": "*",
"magento/module-ui": "*"
},
+ "suggest": {
+ "magento/module-config": "*"
+ },
"type": "magento2-module",
"license": [
"OSL-3.0",
diff --git a/app/code/Magento/CatalogSearch/etc/adminhtml/system.xml b/app/code/Magento/CatalogSearch/etc/adminhtml/system.xml
index 18d2cdf542799..39235511eaeec 100644
--- a/app/code/Magento/CatalogSearch/etc/adminhtml/system.xml
+++ b/app/code/Magento/CatalogSearch/etc/adminhtml/system.xml
@@ -36,6 +36,14 @@
validate-digits
+
+
+ Enable/Disable Product EAV indexer to improve indexation speed. Make sure that indexer is not used by 3rd party extensions.
+
+ mysql
+
+ Magento\Config\Model\Config\Source\Yesno
+
diff --git a/app/code/Magento/CatalogSearch/etc/config.xml b/app/code/Magento/CatalogSearch/etc/config.xml
index d2b50fe9f5336..66b79226c9f34 100644
--- a/app/code/Magento/CatalogSearch/etc/config.xml
+++ b/app/code/Magento/CatalogSearch/etc/config.xml
@@ -17,6 +17,7 @@
128
100
8
+ 1
diff --git a/app/code/Magento/CatalogSearch/etc/di.xml b/app/code/Magento/CatalogSearch/etc/di.xml
index acec17f48211e..cc07384d4c525 100644
--- a/app/code/Magento/CatalogSearch/etc/di.xml
+++ b/app/code/Magento/CatalogSearch/etc/di.xml
@@ -337,4 +337,7 @@
+
+
+
diff --git a/app/code/Magento/CatalogWidget/Model/Rule/Condition/Product.php b/app/code/Magento/CatalogWidget/Model/Rule/Condition/Product.php
index f22879df0ae0c..29adc1816d337 100644
--- a/app/code/Magento/CatalogWidget/Model/Rule/Condition/Product.php
+++ b/app/code/Magento/CatalogWidget/Model/Rule/Condition/Product.php
@@ -101,6 +101,9 @@ public function loadAttributeOptions()
/**
* {@inheritdoc}
+ *
+ * @param array &$attributes
+ * @return void
*/
protected function _addSpecialAttributes(array &$attributes)
{
@@ -163,8 +166,6 @@ protected function addGlobalAttribute(
\Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute,
\Magento\Catalog\Model\ResourceModel\Product\Collection $collection
) {
- $storeId = $this->storeManager->getStore()->getId();
-
switch ($attribute->getBackendType()) {
case 'decimal':
case 'datetime':
@@ -173,10 +174,15 @@ protected function addGlobalAttribute(
$collection->addAttributeToSelect($attribute->getAttributeCode(), 'inner');
break;
default:
- $alias = 'at_' . md5($this->getId()) . $attribute->getAttributeCode();
+ $alias = 'at_' . sha1($this->getId()) . $attribute->getAttributeCode();
+
+ $connection = $this->_productResource->getConnection();
+ $storeId = $connection->getIfNullSql($alias . '.store_id', $this->storeManager->getStore()->getId());
+ $linkField = $attribute->getEntity()->getLinkField();
+
$collection->getSelect()->join(
- [$alias => $collection->getTable('catalog_product_index_eav')],
- "($alias.entity_id = e.entity_id) AND ($alias.store_id = $storeId)" .
+ [$alias => $collection->getTable('catalog_product_entity_varchar')],
+ "($alias.$linkField = e.$linkField) AND ($alias.store_id = $storeId)" .
" AND ($alias.attribute_id = {$attribute->getId()})",
[]
);
@@ -225,6 +231,8 @@ protected function addNotGlobalAttribute(
/**
* {@inheritdoc}
+ *
+ * @return string
*/
public function getMappedSqlField()
{
@@ -244,6 +252,9 @@ public function getMappedSqlField()
/**
* {@inheritdoc}
+ *
+ * @param \Magento\Catalog\Model\ResourceModel\Product\Collection $productCollection
+ * @return $this
*/
public function collectValidatedAttributes($productCollection)
{
diff --git a/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/ProductTest.php b/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/ProductTest.php
index 09270b6b41fc7..219cae6829299 100644
--- a/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/ProductTest.php
+++ b/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/ProductTest.php
@@ -17,11 +17,21 @@ class ProductTest extends \PHPUnit\Framework\TestCase
*/
private $model;
+ /**
+ * @var \Magento\Catalog\Model\ResourceModel\Product|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $productResource;
+
/**
* @var \PHPUnit_Framework_MockObject_MockObject
*/
private $attributeMock;
+ /**
+ * @inheritdoc
+ *
+ * @return void
+ */
protected function setUp()
{
$objectManagerHelper = new ObjectManager($this);
@@ -33,9 +43,9 @@ protected function setUp()
$storeManager = $this->createMock(\Magento\Store\Model\StoreManagerInterface::class);
$storeMock = $this->createMock(\Magento\Store\Api\Data\StoreInterface::class);
$storeManager->expects($this->any())->method('getStore')->willReturn($storeMock);
- $productResource = $this->createMock(\Magento\Catalog\Model\ResourceModel\Product::class);
- $productResource->expects($this->once())->method('loadAllAttributes')->willReturnSelf();
- $productResource->expects($this->once())->method('getAttributesByCode')->willReturn([]);
+ $this->productResource = $this->createMock(\Magento\Catalog\Model\ResourceModel\Product::class);
+ $this->productResource->expects($this->once())->method('loadAllAttributes')->willReturnSelf();
+ $this->productResource->expects($this->once())->method('getAttributesByCode')->willReturn([]);
$productCategoryList = $this->getMockBuilder(\Magento\Catalog\Model\ProductCategoryList::class)
->disableOriginalConstructor()
->getMock();
@@ -45,7 +55,7 @@ protected function setUp()
[
'config' => $eavConfig,
'storeManager' => $storeManager,
- 'productResource' => $productResource,
+ 'productResource' => $this->productResource,
'productCategoryList' => $productCategoryList,
'data' => [
'rule' => $ruleMock,
@@ -55,6 +65,11 @@ protected function setUp()
);
}
+ /**
+ * Test addToCollection method.
+ *
+ * @return void
+ */
public function testAddToCollection()
{
$collectionMock = $this->createMock(\Magento\Catalog\Model\ResourceModel\Product\Collection::class);
@@ -67,9 +82,22 @@ public function testAddToCollection()
$this->attributeMock->expects($this->once())->method('isScopeGlobal')->willReturn(true);
$this->attributeMock->expects($this->once())->method('isScopeGlobal')->willReturn(true);
$this->attributeMock->expects($this->once())->method('getBackendType')->willReturn('multiselect');
+
+ $entityMock = $this->createMock(\Magento\Eav\Model\Entity\AbstractEntity::class);
+ $entityMock->expects($this->once())->method('getLinkField')->willReturn('entitiy_id');
+ $this->attributeMock->expects($this->once())->method('getEntity')->willReturn($entityMock);
+ $connection = $this->createMock(\Magento\Framework\DB\Adapter\AdapterInterface::class);
+
+ $this->productResource->expects($this->atLeastOnce())->method('getConnection')->willReturn($connection);
+
$this->model->addToCollection($collectionMock);
}
+ /**
+ * Test getMappedSqlField method.
+ *
+ * @return void
+ */
public function testGetMappedSqlFieldSku()
{
$this->model->setAttribute('sku');
diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductWithFileCustomOptionTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductWithFileCustomOptionTest.xml
index e7091dbfae215..602e04b138ea3 100644
--- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductWithFileCustomOptionTest.xml
+++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductWithFileCustomOptionTest.xml
@@ -17,6 +17,7 @@
+
diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Product/View/Type/ConfigurableTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Product/View/Type/ConfigurableTest.php
index b45306d670bff..25d8412c91056 100644
--- a/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Product/View/Type/ConfigurableTest.php
+++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Product/View/Type/ConfigurableTest.php
@@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\ConfigurableProduct\Test\Unit\Block\Product\View\Type;
use Magento\Customer\Model\Session;
@@ -83,6 +84,9 @@ class ConfigurableTest extends \PHPUnit\Framework\TestCase
*/
private $variationPricesMock;
+ /**
+ * {@inheritDoc}
+ */
protected function setUp()
{
$this->mockContextObject();
@@ -174,7 +178,7 @@ protected function setUp()
*
* @return array
*/
- public function cacheKeyProvider() : array
+ public function cacheKeyProvider(): array
{
return [
'without_currency_and_customer_group' => [
@@ -313,11 +317,7 @@ public function testGetJsonConfig()
$this->localeFormat->expects($this->atLeastOnce())->method('getPriceFormat')->willReturn([]);
$this->localeFormat->expects($this->any())
->method('getNumber')
- ->willReturnMap([
- [$amount, $amount],
- [$priceQty, $priceQty],
- [$percentage, $percentage],
- ]);
+ ->willReturnArgument(0);
$this->variationPricesMock->expects($this->once())
->method('getFormattedPrices')
@@ -349,13 +349,13 @@ public function testGetJsonConfig()
/**
* Retrieve array with expected parameters for method getJsonConfig()
*
- * @param $productId
- * @param $amount
- * @param $priceQty
- * @param $percentage
+ * @param int $productId
+ * @param double $amount
+ * @param int $priceQty
+ * @param int $percentage
* @return array
*/
- private function getExpectedArray($productId, $amount, $priceQty, $percentage)
+ private function getExpectedArray($productId, $amount, $priceQty, $percentage): array
{
$expectedArray = [
'attributes' => [],
diff --git a/app/code/Magento/Customer/Controller/Address/FormPost.php b/app/code/Magento/Customer/Controller/Address/FormPost.php
index 21334f51b1752..60e1f6eb172f5 100644
--- a/app/code/Magento/Customer/Controller/Address/FormPost.php
+++ b/app/code/Magento/Customer/Controller/Address/FormPost.php
@@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\Customer\Controller\Address;
use Magento\Customer\Api\AddressRepositoryInterface;
@@ -197,17 +198,17 @@ public function execute()
try {
$address = $this->_extractAddress();
$this->_addressRepository->save($address);
- $this->messageManager->addSuccess(__('You saved the address.'));
+ $this->messageManager->addSuccessMessage(__('You saved the address.'));
$url = $this->_buildUrl('*/*/index', ['_secure' => true]);
return $this->resultRedirectFactory->create()->setUrl($this->_redirect->success($url));
} catch (InputException $e) {
- $this->messageManager->addError($e->getMessage());
+ $this->messageManager->addErrorMessage($e->getMessage());
foreach ($e->getErrors() as $error) {
- $this->messageManager->addError($error->getMessage());
+ $this->messageManager->addErrorMessage($error->getMessage());
}
} catch (\Exception $e) {
$redirectUrl = $this->_buildUrl('*/*/index');
- $this->messageManager->addException($e, __('We can\'t save the address.'));
+ $this->messageManager->addExceptionMessage($e, __('We can\'t save the address.'));
}
$url = $redirectUrl;
diff --git a/app/code/Magento/Customer/Model/Metadata/Form/Text.php b/app/code/Magento/Customer/Model/Metadata/Form/Text.php
index 9ef6df0a6d36e..c8b9a1e46a127 100644
--- a/app/code/Magento/Customer/Model/Metadata/Form/Text.php
+++ b/app/code/Magento/Customer/Model/Metadata/Form/Text.php
@@ -5,8 +5,10 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\Customer\Model\Metadata\Form;
+use Magento\Customer\Api\Data\AttributeMetadataInterface;
use Magento\Framework\Api\ArrayObjectSearch;
class Text extends AbstractData
@@ -19,7 +21,7 @@ class Text extends AbstractData
/**
* @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate
* @param \Psr\Log\LoggerInterface $logger
- * @param \Magento\Customer\Api\Data\AttributeMetadataInterface $attribute
+ * @param AttributeMetadataInterface $attribute
* @param \Magento\Framework\Locale\ResolverInterface $localeResolver
* @param string $value
* @param string $entityTypeCode
@@ -29,7 +31,7 @@ class Text extends AbstractData
public function __construct(
\Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,
\Psr\Log\LoggerInterface $logger,
- \Magento\Customer\Api\Data\AttributeMetadataInterface $attribute,
+ AttributeMetadataInterface $attribute,
\Magento\Framework\Locale\ResolverInterface $localeResolver,
$value,
$entityTypeCode,
@@ -41,7 +43,7 @@ public function __construct(
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function extractValue(\Magento\Framework\App\RequestInterface $request)
{
@@ -49,7 +51,7 @@ public function extractValue(\Magento\Framework\App\RequestInterface $request)
}
/**
- * {@inheritdoc}
+ * @inheritdoc
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
*/
@@ -72,26 +74,7 @@ public function validateValue($value)
return true;
}
- // validate length
- $length = $this->_string->strlen(trim($value));
-
- $validateRules = $attribute->getValidationRules();
-
- $minTextLength = ArrayObjectSearch::getArrayElementByName(
- $validateRules,
- 'min_text_length'
- );
- if ($minTextLength !== null && $length < $minTextLength) {
- $errors[] = __('"%1" length must be equal or greater than %2 characters.', $label, $minTextLength);
- }
-
- $maxTextLength = ArrayObjectSearch::getArrayElementByName(
- $validateRules,
- 'max_text_length'
- );
- if ($maxTextLength !== null && $length > $maxTextLength) {
- $errors[] = __('"%1" length must be equal or less than %2 characters.', $label, $maxTextLength);
- }
+ $errors = $this->validateLength($value, $attribute, $errors);
$result = $this->_validateInputRule($value);
if ($result !== true) {
@@ -105,7 +88,7 @@ public function validateValue($value)
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function compactValue($value)
{
@@ -113,7 +96,7 @@ public function compactValue($value)
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function restoreValue($value)
{
@@ -121,10 +104,48 @@ public function restoreValue($value)
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function outputValue($format = \Magento\Customer\Model\Metadata\ElementFactory::OUTPUT_FORMAT_TEXT)
{
return $this->_applyOutputFilter($this->_value);
}
+
+ /**
+ * Length validation
+ *
+ * @param mixed $value
+ * @param AttributeMetadataInterface $attribute
+ * @param array $errors
+ * @return array
+ */
+ private function validateLength($value, AttributeMetadataInterface $attribute, array $errors): array
+ {
+ // validate length
+ $label = __($attribute->getStoreLabel());
+
+ $length = $this->_string->strlen(trim($value));
+
+ $validateRules = $attribute->getValidationRules();
+
+ if (!empty(ArrayObjectSearch::getArrayElementByName($validateRules, 'input_validation'))) {
+ $minTextLength = ArrayObjectSearch::getArrayElementByName(
+ $validateRules,
+ 'min_text_length'
+ );
+ if ($minTextLength !== null && $length < $minTextLength) {
+ $errors[] = __('"%1" length must be equal or greater than %2 characters.', $label, $minTextLength);
+ }
+
+ $maxTextLength = ArrayObjectSearch::getArrayElementByName(
+ $validateRules,
+ 'max_text_length'
+ );
+ if ($maxTextLength !== null && $length > $maxTextLength) {
+ $errors[] = __('"%1" length must be equal or less than %2 characters.', $label, $maxTextLength);
+ }
+ }
+
+ return $errors;
+ }
}
diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Address/FormPostTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Address/FormPostTest.php
index 4ad1b5cbc96bd..c2a795fc95016 100644
--- a/app/code/Magento/Customer/Test/Unit/Controller/Address/FormPostTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Controller/Address/FormPostTest.php
@@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\Customer\Test\Unit\Controller\Address;
use Magento\Customer\Api\AddressRepositoryInterface;
@@ -162,6 +163,9 @@ class FormPostTest extends \PHPUnit\Framework\TestCase
*/
private $customerAddressMapper;
+ /**
+ * {@inheritDoc}
+ */
protected function setUp()
{
$this->prepareContext();
@@ -230,7 +234,10 @@ protected function setUp()
);
}
- protected function prepareContext()
+ /**
+ * Prepares context
+ */
+ protected function prepareContext(): void
{
$this->context = $this->getMockBuilder(\Magento\Framework\App\Action\Context::class)
->disableOriginalConstructor()
@@ -284,7 +291,10 @@ protected function prepareContext()
->willReturn($this->messageManager);
}
- protected function prepareAddress()
+ /**
+ * Prepare address
+ */
+ protected function prepareAddress(): void
{
$this->addressRepository = $this->getMockBuilder(\Magento\Customer\Api\AddressRepositoryInterface::class)
->getMockForAbstractClass();
@@ -303,7 +313,10 @@ protected function prepareAddress()
->willReturn($this->addressData);
}
- protected function prepareRegion()
+ /**
+ * Prepare region
+ */
+ protected function prepareRegion(): void
{
$this->region = $this->getMockBuilder(\Magento\Directory\Model\Region::class)
->disableOriginalConstructor()
@@ -335,7 +348,10 @@ protected function prepareRegion()
->willReturn($this->regionData);
}
- protected function prepareForm()
+ /**
+ * Prepare form
+ */
+ protected function prepareForm(): void
{
$this->form = $this->getMockBuilder(\Magento\Customer\Model\Metadata\Form::class)
->disableOriginalConstructor()
@@ -346,7 +362,10 @@ protected function prepareForm()
->getMock();
}
- public function testExecuteNoFormKey()
+ /**
+ * Test form without formKey
+ */
+ public function testExecuteNoFormKey(): void
{
$this->formKeyValidator->expects($this->once())
->method('validate')
@@ -361,7 +380,10 @@ public function testExecuteNoFormKey()
$this->assertEquals($this->resultRedirect, $this->model->execute());
}
- public function testExecuteNoPostData()
+ /**
+ * Test executing without post data
+ */
+ public function testExecuteNoPostData(): void
{
$postValue = 'post_value';
$url = 'url';
@@ -409,10 +431,11 @@ public function testExecuteNoPostData()
}
/**
+ * Tests executing
+ *
* @param int $addressId
* @param int $countryId
* @param int $customerId
- * @param bool $isRegionRequired
* @param int $regionId
* @param string $region
* @param string $regionCode
@@ -433,7 +456,7 @@ public function testExecute(
$newRegionId,
$newRegion,
$newRegionCode
- ) {
+ ): void {
$existingAddressData = [
'country_id' => $countryId,
'region_id' => $regionId,
@@ -517,7 +540,8 @@ public function testExecute(
->willReturnMap([
[
$this->regionData,
- $regionData, \Magento\Customer\Api\Data\RegionInterface::class,
+ $regionData,
+ \Magento\Customer\Api\Data\RegionInterface::class,
$this->dataObjectHelper,
],
[
@@ -549,7 +573,7 @@ public function testExecute(
->willReturnSelf();
$this->messageManager->expects($this->once())
- ->method('addSuccess')
+ ->method('addSuccessMessage')
->with(__('You saved the address.'))
->willReturnSelf();
@@ -581,7 +605,7 @@ public function testExecute(
/**
* @return array
*/
- public function dataProviderTestExecute()
+ public function dataProviderTestExecute(): array
{
return [
[1, 1, 1, null, '', null, '', null, ''],
@@ -612,7 +636,10 @@ public function dataProviderTestExecute()
];
}
- public function testExecuteInputException()
+ /**
+ * Tests input exception
+ */
+ public function testExecuteInputException(): void
{
$addressId = 1;
$postValue = 'post_value';
@@ -640,7 +667,7 @@ public function testExecuteInputException()
->willThrowException(new InputException(__('InputException')));
$this->messageManager->expects($this->once())
- ->method('addError')
+ ->method('addErrorMessage')
->with('InputException')
->willReturnSelf();
@@ -674,7 +701,10 @@ public function testExecuteInputException()
$this->assertEquals($this->resultRedirect, $this->model->execute());
}
- public function testExecuteException()
+ /**
+ * Tests exception
+ */
+ public function testExecuteException(): void
{
$addressId = 1;
$postValue = 'post_value';
@@ -703,7 +733,7 @@ public function testExecuteException()
->willThrowException($exception);
$this->messageManager->expects($this->once())
- ->method('addException')
+ ->method('addExceptionMessage')
->with($exception, __('We can\'t save the address.'))
->willReturnSelf();
diff --git a/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/TextTest.php b/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/TextTest.php
index b95987cba1dcf..7987bdc79ed98 100644
--- a/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/TextTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/TextTest.php
@@ -5,8 +5,10 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\Customer\Test\Unit\Model\Metadata\Form;
+use Magento\Customer\Api\Data\ValidationRuleInterface;
use Magento\Customer\Model\Metadata\Form\Text;
class TextTest extends AbstractFormTestCase
@@ -14,6 +16,9 @@ class TextTest extends AbstractFormTestCase
/** @var \Magento\Framework\Stdlib\StringUtils */
protected $stringHelper;
+ /**
+ * {@inheritDoc}
+ */
protected function setUp()
{
parent::setUp();
@@ -111,7 +116,7 @@ public function validateValueRequiredDataProvider()
*/
public function testValidateValueLength($value, $expected)
{
- $minTextLengthRule = $this->getMockBuilder(\Magento\Customer\Api\Data\ValidationRuleInterface::class)
+ $minTextLengthRule = $this->getMockBuilder(ValidationRuleInterface::class)
->disableOriginalConstructor()
->setMethods(['getName', 'getValue'])
->getMockForAbstractClass();
@@ -122,7 +127,7 @@ public function testValidateValueLength($value, $expected)
->method('getValue')
->will($this->returnValue(4));
- $maxTextLengthRule = $this->getMockBuilder(\Magento\Customer\Api\Data\ValidationRuleInterface::class)
+ $maxTextLengthRule = $this->getMockBuilder(ValidationRuleInterface::class)
->disableOriginalConstructor()
->setMethods(['getName', 'getValue'])
->getMockForAbstractClass();
@@ -133,7 +138,19 @@ public function testValidateValueLength($value, $expected)
->method('getValue')
->will($this->returnValue(8));
+ $inputValidationRule = $this->getMockBuilder(ValidationRuleInterface::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getName', 'getValue'])
+ ->getMockForAbstractClass();
+ $inputValidationRule->expects($this->any())
+ ->method('getName')
+ ->will($this->returnValue('input_validation'));
+ $inputValidationRule->expects($this->any())
+ ->method('getValue')
+ ->will($this->returnValue('other'));
+
$validationRules = [
+ 'input_validation' => $inputValidationRule,
'min_text_length' => $minTextLengthRule,
'max_text_length' => $maxTextLengthRule,
];
diff --git a/app/code/Magento/Eav/Model/Attribute/Data/Text.php b/app/code/Magento/Eav/Model/Attribute/Data/Text.php
index 242f4e98108c9..f81fb2affd3b3 100644
--- a/app/code/Magento/Eav/Model/Attribute/Data/Text.php
+++ b/app/code/Magento/Eav/Model/Attribute/Data/Text.php
@@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\Eav\Model\Attribute\Data;
use Magento\Framework\App\RequestInterface;
@@ -76,19 +77,9 @@ public function validateValue($value)
return true;
}
- // validate length
- $length = $this->_string->strlen(trim($value));
-
- $validateRules = $attribute->getValidateRules();
- if (!empty($validateRules['min_text_length']) && $length < $validateRules['min_text_length']) {
- $label = __($attribute->getStoreLabel());
- $v = $validateRules['min_text_length'];
- $errors[] = __('"%1" length must be equal or greater than %2 characters.', $label, $v);
- }
- if (!empty($validateRules['max_text_length']) && $length > $validateRules['max_text_length']) {
- $label = __($attribute->getStoreLabel());
- $v = $validateRules['max_text_length'];
- $errors[] = __('"%1" length must be equal or less than %2 characters.', $label, $v);
+ $result = $this->validateLength($attribute, $value);
+ if (count($result) !== 0) {
+ $errors = array_merge($errors, $result);
}
$result = $this->_validateInputRule($value);
@@ -142,4 +133,33 @@ public function outputValue($format = \Magento\Eav\Model\AttributeDataFactory::O
return $value;
}
+
+ /**
+ * Validates value length by attribute rules
+ *
+ * @param \Magento\Eav\Model\Attribute $attribute
+ * @param string $value
+ * @return array errors
+ */
+ private function validateLength(\Magento\Eav\Model\Attribute $attribute, $value): array
+ {
+ $errors = [];
+ $length = $this->_string->strlen(trim($value));
+ $validateRules = $attribute->getValidateRules();
+
+ if (!empty($validateRules['input_validation'])) {
+ if (!empty($validateRules['min_text_length']) && $length < $validateRules['min_text_length']) {
+ $label = __($attribute->getStoreLabel());
+ $v = $validateRules['min_text_length'];
+ $errors[] = __('"%1" length must be equal or greater than %2 characters.', $label, $v);
+ }
+ if (!empty($validateRules['max_text_length']) && $length > $validateRules['max_text_length']) {
+ $label = __($attribute->getStoreLabel());
+ $v = $validateRules['max_text_length'];
+ $errors[] = __('"%1" length must be equal or less than %2 characters.', $label, $v);
+ }
+ }
+
+ return $errors;
+ }
}
diff --git a/app/code/Magento/Eav/Test/Unit/Model/Attribute/Data/MultilineTest.php b/app/code/Magento/Eav/Test/Unit/Model/Attribute/Data/MultilineTest.php
index f628d52f6647f..bde4a3adb9de5 100644
--- a/app/code/Magento/Eav/Test/Unit/Model/Attribute/Data/MultilineTest.php
+++ b/app/code/Magento/Eav/Test/Unit/Model/Attribute/Data/MultilineTest.php
@@ -3,8 +3,12 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\Eav\Test\Unit\Model\Attribute\Data;
+use Magento\Framework\Locale\ResolverInterface;
+use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
+
class MultilineTest extends \PHPUnit\Framework\TestCase
{
/**
@@ -13,15 +17,21 @@ class MultilineTest extends \PHPUnit\Framework\TestCase
protected $model;
/**
- * @var \PHPUnit_Framework_MockObject_MockObject
+ * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Stdlib\StringUtils
*/
protected $stringMock;
+ /**
+ * {@inheritDoc}
+ */
protected function setUp()
{
- $timezoneMock = $this->createMock(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::class);
+ /** @var TimezoneInterface $timezoneMock */
+ $timezoneMock = $this->createMock(TimezoneInterface::class);
+ /** @var \Psr\Log\LoggerInterface $loggerMock */
$loggerMock = $this->createMock(\Psr\Log\LoggerInterface::class);
- $localeResolverMock = $this->createMock(\Magento\Framework\Locale\ResolverInterface::class);
+ /** @var ResolverInterface $localeResolverMock */
+ $localeResolverMock = $this->createMock(ResolverInterface::class);
$this->stringMock = $this->createMock(\Magento\Framework\Stdlib\StringUtils::class);
$this->model = new \Magento\Eav\Model\Attribute\Data\Multiline(
@@ -33,7 +43,7 @@ protected function setUp()
}
/**
- * @covers \Magento\Eav\Model\Attribute\Data\Multiline::extractValue
+ * @covers \Magento\Eav\Model\Attribute\Data\Multiline::extractValue
*
* @param mixed $param
* @param mixed $expectedResult
@@ -41,11 +51,15 @@ protected function setUp()
*/
public function testExtractValue($param, $expectedResult)
{
+ /** @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\App\RequestInterface $requestMock */
$requestMock = $this->createMock(\Magento\Framework\App\RequestInterface::class);
+ /** @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Eav\Model\Attribute $attributeMock */
$attributeMock = $this->createMock(\Magento\Eav\Model\Attribute::class);
$requestMock->expects($this->once())->method('getParam')->will($this->returnValue($param));
- $attributeMock->expects($this->once())->method('getAttributeCode')->will($this->returnValue('attributeCode'));
+ $attributeMock->expects($this->once())
+ ->method('getAttributeCode')
+ ->will($this->returnValue('attributeCode'));
$this->model->setAttribute($attributeMock);
$this->assertEquals($expectedResult, $this->model->extractValue($requestMock));
@@ -69,7 +83,7 @@ public function extractValueDataProvider()
}
/**
- * @covers \Magento\Eav\Model\Attribute\Data\Multiline::outputValue
+ * @covers \Magento\Eav\Model\Attribute\Data\Multiline::outputValue
*
* @param string $format
* @param mixed $expectedResult
@@ -77,9 +91,13 @@ public function extractValueDataProvider()
*/
public function testOutputValue($format, $expectedResult)
{
+ /** @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Model\AbstractModel $entityMock */
$entityMock = $this->createMock(\Magento\Framework\Model\AbstractModel::class);
- $entityMock->expects($this->once())->method('getData')->will($this->returnValue("value1\nvalue2"));
+ $entityMock->expects($this->once())
+ ->method('getData')
+ ->will($this->returnValue("value1\nvalue2"));
+ /** @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Eav\Model\Attribute $attributeMock */
$attributeMock = $this->createMock(\Magento\Eav\Model\Attribute::class);
$this->model->setEntity($entityMock);
@@ -113,8 +131,8 @@ public function outputValueDataProvider()
}
/**
- * @covers \Magento\Eav\Model\Attribute\Data\Multiline::validateValue
- * @covers \Magento\Eav\Model\Attribute\Data\Text::validateValue
+ * @covers \Magento\Eav\Model\Attribute\Data\Multiline::validateValue
+ * @covers \Magento\Eav\Model\Attribute\Data\Text::validateValue
*
* @param mixed $value
* @param bool $isAttributeRequired
@@ -124,14 +142,23 @@ public function outputValueDataProvider()
*/
public function testValidateValue($value, $isAttributeRequired, $rules, $expectedResult)
{
+ /** @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Model\AbstractModel $entityMock */
$entityMock = $this->createMock(\Magento\Framework\Model\AbstractModel::class);
- $entityMock->expects($this->any())->method('getDataUsingMethod')->will($this->returnValue("value1\nvalue2"));
+ $entityMock->expects($this->any())
+ ->method('getDataUsingMethod')
+ ->will($this->returnValue("value1\nvalue2"));
+ /** @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Eav\Model\Attribute $attributeMock */
$attributeMock = $this->createMock(\Magento\Eav\Model\Attribute::class);
$attributeMock->expects($this->any())->method('getMultilineCount')->will($this->returnValue(2));
$attributeMock->expects($this->any())->method('getValidateRules')->will($this->returnValue($rules));
- $attributeMock->expects($this->any())->method('getStoreLabel')->will($this->returnValue('Label'));
- $attributeMock->expects($this->any())->method('getIsRequired')->will($this->returnValue($isAttributeRequired));
+ $attributeMock->expects($this->any())
+ ->method('getStoreLabel')
+ ->will($this->returnValue('Label'));
+
+ $attributeMock->expects($this->any())
+ ->method('getIsRequired')
+ ->will($this->returnValue($isAttributeRequired));
$this->stringMock->expects($this->any())->method('strlen')->will($this->returnValue(5));
@@ -159,7 +186,7 @@ public function validateValueDataProvider()
'expectedResult' => true,
],
[
- 'value' => ['value1', 'value2'],
+ 'value' => ['value1', 'value2'],
'isAttributeRequired' => false,
'rules' => [],
'expectedResult' => true,
@@ -167,13 +194,13 @@ public function validateValueDataProvider()
[
'value' => 'value',
'isAttributeRequired' => false,
- 'rules' => ['max_text_length' => 3],
+ 'rules' => ['input_validation' => 'other', 'max_text_length' => 3],
'expectedResult' => ['"Label" length must be equal or less than 3 characters.'],
],
[
'value' => 'value',
'isAttributeRequired' => false,
- 'rules' => ['min_text_length' => 10],
+ 'rules' => ['input_validation' => 'other', 'min_text_length' => 10],
'expectedResult' => ['"Label" length must be equal or greater than 10 characters.'],
],
[
diff --git a/app/code/Magento/Eav/Test/Unit/Model/Attribute/Data/TextTest.php b/app/code/Magento/Eav/Test/Unit/Model/Attribute/Data/TextTest.php
index 36eac0bfab27b..bbbe712b2bb42 100644
--- a/app/code/Magento/Eav/Test/Unit/Model/Attribute/Data/TextTest.php
+++ b/app/code/Magento/Eav/Test/Unit/Model/Attribute/Data/TextTest.php
@@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\Eav\Test\Unit\Model\Attribute\Data;
class TextTest extends \PHPUnit\Framework\TestCase
@@ -12,6 +13,9 @@ class TextTest extends \PHPUnit\Framework\TestCase
*/
protected $_model;
+ /**
+ * {@inheritDoc}
+ */
protected function setUp()
{
$locale = $this->createMock(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::class);
@@ -19,14 +23,77 @@ protected function setUp()
$logger = $this->createMock(\Psr\Log\LoggerInterface::class);
$helper = $this->createMock(\Magento\Framework\Stdlib\StringUtils::class);
- $attributeData = [
+ $this->_model = new \Magento\Eav\Model\Attribute\Data\Text($locale, $logger, $localeResolver, $helper);
+ $this->_model->setAttribute(
+ $this->createAttribute(
+ [
+ 'store_label' => 'Test',
+ 'attribute_code' => 'test',
+ 'is_required' => 1,
+ 'validate_rules' => ['min_text_length' => 0, 'max_text_length' => 0, 'input_validation' => 0],
+ ]
+ )
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function tearDown()
+ {
+ $this->_model = null;
+ }
+
+ /**
+ * Test for string validation
+ */
+ public function testValidateValueString(): void
+ {
+ $inputValue = '0';
+ $expectedResult = true;
+ $this->assertEquals($expectedResult, $this->_model->validateValue($inputValue));
+ }
+
+ /**
+ * Test for integer validation
+ */
+ public function testValidateValueInteger(): void
+ {
+ $inputValue = 0;
+ $expectedResult = ['"Test" is a required value.'];
+ $result = $this->_model->validateValue($inputValue);
+ $this->assertEquals($expectedResult, [(string)$result[0]]);
+ }
+
+ /**
+ * Test without length validation
+ */
+ public function testWithoutLengthValidation(): void
+ {
+ $expectedResult = true;
+ $defaultAttributeData = [
'store_label' => 'Test',
'attribute_code' => 'test',
'is_required' => 1,
'validate_rules' => ['min_text_length' => 0, 'max_text_length' => 0, 'input_validation' => 0],
];
- $attributeClass = \Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class;
+ $defaultAttributeData['validate_rules']['min_text_length'] = 2;
+ $this->_model->setAttribute($this->createAttribute($defaultAttributeData));
+ $this->assertEquals($expectedResult, $this->_model->validateValue('t'));
+
+ $defaultAttributeData['validate_rules']['max_text_length'] = 3;
+ $this->_model->setAttribute($this->createAttribute($defaultAttributeData));
+ $this->assertEquals($expectedResult, $this->_model->validateValue('test'));
+ }
+
+ /**
+ * @param array $attributeData
+ * @return \Magento\Eav\Model\Attribute
+ */
+ protected function createAttribute($attributeData): \Magento\Eav\Model\Entity\Attribute\AbstractAttribute
+ {
+ $attributeClass = \Magento\Eav\Model\Attribute::class;
$objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
$eavTypeFactory = $this->createMock(\Magento\Eav\Model\Entity\TypeFactory::class);
$arguments = $objectManagerHelper->getConstructArguments(
@@ -41,27 +108,6 @@ protected function setUp()
->setMethods(['_init'])
->setConstructorArgs($arguments)
->getMock();
- $this->_model = new \Magento\Eav\Model\Attribute\Data\Text($locale, $logger, $localeResolver, $helper);
- $this->_model->setAttribute($attribute);
- }
-
- protected function tearDown()
- {
- $this->_model = null;
- }
-
- public function testValidateValueString()
- {
- $inputValue = '0';
- $expectedResult = true;
- $this->assertEquals($expectedResult, $this->_model->validateValue($inputValue));
- }
-
- public function testValidateValueInteger()
- {
- $inputValue = 0;
- $expectedResult = ['"Test" is a required value.'];
- $result = $this->_model->validateValue($inputValue);
- $this->assertEquals($expectedResult, [(string)$result[0]]);
+ return $attribute;
}
}
diff --git a/app/code/Magento/ProductVideo/Block/Product/View/Gallery.php b/app/code/Magento/ProductVideo/Block/Product/View/Gallery.php
index 2277aa980f66c..45c4925640a0c 100644
--- a/app/code/Magento/ProductVideo/Block/Product/View/Gallery.php
+++ b/app/code/Magento/ProductVideo/Block/Product/View/Gallery.php
@@ -9,9 +9,8 @@
*
* @author Magento Core Team
*/
-namespace Magento\ProductVideo\Block\Product\View;
-use Magento\Catalog\Model\Product\Image\UrlBuilder;
+namespace Magento\ProductVideo\Block\Product\View;
/**
* @api
@@ -93,6 +92,6 @@ public function getVideoSettingsJson()
*/
public function getOptionsMediaGalleryDataJson()
{
- return $this->jsonEncoder->encode([]);
+ return $this->jsonEncoder->encode([]);
}
}
diff --git a/app/code/Magento/ProductVideo/Model/Plugin/Catalog/Product/Gallery/CreateHandler.php b/app/code/Magento/ProductVideo/Model/Plugin/Catalog/Product/Gallery/CreateHandler.php
index ab3c8f3c5269a..ce1493b349a85 100644
--- a/app/code/Magento/ProductVideo/Model/Plugin/Catalog/Product/Gallery/CreateHandler.php
+++ b/app/code/Magento/ProductVideo/Model/Plugin/Catalog/Product/Gallery/CreateHandler.php
@@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\ProductVideo\Model\Plugin\Catalog\Product\Gallery;
use Magento\ProductVideo\Model\Product\Attribute\Media\ExternalVideoEntryConverter;
@@ -29,6 +30,7 @@ public function beforeExecute(
\Magento\Catalog\Model\Product $product,
array $arguments = []
) {
+ /** @var \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute */
$attribute = $mediaGalleryCreateHandler->getAttribute();
$mediaCollection = $this->getMediaEntriesDataCollection($product, $attribute);
if (!empty($mediaCollection)) {
@@ -36,7 +38,7 @@ public function beforeExecute(
$mediaCollection = $this->addAdditionalStoreData($mediaCollection, $storeDataCollection);
$product->setData(
$attribute->getAttributeCode(),
- $mediaCollection + $product->getData($attribute->getAttributeCode())
+ $mediaCollection
);
}
}
@@ -56,6 +58,9 @@ public function afterExecute(
);
if (!empty($mediaCollection)) {
+ $newVideoCollection = $this->collectNewVideos($mediaCollection);
+ $this->saveVideoData($newVideoCollection, 0);
+
$videoDataCollection = $this->collectVideoData($mediaCollection);
$this->saveVideoData($videoDataCollection, $product->getStoreId());
$this->saveAdditionalStoreData($videoDataCollection);
@@ -167,10 +172,7 @@ protected function collectVideoData(array $mediaCollection)
{
$videoDataCollection = [];
foreach ($mediaCollection as $item) {
- if (!empty($item['media_type'])
- && empty($item['removed'])
- && $item['media_type'] == ExternalVideoEntryConverter::MEDIA_TYPE_CODE
- ) {
+ if ($this->isVideoItem($item)) {
$videoData = $this->extractVideoDataFromRowData($item);
$videoDataCollection[] = $videoData;
}
@@ -199,11 +201,7 @@ protected function collectVideoEntriesIdsToAdditionalLoad(array $mediaCollection
{
$ids = [];
foreach ($mediaCollection as $item) {
- if (!empty($item['media_type'])
- && empty($item['removed'])
- && $item['media_type'] == ExternalVideoEntryConverter::MEDIA_TYPE_CODE
- && isset($item['save_data_from'])
- ) {
+ if ($this->isVideoItem($item) && isset($item['save_data_from'])) {
$ids[] = $item['save_data_from'];
}
}
@@ -215,18 +213,19 @@ protected function collectVideoEntriesIdsToAdditionalLoad(array $mediaCollection
* @param array $data
* @return array
*/
- protected function addAdditionalStoreData(array $mediaCollection, array $data)
+ protected function addAdditionalStoreData(array $mediaCollection, array $data): array
{
- foreach ($mediaCollection as &$mediaItem) {
+ $return = [];
+ foreach ($mediaCollection as $key => $mediaItem) {
if (!empty($mediaItem['save_data_from'])) {
$additionalData = $this->createAdditionalStoreDataCollection($data, $mediaItem['save_data_from']);
if (!empty($additionalData)) {
$mediaItem[self::ADDITIONAL_STORE_DATA_KEY] = $additionalData;
}
}
+ $return[$key] = $mediaItem;
}
-
- return ['images' => $mediaCollection];
+ return ['images' => $return];
}
/**
@@ -234,7 +233,7 @@ protected function addAdditionalStoreData(array $mediaCollection, array $data)
* @param int $valueId
* @return array
*/
- protected function createAdditionalStoreDataCollection(array $storeData, $valueId)
+ protected function createAdditionalStoreDataCollection(array $storeData, $valueId): array
{
$result = [];
foreach ($storeData as $item) {
@@ -246,4 +245,41 @@ protected function createAdditionalStoreDataCollection(array $storeData, $valueI
return $result;
}
+
+ /**
+ * @param array $mediaCollection
+ * @return array
+ */
+ private function collectNewVideos(array $mediaCollection): array
+ {
+ $return = [];
+ foreach ($mediaCollection as $item) {
+ if ($this->isVideoItem($item) && $this->isNewVideo($item)) {
+ $return[] = $this->extractVideoDataFromRowData($item);
+ }
+ }
+ return $return;
+ }
+
+ /**
+ * @param array $item
+ * @return bool
+ */
+ private function isVideoItem(array $item): bool
+ {
+ return !empty($item['media_type'])
+ && empty($item['removed'])
+ && $item['media_type'] == ExternalVideoEntryConverter::MEDIA_TYPE_CODE;
+ }
+
+ /**
+ * @param array $item
+ * @return bool
+ */
+ private function isNewVideo(array $item): bool
+ {
+ return !isset($item['video_url_default'], $item['video_title_default'])
+ || empty($item['video_url_default'])
+ || empty($item['video_title_default']);
+ }
}
diff --git a/app/code/Magento/ProductVideo/Model/Plugin/Catalog/Product/Gallery/ReadHandler.php b/app/code/Magento/ProductVideo/Model/Plugin/Catalog/Product/Gallery/ReadHandler.php
index 6c534580c39d9..31d63efcf8cb0 100644
--- a/app/code/Magento/ProductVideo/Model/Plugin/Catalog/Product/Gallery/ReadHandler.php
+++ b/app/code/Magento/ProductVideo/Model/Plugin/Catalog/Product/Gallery/ReadHandler.php
@@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\ProductVideo\Model\Plugin\Catalog\Product\Gallery;
use Magento\ProductVideo\Model\Product\Attribute\Media\ExternalVideoEntryConverter;
@@ -55,8 +56,8 @@ protected function collectVideoEntriesIds(array $mediaCollection)
{
$ids = [];
foreach ($mediaCollection as $item) {
- if ($item['media_type'] == ExternalVideoEntryConverter::MEDIA_TYPE_CODE
- && !array_key_exists('video_url', $item)
+ if ($item['media_type'] === ExternalVideoEntryConverter::MEDIA_TYPE_CODE
+ && !isset($item['video_url'])
) {
$ids[] = $item['value_id'];
}
@@ -72,7 +73,7 @@ protected function collectVideoEntriesIds(array $mediaCollection)
protected function loadVideoDataById(array $ids, $storeId = null)
{
$mainTableAlias = $this->resourceModel->getMainTableAlias();
- $joinConditions = $mainTableAlias.'.value_id = store_value.value_id';
+ $joinConditions = $mainTableAlias . '.value_id = store_value.value_id';
if (null !== $storeId) {
$joinConditions = implode(
' AND ',
@@ -138,10 +139,10 @@ protected function addVideoDataToMediaEntries(array $mediaCollection, array $dat
protected function substituteNullsWithDefaultValues(array $rowData)
{
foreach ($this->getVideoProperties(false) as $key) {
- if (empty($rowData[$key]) && !empty($rowData[$key.'_default'])) {
- $rowData[$key] = $rowData[$key.'_default'];
+ if (empty($rowData[$key]) && !empty($rowData[$key . '_default'])) {
+ $rowData[$key] = $rowData[$key . '_default'];
}
- unset($rowData[$key.'_default']);
+ unset($rowData[$key . '_default']);
}
return $rowData;
@@ -154,8 +155,7 @@ protected function substituteNullsWithDefaultValues(array $rowData)
protected function getVideoProperties($withDbMapping = true)
{
$properties = $this->videoPropertiesDbMapping;
- unset($properties['value_id']);
- unset($properties['store_id']);
+ unset($properties['value_id'], $properties['store_id']);
return $withDbMapping ? $properties : array_keys($properties);
}
diff --git a/app/code/Magento/ProductVideo/Test/Unit/Model/Plugin/Catalog/Product/Gallery/CreateHandlerTest.php b/app/code/Magento/ProductVideo/Test/Unit/Model/Plugin/Catalog/Product/Gallery/CreateHandlerTest.php
index 5770ea8b5689d..57ad71997dad7 100644
--- a/app/code/Magento/ProductVideo/Test/Unit/Model/Plugin/Catalog/Product/Gallery/CreateHandlerTest.php
+++ b/app/code/Magento/ProductVideo/Test/Unit/Model/Plugin/Catalog/Product/Gallery/CreateHandlerTest.php
@@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\ProductVideo\Test\Unit\Model\Plugin\Catalog\Product\Gallery;
/**
@@ -37,6 +38,9 @@ class CreateHandlerTest extends \PHPUnit\Framework\TestCase
*/
protected $mediaGalleryCreateHandler;
+ /**
+ * {@inheritDoc}
+ */
protected function setUp()
{
$this->product = $this->createMock(\Magento\Catalog\Model\Product::class);
@@ -62,72 +66,18 @@ protected function setUp()
);
}
- public function testAfterExecute()
+ /**
+ * @dataProvider provideImageForAfterExecute
+ * @param array $image
+ * @param array $expectedSave
+ * @param int $rowSaved
+ */
+ public function testAfterExecute($image, $expectedSave, $rowSaved): void
{
- $mediaData = [
- 'images' => [
- '72mljfhmasfilp9cuq' => [
- 'position' => '3',
- 'media_type' => 'external-video',
- 'file' => '/i/n/index111111.jpg',
- 'value_id' => '4',
- 'label' => '',
- 'disabled' => '0',
- 'removed' => '',
- 'video_provider' => 'youtube',
- 'video_url' => 'https://www.youtube.com/watch?v=ab123456',
- 'video_title' => 'Some second title',
- 'video_description' => 'Description second',
- 'video_metadata' => 'meta two',
- 'role' => '',
- ],
- 'w596fi79hv1p6wj21u' => [
- 'position' => '4',
- 'media_type' => 'image',
- 'video_provider' => '',
- 'file' => '/h/d/hd_image.jpg',
- 'value_id' => '7',
- 'label' => '',
- 'disabled' => '0',
- 'removed' => '',
- 'video_url' => '',
- 'video_title' => '',
- 'video_description' => '',
- 'video_metadata' => '',
- 'role' => '',
- ],
- 'tcodwd7e0dirifr64j' => [
- 'position' => '4',
- 'media_type' => 'external-video',
- 'file' => '/s/a/sample_3.jpg',
- 'value_id' => '5',
- 'label' => '',
- 'disabled' => '0',
- 'removed' => '',
- 'video_provider' => 'youtube',
- 'video_url' => 'https://www.youtube.com/watch?v=ab123456',
- 'video_title' => 'Some second title',
- 'video_description' => 'Description second',
- 'video_metadata' => 'meta two',
- 'role' => '',
- 'additional_store_data' => [
- 0 => [
- 'store_id' => '0',
- 'video_provider' => null,
- 'video_url' => 'https://www.youtube.com/watch?v=ab123456',
- 'video_title' => 'New Title',
- 'video_description' => 'New Description',
- 'video_metadata' => 'New metadata',
- ],
- ]
- ],
- ],
- ];
-
$this->product->expects($this->once())
->method('getData')
->with('media_gallery')
- ->willReturn($mediaData);
+ ->willReturn(['images' => $image]);
$this->product->expects($this->once())
->method('getStoreId')
->willReturn(0);
@@ -136,13 +86,150 @@ public function testAfterExecute()
->method('getAttribute')
->willReturn($this->attribute);
- $this->subject->afterExecute(
- $this->mediaGalleryCreateHandler,
- $this->product
- );
+ $this->resourceModel->expects($this->exactly($rowSaved))
+ ->method('saveDataRow')
+ ->with('catalog_product_entity_media_gallery_value_video', $expectedSave)
+ ->willReturn(1);
+
+ $this->subject->afterExecute($this->mediaGalleryCreateHandler, $this->product);
+ }
+
+ /**
+ * DataProvider for testAfterExecute
+ *
+ * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+ * @return array
+ */
+ public function provideImageForAfterExecute(): array
+ {
+ return [
+ 'new_video' => [
+ [
+ '72mljfhmasfilp9cuq' => [
+ 'position' => '3',
+ 'media_type' => 'external-video',
+ 'file' => '/i/n/index111111.jpg',
+ 'value_id' => '4',
+ 'label' => '',
+ 'disabled' => '0',
+ 'removed' => '',
+ 'video_provider' => 'youtube',
+ 'video_url' => 'https://www.youtube.com/watch?v=ab123456',
+ 'video_title' => 'Some second title',
+ 'video_description' => 'Description second',
+ 'video_metadata' => 'meta two',
+ 'role' => '',
+ ],
+ ],
+ [
+ 'value_id' => '4',
+ 'store_id' => 0,
+ 'provider' => 'youtube',
+ 'url' => 'https://www.youtube.com/watch?v=ab123456',
+ 'title' => 'Some second title',
+ 'description' => 'Description second',
+ 'metadata' => 'meta two',
+ ],
+ 2
+ ],
+ 'image' => [
+ [
+ 'w596fi79hv1p6wj21u' => [
+ 'position' => '4',
+ 'media_type' => 'image',
+ 'video_provider' => '',
+ 'file' => '/h/d/hd_image.jpg',
+ 'value_id' => '7',
+ 'label' => '',
+ 'disabled' => '0',
+ 'removed' => '',
+ 'video_url' => '',
+ 'video_title' => '',
+ 'video_description' => '',
+ 'video_metadata' => '',
+ 'role' => '',
+ ],
+ ],
+ [],
+ 0
+ ],
+ 'new_video_with_additional_data' => [
+ [
+ 'tcodwd7e0dirifr64j' => [
+ 'position' => '4',
+ 'media_type' => 'external-video',
+ 'file' => '/s/a/sample_3.jpg',
+ 'value_id' => '5',
+ 'label' => '',
+ 'disabled' => '0',
+ 'removed' => '',
+ 'video_provider' => 'youtube',
+ 'video_url' => 'https://www.youtube.com/watch?v=ab123456',
+ 'video_title' => 'Some second title',
+ 'video_description' => 'Description second',
+ 'video_metadata' => 'meta two',
+ 'role' => '',
+ 'additional_store_data' => [
+ 0 => [
+ 'store_id' => 0,
+ 'video_provider' => 'youtube',
+ 'video_url' => 'https://www.youtube.com/watch?v=ab123456',
+ 'video_title' => 'Some second title',
+ 'video_description' => 'Description second',
+ 'video_metadata' => 'meta two',
+ ],
+ ]
+ ],
+ ],
+ [
+ 'value_id' => '5',
+ 'store_id' => 0,
+ 'provider' => 'youtube',
+ 'url' => 'https://www.youtube.com/watch?v=ab123456',
+ 'title' => 'Some second title',
+ 'description' => 'Description second',
+ 'metadata' => 'meta two',
+ ],
+ 3
+ ],
+ 'not_new_video' => [
+ [
+ '72mljfhmasfilp9cuq' => [
+ 'position' => '3',
+ 'media_type' => 'external-video',
+ 'file' => '/i/n/index111111.jpg',
+ 'value_id' => '4',
+ 'label' => '',
+ 'disabled' => '0',
+ 'removed' => '',
+ 'video_provider' => 'youtube',
+ 'video_url' => 'https://www.youtube.com/watch?v=ab123456',
+ 'video_url_default' => 'https://www.youtube.com/watch?v=ab123456',
+ 'video_title' => 'Some second title',
+ 'video_title_default' => 'Some second title',
+ 'video_description' => 'Description second',
+ 'video_metadata' => 'meta two',
+ 'role' => '',
+ ],
+ ],
+ [
+ 'value_id' => '4',
+ 'store_id' => 0,
+ 'provider' => 'youtube',
+ 'url' => 'https://www.youtube.com/watch?v=ab123456',
+ 'title' => 'Some second title',
+ 'description' => 'Description second',
+ 'metadata' => 'meta two',
+ ],
+ 1
+ ],
+ ];
}
- public function testAfterExecuteEmpty()
+ /**
+ * Tests empty media gallery
+ */
+ public function testAfterExecuteEmpty(): void
{
$this->product->expects($this->once())
->method('getData')
@@ -162,7 +249,7 @@ public function testAfterExecuteEmpty()
/**
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
- public function testBeforeExecute()
+ public function testBeforeExecute(): void
{
$mediaData = [
'images' => [
diff --git a/app/code/Magento/Rule/Model/Condition/AbstractCondition.php b/app/code/Magento/Rule/Model/Condition/AbstractCondition.php
index e3bec2d9959b1..a1987f67e47f2 100644
--- a/app/code/Magento/Rule/Model/Condition/AbstractCondition.php
+++ b/app/code/Magento/Rule/Model/Condition/AbstractCondition.php
@@ -355,10 +355,10 @@ public function getValueParsed()
{
if (!$this->hasValueParsed()) {
$value = $this->getData('value');
- if (is_array($value) && isset($value[0]) && is_string($value[0])) {
- $value = $value[0];
+ if (is_array($value) && count($value) === 1) {
+ $value = reset($value);
}
- if ($this->isArrayOperatorType() && $value) {
+ if (!is_array($value) && $this->isArrayOperatorType() && $value) {
$value = preg_split('#\s*[,;]\s*#', $value, null, PREG_SPLIT_NO_EMPTY);
}
$this->setValueParsed($value);
@@ -380,7 +380,7 @@ public function isArrayOperatorType()
}
/**
- * @return array
+ * @return mixed
*/
public function getValue()
{
diff --git a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php
index e1c9bf99f2675..2894de0f19b87 100644
--- a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php
+++ b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php
@@ -163,8 +163,22 @@ protected function _getMappedSqlCondition(
$this->_conditionOperatorMap[$conditionOperator]
);
+ $bindValue = $condition->getBindArgumentValue();
+ $expression = $value . $this->_connection->quoteInto($sql, $bindValue);
+
+ // values for multiselect attributes can be saved in comma-separated format
+ // below is a solution for matching such conditions with selected values
+ if (is_array($bindValue) && \in_array($conditionOperator, ['()', '{}'], true)) {
+ foreach ($bindValue as $item) {
+ $expression .= $this->_connection->quoteInto(
+ " OR (FIND_IN_SET (?, {$this->_connection->quoteIdentifier($argument)}) > 0)",
+ $item
+ );
+ }
+ }
+
return $this->_expressionFactory->create(
- ['expression' => $value . $this->_connection->quoteInto($sql, $condition->getBindArgumentValue())]
+ ['expression' => $expression]
);
}
@@ -174,6 +188,7 @@ protected function _getMappedSqlCondition(
* @param bool $isDefaultStoreUsed
* @return string
* @SuppressWarnings(PHPMD.NPathComplexity)
+ * @throws \Magento\Framework\Exception\LocalizedException
*/
protected function _getMappedSqlCombination(
Combine $combine,
diff --git a/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php b/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php
index 499e35db9dfd6..d2e7cabe473f4 100644
--- a/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php
+++ b/app/code/Magento/SalesRule/Model/Rule/Condition/Product.php
@@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\SalesRule\Model\Rule\Condition;
/**
@@ -51,10 +52,17 @@ public function validate(\Magento\Framework\Model\AbstractModel $model)
$attrCode = $this->getAttribute();
- if ('category_ids' == $attrCode) {
+ if ($attrCode === 'category_ids') {
return $this->validateAttribute($this->_getAvailableInCategories($product->getId()));
}
+ if ($attrCode === 'quote_item_price') {
+ $numericOperations = $this->getDefaultOperatorInputByType()['numeric'];
+ if (in_array($this->getOperator(), $numericOperations)) {
+ $this->setData('value', $this->getFormattedPrice($this->getValue()));
+ }
+ }
+
return parent::validate($product);
}
@@ -79,4 +87,23 @@ public function getValueElementChooserUrl()
}
return $url !== false ? $this->_backendData->getUrl($url) : '';
}
+
+ /**
+ * @param string $value
+ * @return float|null
+ */
+ private function getFormattedPrice($value)
+ {
+ $value = preg_replace('/[^0-9^\^.,-]/m', '', $value);
+
+ /**
+ * If the comma is the third symbol in the number, we consider it to be a decimal separator
+ */
+ $separatorComa = strpos($value, ',');
+ $separatorDot = strpos($value, '.');
+ if ($separatorComa !== false && $separatorDot === false && preg_match('/,\d{3}$/m', $value) === 1) {
+ $value .= '.00';
+ }
+ return $this->_localeFormat->getNumber($value);
+ }
}
diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/Rule/Condition/ProductTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/Rule/Condition/ProductTest.php
index 0bce282747b16..51c7b9ede5aa2 100644
--- a/app/code/Magento/SalesRule/Test/Unit/Model/Rule/Condition/ProductTest.php
+++ b/app/code/Magento/SalesRule/Test/Unit/Model/Rule/Condition/ProductTest.php
@@ -3,11 +3,15 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\SalesRule\Test\Unit\Model\Rule\Condition;
+use Magento\Directory\Model\CurrencyFactory;
+use Magento\Framework\App\ScopeResolverInterface;
use \Magento\Framework\DB\Adapter\AdapterInterface;
use \Magento\Framework\DB\Select;
-use \Magento\Framework\Model\AbstractModel;
+use Magento\Framework\Locale\Format;
+use Magento\Framework\Locale\ResolverInterface;
use Magento\Quote\Model\Quote\Item\AbstractItem;
use \Magento\Rule\Model\Condition\Context;
use \Magento\Backend\Helper\Data;
@@ -50,8 +54,8 @@ class ProductTest extends \PHPUnit\Framework\TestCase
/** @var Collection|\PHPUnit_Framework_MockObject_MockObject */
protected $collectionMock;
- /** @var FormatInterface|\PHPUnit_Framework_MockObject_MockObject */
- protected $formatMock;
+ /** @var FormatInterface */
+ protected $format;
/** @var AttributeLoaderInterface|\PHPUnit_Framework_MockObject_MockObject */
protected $attributeLoaderInterfaceMock;
@@ -130,8 +134,12 @@ protected function setUp()
$this->collectionMock = $this->getMockBuilder(Collection::class)
->disableOriginalConstructor()
->getMock();
- $this->formatMock = $this->getMockBuilder(FormatInterface::class)
- ->getMockForAbstractClass();
+ $this->format = new Format(
+ $this->getMockBuilder(ScopeResolverInterface::class)->disableOriginalConstructor()->getMock(),
+ $this->getMockBuilder(ResolverInterface::class)->disableOriginalConstructor()->getMock(),
+ $this->getMockBuilder(CurrencyFactory::class)->disableOriginalConstructor()->getMock()
+ );
+
$this->model = new SalesRuleProduct(
$this->contextMock,
$this->backendHelperMock,
@@ -140,7 +148,7 @@ protected function setUp()
$this->productRepositoryMock,
$this->productMock,
$this->collectionMock,
- $this->formatMock
+ $this->format
);
}
@@ -199,7 +207,10 @@ public function testGetValueElementChooserUrl($attribute, $url, $jsObject = '')
$this->assertEquals($url, $this->model->getValueElementChooserUrl());
}
- public function testValidateCategoriesIgnoresVisibility()
+ /**
+ * test ValidateCategoriesIgnoresVisibility
+ */
+ public function testValidateCategoriesIgnoresVisibility(): void
{
/* @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject $product */
$product = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
@@ -231,4 +242,81 @@ public function testValidateCategoriesIgnoresVisibility()
$this->model->validate($item);
}
+
+ /**
+ * @param boolean $isValid
+ * @param string $conditionValue
+ * @param string $operator
+ * @param double $productPrice
+ * @dataProvider localisationProvider
+ */
+ public function testQuoteLocaleFormatPrice($isValid, $conditionValue, $operator = '>=', $productPrice = 2000.00)
+ {
+ $attr = $this->getMockBuilder(\Magento\Framework\Model\ResourceModel\Db\AbstractDb::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getAttribute'])
+ ->getMockForAbstractClass();
+
+ $attr->expects($this->any())
+ ->method('getAttribute')
+ ->willReturn('');
+
+ /* @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject $product */
+ $product = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['setQuoteItemPrice', 'getResource', 'hasData', 'getData',])
+ ->getMock();
+
+ $product->expects($this->any())
+ ->method('setQuoteItemPrice')
+ ->willReturnSelf();
+
+ $product->expects($this->any())
+ ->method('getResource')
+ ->willReturn($attr);
+
+ $product->expects($this->any())
+ ->method('hasData')
+ ->willReturn(true);
+
+ $product->expects($this->any())
+ ->method('getData')
+ ->with('quote_item_price')
+ ->willReturn($productPrice);
+
+ /* @var AbstractItem|\PHPUnit_Framework_MockObject_MockObject $item */
+ $item = $this->getMockBuilder(AbstractItem::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getPrice', 'getProduct',])
+ ->getMockForAbstractClass();
+
+ $item->expects($this->any())
+ ->method('getPrice')
+ ->willReturn($productPrice);
+
+ $item->expects($this->any())
+ ->method('getProduct')
+ ->willReturn($product);
+
+ $this->model->setAttribute('quote_item_price')
+ ->setOperator($operator);
+
+ $this->assertEquals($isValid, $this->model->setValue($conditionValue)->validate($item));
+ }
+
+ /**
+ * DataProvider for testQuoteLocaleFormatPrice
+ *
+ * @return array
+ */
+ public function localisationProvider(): array
+ {
+ return [
+ 'number' => [true, 500.01],
+ 'locale' => [true, '1,500.03'],
+ 'operation' => [true, '1,500.03', '!='],
+ 'stringOperation' => [false, '1,500.03', '{}'],
+ 'smallPrice' => [false, '1,500.03', '>=', 1000],
+ ];
+ }
}
diff --git a/app/code/Magento/Ui/DataProvider/EavValidationRules.php b/app/code/Magento/Ui/DataProvider/EavValidationRules.php
index 12e345e1fa12c..6e2bb3866e947 100644
--- a/app/code/Magento/Ui/DataProvider/EavValidationRules.php
+++ b/app/code/Magento/Ui/DataProvider/EavValidationRules.php
@@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\Ui\DataProvider;
use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
@@ -31,25 +32,51 @@ class EavValidationRules
*/
public function build(AbstractAttribute $attribute, array $data)
{
- $validation = [];
+ $validations = [];
if (isset($data['required']) && $data['required'] == 1) {
- $validation = array_merge($validation, ['required-entry' => true]);
+ $validations = array_merge($validations, ['required-entry' => true]);
}
if ($attribute->getFrontendInput() === 'price') {
- $validation = array_merge($validation, ['validate-zero-or-greater' => true]);
+ $validations = array_merge($validations, ['validate-zero-or-greater' => true]);
}
if ($attribute->getValidateRules()) {
- $validation = array_merge($validation, $attribute->getValidateRules());
+ $validations = array_merge($validations, $this->clipLengthRules($attribute->getValidateRules()));
}
+ return $this->aggregateRules($validations);
+ }
+
+ /**
+ * @param array $validations
+ * @return array
+ */
+ private function aggregateRules(array $validations): array
+ {
$rules = [];
- foreach ($validation as $type => $ruleName) {
- $rule = [$type => $ruleName];
+ foreach ($validations as $type => $ruleValue) {
+ $rule = [$type => $ruleValue];
if ($type === 'input_validation') {
- $rule = isset($this->validationRules[$ruleName]) ? $this->validationRules[$ruleName] : [];
+ $rule = $this->validationRules[$ruleValue] ?? [];
+ }
+ if (count($rule) !== 0) {
+ $key = key($rule);
+ $rules[$key] = $rule[$key];
}
- $rules = array_merge($rules, $rule);
}
+ return $rules;
+ }
+ /**
+ * @param array $rules
+ * @return array
+ */
+ private function clipLengthRules(array $rules): array
+ {
+ if (empty($rules['input_validation'])) {
+ unset(
+ $rules['min_text_length'],
+ $rules['max_text_length']
+ );
+ }
return $rules;
}
}
diff --git a/app/code/Magento/Ui/Test/Unit/DataProvider/EavValidationRulesTest.php b/app/code/Magento/Ui/Test/Unit/DataProvider/EavValidationRulesTest.php
index debcde4765fc7..cdb62ce1db68d 100644
--- a/app/code/Magento/Ui/Test/Unit/DataProvider/EavValidationRulesTest.php
+++ b/app/code/Magento/Ui/Test/Unit/DataProvider/EavValidationRulesTest.php
@@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\Ui\Test\Unit\DataProvider;
use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
@@ -29,6 +30,9 @@ class EavValidationRulesTest extends \PHPUnit\Framework\TestCase
*/
protected $attributeMock;
+ /**
+ * {@inheritDoc}
+ */
protected function setUp()
{
$this->objectManager = new ObjectManager($this);
@@ -42,11 +46,13 @@ protected function setUp()
}
/**
+ * @param string $attributeInputType
+ * @param mixed $validateRules
* @param array $data
* @param array $expected
* @dataProvider buildDataProvider
*/
- public function testBuild($attributeInputType, $validateRules, $data, $expected)
+ public function testBuild($attributeInputType, $validateRules, $data, $expected): void
{
$this->attributeMock->expects($this->once())->method('getFrontendInput')->willReturn($attributeInputType);
$this->attributeMock->expects($this->any())->method('getValidateRules')->willReturn($validateRules);
@@ -70,11 +76,25 @@ public function buildDataProvider()
['', ['input_validation' => 'email'], [], ['validate-email' => true]],
['', ['input_validation' => 'date'], [], ['validate-date' => true]],
['', ['input_validation' => 'other'], [], []],
- ['', ['max_text_length' => '254'], ['required' => 1], ['max_text_length' => 254, 'required-entry' => true]],
- ['', ['max_text_length' => '254', 'min_text_length' => 1], [],
- ['max_text_length' => 254, 'min_text_length' => 1]],
- ['', ['max_text_length' => '254', 'input_validation' => 'date'], [],
- ['max_text_length' => 254, 'validate-date' => true]],
+ ['', ['max_text_length' => '254'], ['required' => 1], ['required-entry' => true]],
+ [
+ '',
+ ['input_validation' => 'other', 'max_text_length' => '254'],
+ ['required' => 1],
+ ['max_text_length' => 254, 'required-entry' => true]
+ ],
+ [
+ '',
+ ['input_validation' => 'other', 'max_text_length' => '254', 'min_text_length' => 1],
+ [],
+ ['max_text_length' => 254, 'min_text_length' => 1]
+ ],
+ [
+ '',
+ ['max_text_length' => '254', 'input_validation' => 'date'],
+ [],
+ ['max_text_length' => 254, 'validate-date' => true]
+ ],
];
}
}
diff --git a/app/code/Magento/Ui/view/base/web/js/form/components/fieldset.js b/app/code/Magento/Ui/view/base/web/js/form/components/fieldset.js
index b729dd3127d90..6d33386fa1f1c 100644
--- a/app/code/Magento/Ui/view/base/web/js/form/components/fieldset.js
+++ b/app/code/Magento/Ui/view/base/web/js/form/components/fieldset.js
@@ -22,7 +22,7 @@ define([
opened: false,
level: 0,
visible: true,
- initializeFieldsetDataByDefault: false, /* Data in some fieldsets should be initialized before open */
+ initializeFieldsetDataByDefault: false, /* Data in some fieldsets should be initialized before open */
disabled: false,
listens: {
'opened': 'onVisibilityChange'
@@ -77,9 +77,9 @@ define([
elem.initContainer(this);
elem.on({
- 'update': this.onChildrenUpdate,
- 'loading': this.onContentLoading,
- 'error': this.onChildrenError
+ 'update': this.onChildrenUpdate,
+ 'loading': this.onContentLoading,
+ 'error': this.onChildrenError
});
if (this.disabled) {
@@ -155,11 +155,42 @@ define([
* @param {String} message - error message.
*/
onChildrenError: function (message) {
- var hasErrors = this.elems.some('error');
+ var hasErrors = false;
+
+ if (!message) {
+ hasErrors = this._isChildrenHasErrors(hasErrors, this);
+ }
this.error(hasErrors || message);
},
+ /**
+ * Returns errors of children if exist
+ *
+ * @param {Boolean} hasErrors
+ * @param {*} container
+ * @return {Boolean}
+ * @private
+ */
+ _isChildrenHasErrors: function (hasErrors, container) {
+ var self = this;
+
+ if (hasErrors === false && container.hasOwnProperty('elems')) {
+ hasErrors = container.elems.some('error');
+
+ if (hasErrors === false && container.hasOwnProperty('_elems')) {
+ container._elems.forEach(function (child) {
+
+ if (hasErrors === false) {
+ hasErrors = self._isChildrenHasErrors(hasErrors, child);
+ }
+ });
+ }
+ }
+
+ return hasErrors;
+ },
+
/**
* Callback that sets loading property to true.
*/
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml
index 9e20bbdaac1d9..5c05d4a840009 100644
--- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml
@@ -49,6 +49,10 @@
+
+ stable:no
+ MAGETWO-94169: [MTF] - OnePageCheckoutUsingNonDefaultAddress_0 fails on 2.3-develop
+
severity:S1
diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/AddressTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/AddressTest.php
index 4c30adb6894e2..32a622d4aa654 100644
--- a/dev/tests/integration/testsuite/Magento/Customer/Controller/AddressTest.php
+++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/AddressTest.php
@@ -18,6 +18,9 @@ class AddressTest extends \Magento\TestFramework\TestCase\AbstractController
/** @var FormKey */
private $formKey;
+ /**
+ * {@inheritDoc}
+ */
protected function setUp()
{
parent::setUp();
@@ -150,8 +153,8 @@ public function testFailedFormPostAction()
$this->equalTo(
[
'One or more input exceptions have occurred.',
- '"street" is required. Enter and try again.',
- '"city" is required. Enter and try again.',
+ '"street" is required. Enter and try again.',
+ '"city" is required. Enter and try again.',
]
),
\Magento\Framework\Message\MessageInterface::TYPE_ERROR
diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php
index b942365d64a75..6448816c9345c 100644
--- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php
+++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php
@@ -44,6 +44,9 @@ class IndexTest extends \Magento\TestFramework\TestCase\AbstractBackendControlle
/** @var \Magento\TestFramework\ObjectManager */
protected $objectManager;
+ /**
+ * {@inheritDoc}
+ */
protected function setUp()
{
parent::setUp();
@@ -67,6 +70,9 @@ protected function setUp()
);
}
+ /**
+ * {@inheritDoc}
+ */
protected function tearDown()
{
/**
@@ -522,7 +528,10 @@ public function testEditAction()
$this->assertContains('test firstname test lastname
', $body);
}
- public function testNewAction()
+ /**
+ * Tests new action
+ */
+ public function testNewAction(): void
{
$this->dispatch('backend/customer/index/edit');
$body = $this->getResponse()->getBody();
@@ -717,12 +726,9 @@ public function testValidateCustomerWithAddressFailure()
$this->assertContains('{"error":true,"messages":', $body);
$this->assertContains('\"First Name\" is a required value', $body);
- $this->assertContains('\"First Name\" length must be equal or greater than 1 characters', $body);
$this->assertContains('\"Last Name\" is a required value.', $body);
- $this->assertContains('\"Last Name\" length must be equal or greater than 1 characters.', $body);
$this->assertContains('\"Country\" is a required value.', $body);
$this->assertContains('\"Phone Number\" is a required value.', $body);
- $this->assertContains('\"Phone Number\" length must be equal or greater than 1 characters.', $body);
}
/**
diff --git a/lib/internal/Magento/Framework/Locale/Format.php b/lib/internal/Magento/Framework/Locale/Format.php
index 89f6957011876..ca50cdb2440f4 100644
--- a/lib/internal/Magento/Framework/Locale/Format.php
+++ b/lib/internal/Magento/Framework/Locale/Format.php
@@ -65,7 +65,7 @@ public function getNumber($value)
}
//trim spaces and apostrophes
- $value = str_replace(['\'', ' '], '', $value);
+ $value = preg_replace('/[^0-9^\^.,-]/m', '', $value);
$separatorComa = strpos($value, ',');
$separatorDot = strpos($value, '.');
diff --git a/lib/internal/Magento/Framework/Locale/Test/Unit/FormatTest.php b/lib/internal/Magento/Framework/Locale/Test/Unit/FormatTest.php
index 41583fd1383a5..1141f451c13a5 100644
--- a/lib/internal/Magento/Framework/Locale/Test/Unit/FormatTest.php
+++ b/lib/internal/Magento/Framework/Locale/Test/Unit/FormatTest.php
@@ -33,6 +33,9 @@ class FormatTest extends \PHPUnit\Framework\TestCase
*/
protected $currency;
+ /**
+ * {@inheritDoc}
+ */
protected function setUp()
{
$this->currency = $this->getMockBuilder(\Magento\Directory\Model\Currency::class)
@@ -41,9 +44,7 @@ protected function setUp()
$this->scope = $this->getMockBuilder(\Magento\Framework\App\ScopeInterface::class)
->setMethods(['getCurrentCurrency'])
->getMockForAbstractClass();
- $this->scope->expects($this->once())
- ->method('getCurrentCurrency')
- ->willReturn($this->currency);
+
$this->scopeResolver = $this->getMockBuilder(\Magento\Framework\App\ScopeResolverInterface::class)
->setMethods(['getScope'])
->getMockForAbstractClass();
@@ -52,7 +53,10 @@ protected function setUp()
->willReturn($this->scope);
$this->localeResolver = $this->getMockBuilder(\Magento\Framework\Locale\ResolverInterface::class)
->getMock();
+
+ /** @var \Magento\Directory\Model\CurrencyFactory|\PHPUnit_Framework_MockObject_MockObject $currencyFactory */
$currencyFactory = $this->getMockBuilder(\Magento\Directory\Model\CurrencyFactory::class)
+ ->disableOriginalConstructor()
->getMock();
$this->formatModel = new \Magento\Framework\Locale\Format(
@@ -63,21 +67,26 @@ protected function setUp()
}
/**
- * @param $localeCode
- * @param $expectedResult
+ * @param string $localeCode
+ * @param array $expectedResult
* @dataProvider getPriceFormatDataProvider
*/
- public function testGetPriceFormat($localeCode, $expectedResult)
+ public function testGetPriceFormat($localeCode, array $expectedResult): void
{
+ $this->scope->expects($this->once())
+ ->method('getCurrentCurrency')
+ ->willReturn($this->currency);
+
$result = $this->formatModel->getPriceFormat($localeCode);
$intersection = array_intersect_assoc($result, $expectedResult);
$this->assertCount(count($expectedResult), $intersection);
}
/**
+ *
* @return array
*/
- public function getPriceFormatDataProvider()
+ public function getPriceFormatDataProvider(): array
{
return [
['en_US', ['decimalSymbol' => '.', 'groupSymbol' => ',']],
@@ -86,4 +95,35 @@ public function getPriceFormatDataProvider()
['uk_UA', ['decimalSymbol' => ',', 'groupSymbol' => ' ']]
];
}
+
+ /**
+ *
+ * @param mixed $value
+ * @param float $expected
+ * @dataProvider provideNumbers
+ */
+ public function testGetNumber($value, $expected): void
+ {
+ $this->assertEquals($expected, $this->formatModel->getNumber($value));
+ }
+
+ /**
+ *
+ * @return array
+ */
+ public function provideNumbers(): array
+ {
+ return [
+ [' 2345.4356,1234', 23454356.1234],
+ ['+23,3452.123', 233452.123],
+ ['12343', 12343],
+ ['-9456km', -9456],
+ ['0', 0],
+ ['2 054,10', 2054.1],
+ ['2046,45', 2046.45],
+ ['2 054.52', 2054.52],
+ ['2,46 GB', 2.46],
+ ['2,054.00', 2054],
+ ];
+ }
}