diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category.php
index 8f8f21e207bf5..071ba902f4fe0 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category.php
@@ -31,7 +31,7 @@ abstract class Category extends \Magento\Backend\App\Action
*/
protected function _initCategory($getRootInstead = false)
{
- $categoryId = (int)$this->getRequest()->getParam('id', false);
+ $categoryId = $this->resolveCategoryId();
$storeId = (int)$this->getRequest()->getParam('store');
$category = $this->_objectManager->create(\Magento\Catalog\Model\Category::class);
$category->setStoreId($storeId);
@@ -62,6 +62,18 @@ protected function _initCategory($getRootInstead = false)
return $category;
}
+ /**
+ * Resolve Category Id (from get or from post)
+ *
+ * @return int
+ */
+ private function resolveCategoryId()
+ {
+ $categoryId = (int)$this->getRequest()->getParam('id', false);
+
+ return $categoryId ?: (int)$this->getRequest()->getParam('entity_id', false);
+ }
+
/**
* Build response for ajax request
*
diff --git a/app/code/Magento/Catalog/Helper/Product/Compare.php b/app/code/Magento/Catalog/Helper/Product/Compare.php
index 64b3411591455..3a7ce70cbff52 100644
--- a/app/code/Magento/Catalog/Helper/Product/Compare.php
+++ b/app/code/Magento/Catalog/Helper/Product/Compare.php
@@ -228,10 +228,9 @@ public function getRemoveUrl()
*/
public function getPostDataRemove($product)
{
- $listCleanUrl = $this->getEncodedUrl($this->_getUrl('catalog/product_compare'));
$data = [
- \Magento\Framework\App\ActionInterface::PARAM_NAME_URL_ENCODED => $listCleanUrl,
- 'product' => $product->getId()
+ \Magento\Framework\App\ActionInterface::PARAM_NAME_URL_ENCODED => '',
+ 'product' => $product->getId(),
];
return $this->postHelper->getPostData($this->getRemoveUrl(), $data);
}
@@ -253,9 +252,8 @@ public function getClearListUrl()
*/
public function getPostDataClearList()
{
- $refererUrl = $this->_getRequest()->getServer('HTTP_REFERER');
$params = [
- \Magento\Framework\App\ActionInterface::PARAM_NAME_URL_ENCODED => $this->urlEncoder->encode($refererUrl)
+ \Magento\Framework\App\ActionInterface::PARAM_NAME_URL_ENCODED => '',
];
return $this->postHelper->getPostData($this->getClearListUrl(), $params);
}
diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Action/Full.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Action/Full.php
index ba093c0129855..3c33c44cb0dc4 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Action/Full.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Action/Full.php
@@ -7,6 +7,13 @@
class Full extends \Magento\Catalog\Model\Indexer\Category\Product\AbstractAction
{
+ /**
+ * Whether to use main or temporary index table
+ *
+ * @var bool
+ */
+ protected $useTempTable = false;
+
/**
* Refresh entities index
*
diff --git a/app/code/Magento/Catalog/Model/ProductRepository.php b/app/code/Magento/Catalog/Model/ProductRepository.php
index 9ceaa8bc9d049..4385c8add37ae 100644
--- a/app/code/Magento/Catalog/Model/ProductRepository.php
+++ b/app/code/Magento/Catalog/Model/ProductRepository.php
@@ -313,15 +313,22 @@ protected function initializeProductData(array $productData, $createNew)
*/
private function assignProductToWebsites(\Magento\Catalog\Model\Product $product)
{
+ $websiteIds = $product->getWebsiteIds();
+
if (!$this->storeManager->hasSingleStore()) {
- if ($this->storeManager->getStore()->getCode() == \Magento\Store\Model\Store::ADMIN_CODE) {
- $websiteIds = array_keys($this->storeManager->getWebsites());
- } else {
- $websiteIds = [$this->storeManager->getStore()->getWebsiteId()];
- }
+ $websiteIds = array_unique(
+ array_merge(
+ $websiteIds,
+ [$this->storeManager->getStore()->getWebsiteId()]
+ )
+ );
+ }
- $product->setWebsiteIds(array_unique(array_merge($product->getWebsiteIds(), $websiteIds)));
+ if ($this->storeManager->getStore(true)->getCode() == \Magento\Store\Model\Store::ADMIN_CODE) {
+ $websiteIds = array_keys($this->storeManager->getWebsites());
}
+
+ $product->setWebsiteIds($websiteIds);
}
/**
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category.php b/app/code/Magento/Catalog/Model/ResourceModel/Category.php
index 3b3468656935d..407c2027923de 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Category.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Category.php
@@ -33,6 +33,11 @@ class Category extends AbstractResource
*/
protected $_categoryProductTable;
+ /**
+ * @var array[]
+ */
+ private $entitiesWhereAttributesIs;
+
/**
* Id of 'is_active' category attribute
*
@@ -573,22 +578,29 @@ public function getIsActiveAttributeId()
*/
public function findWhereAttributeIs($entityIdsFilter, $attribute, $expectedValue)
{
- $linkField = $this->getLinkField();
- $bind = ['attribute_id' => $attribute->getId(), 'value' => $expectedValue];
- $selectEntities = $this->getConnection()->select()->from(
- ['ce' => $this->getTable('catalog_category_entity')],
- ['entity_id']
- )->joinLeft(
- ['ci' => $attribute->getBackend()->getTable()],
- "ci.{$linkField} = ce.{$linkField} AND attribute_id = :attribute_id",
- ['value']
- )->where(
- 'ci.value = :value'
- )->where(
- 'ce.entity_id IN (?)',
- $entityIdsFilter
- );
- return $this->getConnection()->fetchCol($selectEntities, $bind);
+ $entityIdsFilterHash = md5(serialize($entityIdsFilter));
+
+ if (!isset($this->entitiesWhereAttributesIs[$entityIdsFilterHash][$attribute->getId()][$expectedValue])) {
+ $linkField = $this->getLinkField();
+ $bind = ['attribute_id' => $attribute->getId(), 'value' => $expectedValue];
+ $selectEntities = $this->getConnection()->select()->from(
+ ['ce' => $this->getTable('catalog_category_entity')],
+ ['entity_id']
+ )->joinLeft(
+ ['ci' => $attribute->getBackend()->getTable()],
+ "ci.{$linkField} = ce.{$linkField} AND attribute_id = :attribute_id",
+ ['value']
+ )->where(
+ 'ci.value = :value'
+ )->where(
+ 'ce.entity_id IN (?)',
+ $entityIdsFilter
+ );
+ $this->entitiesWhereAttributesIs[$entityIdsFilterHash][$attribute->getId()][$expectedValue] =
+ $this->getConnection()->fetchCol($selectEntities, $bind);
+ }
+
+ return $this->entitiesWhereAttributesIs[$entityIdsFilterHash][$attribute->getId()][$expectedValue];
}
/**
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/MaxHeapTableSizeProcessor.php b/app/code/Magento/Catalog/Model/ResourceModel/MaxHeapTableSizeProcessor.php
index 92946c7f2d9e1..2e599c2af3d87 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/MaxHeapTableSizeProcessor.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/MaxHeapTableSizeProcessor.php
@@ -7,6 +7,9 @@
use Magento\Framework\App\ResourceConnection;
+/**
+ * @deprecated
+ */
class MaxHeapTableSizeProcessor
{
/**
diff --git a/app/code/Magento/Catalog/Plugin/Model/Indexer/Category/Product/MaxHeapTableSizeProcessorOnFullReindex.php b/app/code/Magento/Catalog/Plugin/Model/Indexer/Category/Product/MaxHeapTableSizeProcessorOnFullReindex.php
index a4cd503c6b08b..f14156c7f09e7 100644
--- a/app/code/Magento/Catalog/Plugin/Model/Indexer/Category/Product/MaxHeapTableSizeProcessorOnFullReindex.php
+++ b/app/code/Magento/Catalog/Plugin/Model/Indexer/Category/Product/MaxHeapTableSizeProcessorOnFullReindex.php
@@ -10,6 +10,9 @@
use Magento\Catalog\Model\ResourceModel\MaxHeapTableSizeProcessor;
use Psr\Log\LoggerInterface;
+/**
+ * @deprecated
+ */
class MaxHeapTableSizeProcessorOnFullReindex
{
/**
diff --git a/app/code/Magento/Catalog/Test/Unit/Helper/Product/CompareTest.php b/app/code/Magento/Catalog/Test/Unit/Helper/Product/CompareTest.php
index 29786ecdce969..9f4d41aefd6bb 100644
--- a/app/code/Magento/Catalog/Test/Unit/Helper/Product/CompareTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Helper/Product/CompareTest.php
@@ -113,18 +113,13 @@ public function testGetPostDataRemove()
//Data
$productId = 1;
$removeUrl = 'catalog/product_compare/remove';
- $compareListUrl = 'catalog/product_compare';
$postParams = [
- Action::PARAM_NAME_URL_ENCODED => strtr(base64_encode($compareListUrl), '+/=', '-_,'),
+ Action::PARAM_NAME_URL_ENCODED => '',
'product' => $productId
];
//Verification
- $this->urlBuilder->expects($this->at(0))
- ->method('getUrl')
- ->with($compareListUrl)
- ->will($this->returnValue($compareListUrl));
- $this->urlBuilder->expects($this->at(1))
+ $this->urlBuilder->expects($this->once())
->method('getUrl')
->with($removeUrl)
->will($this->returnValue($removeUrl));
@@ -159,18 +154,12 @@ public function testGetClearListUrl()
public function testGetPostDataClearList()
{
//Data
- $refererUrl = 'home/';
$clearUrl = 'catalog/product_compare/clear';
$postParams = [
- Action::PARAM_NAME_URL_ENCODED => strtr(base64_encode($refererUrl), '+/=', '-_,')
+ Action::PARAM_NAME_URL_ENCODED => ''
];
//Verification
- $this->request->expects($this->once())
- ->method('getServer')
- ->with('HTTP_REFERER')
- ->will($this->returnValue($refererUrl));
-
$this->urlBuilder->expects($this->once())
->method('getUrl')
->with($clearUrl)
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php
index 5042ac1b745cf..e91bb469eb112 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php
@@ -14,6 +14,7 @@
use Magento\Framework\DB\Adapter\ConnectionException;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
use Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface;
+use Magento\Store\Api\Data\StoreInterface;
/**
* Class ProductRepositoryTest
@@ -284,7 +285,6 @@ protected function setUp()
$storeMock->expects($this->any())->method('getWebsiteId')->willReturn('1');
$storeMock->expects($this->any())->method('getCode')->willReturn(\Magento\Store\Model\Store::ADMIN_CODE);
$this->storeManagerMock->expects($this->any())->method('getStore')->willReturn($storeMock);
- $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']);
$this->mediaGalleryProcessor = $this->getMock(
\Magento\Catalog\Model\Product\Gallery\Processor::class,
@@ -495,6 +495,7 @@ public function testGetBySkuFromCacheInitializedInGetById()
public function testSaveExisting()
{
+ $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']);
$this->resourceModelMock->expects($this->any())->method('getIdBySku')->will($this->returnValue(100));
$this->productFactoryMock->expects($this->any())
->method('create')
@@ -514,6 +515,7 @@ public function testSaveExisting()
public function testSaveNew()
{
+ $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']);
$this->resourceModelMock->expects($this->at(0))->method('getIdBySku')->will($this->returnValue(null));
$this->resourceModelMock->expects($this->at(3))->method('getIdBySku')->will($this->returnValue(100));
$this->productFactoryMock->expects($this->any())
@@ -538,6 +540,7 @@ public function testSaveNew()
*/
public function testSaveUnableToSaveException()
{
+ $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']);
$this->resourceModelMock->expects($this->exactly(1))->method('getIdBySku')->will($this->returnValue(null));
$this->productFactoryMock->expects($this->exactly(2))
->method('create')
@@ -562,6 +565,7 @@ public function testSaveUnableToSaveException()
*/
public function testSaveException()
{
+ $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']);
$this->resourceModelMock->expects($this->exactly(1))->method('getIdBySku')->will($this->returnValue(null));
$this->productFactoryMock->expects($this->exactly(2))
->method('create')
@@ -587,6 +591,7 @@ public function testSaveException()
*/
public function testSaveInvalidProductException()
{
+ $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']);
$this->resourceModelMock->expects($this->exactly(1))->method('getIdBySku')->will($this->returnValue(null));
$this->productFactoryMock->expects($this->exactly(2))
->method('create')
@@ -610,6 +615,7 @@ public function testSaveInvalidProductException()
*/
public function testSaveThrowsTemporaryStateExceptionIfDatabaseConnectionErrorOccurred()
{
+ $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']);
$this->productFactoryMock->expects($this->any())
->method('create')
->will($this->returnValue($this->productMock));
@@ -796,6 +802,7 @@ public function cacheKeyDataProvider()
*/
public function testSaveExistingWithOptions(array $newOptions, array $existingOptions, array $expectedData)
{
+ $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']);
$this->resourceModelMock->expects($this->any())->method('getIdBySku')->will($this->returnValue(100));
$this->productFactoryMock->expects($this->any())
->method('create')
@@ -964,6 +971,7 @@ public function saveExistingWithOptionsDataProvider()
*/
public function testSaveWithLinks(array $newLinks, array $existingLinks, array $expectedData)
{
+ $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']);
$this->resourceModelMock->expects($this->any())->method('getIdBySku')->will($this->returnValue(100));
$this->productFactoryMock->expects($this->any())
->method('create')
@@ -1143,6 +1151,7 @@ protected function setupProductMocksForSave()
public function testSaveExistingWithNewMediaGalleryEntries()
{
+ $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']);
$newEntriesData = [
[
"label" => "label_text",
@@ -1222,8 +1231,48 @@ public function testSaveExistingWithNewMediaGalleryEntries()
$this->model->save($this->productMock);
}
+ public function websitesProvider()
+ {
+ return [
+ [[1,2,3]]
+ ];
+ }
+
+ public function testSaveWithDifferentWebsites()
+ {
+ $storeMock = $this->getMock(StoreInterface::class);
+ $this->resourceModelMock->expects($this->at(0))->method('getIdBySku')->will($this->returnValue(null));
+ $this->resourceModelMock->expects($this->at(3))->method('getIdBySku')->will($this->returnValue(100));
+ $this->productFactoryMock->expects($this->any())
+ ->method('create')
+ ->will($this->returnValue($this->productMock));
+ $this->initializationHelperMock->expects($this->never())->method('initialize');
+ $this->resourceModelMock->expects($this->once())->method('validate')->with($this->productMock)
+ ->willReturn(true);
+ $this->resourceModelMock->expects($this->once())->method('save')->with($this->productMock)->willReturn(true);
+ $this->extensibleDataObjectConverterMock
+ ->expects($this->once())
+ ->method('toNestedArray')
+ ->will($this->returnValue($this->productData));
+ $this->storeManagerMock->expects($this->any())
+ ->method('getStore')
+ ->willReturn($storeMock);
+ $this->storeManagerMock->expects($this->once())
+ ->method('getWebsites')
+ ->willReturn([
+ 1 => ['first'],
+ 2 => ['second'],
+ 3 => ['third']
+ ]);
+ $this->productMock->expects($this->once())->method('getWebsiteIds')->willReturn([1,2,3]);
+ $this->productMock->expects($this->once())->method('setWebsiteIds')->willReturn([2,3]);
+
+ $this->assertEquals($this->productMock, $this->model->save($this->productMock));
+ }
+
public function testSaveExistingWithMediaGalleryEntries()
{
+ $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']);
//update one entry, delete one entry
$newEntries = [
[
diff --git a/app/code/Magento/Catalog/etc/adminhtml/di.xml b/app/code/Magento/Catalog/etc/adminhtml/di.xml
index 9993d4657533a..584a2e51514db 100644
--- a/app/code/Magento/Catalog/etc/adminhtml/di.xml
+++ b/app/code/Magento/Catalog/etc/adminhtml/di.xml
@@ -73,7 +73,6 @@
-
diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/IndexerHandlerFactory.php b/app/code/Magento/CatalogSearch/Model/Indexer/IndexerHandlerFactory.php
index bb2df11c9083d..58be7fcb1bcb9 100644
--- a/app/code/Magento/CatalogSearch/Model/Indexer/IndexerHandlerFactory.php
+++ b/app/code/Magento/CatalogSearch/Model/Indexer/IndexerHandlerFactory.php
@@ -75,12 +75,14 @@ public function create(array $data = [])
$indexer = $this->_objectManager->create($this->handlers[$currentHandler], $data);
if (!$indexer instanceof IndexerInterface) {
- throw new \InvalidArgumentException($indexer . ' doesn\'t implement \Magento\Framework\IndexerInterface');
+ throw new \InvalidArgumentException(
+ $currentHandler . ' indexer handler doesn\'t implement ' . IndexerInterface::class
+ );
}
if ($indexer && !$indexer->isAvailable()) {
throw new \LogicException(
- 'Indexer handler is not available: ' . $indexer
+ 'Indexer handler is not available: ' . $currentHandler
);
}
return $indexer;
diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/IndexerHandlerFactoryTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/IndexerHandlerFactoryTest.php
new file mode 100644
index 0000000000000..417eb63d08ab4
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/IndexerHandlerFactoryTest.php
@@ -0,0 +1,173 @@
+objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class)
+ ->getMockForAbstractClass();
+ $this->scopeConfigMock = $this->getMockBuilder(ScopeConfigInterface::class)
+ ->getMockForAbstractClass();
+ }
+
+ public function testCreate()
+ {
+ $configPath = 'config_path';
+ $currentHandler = 'current_handler';
+ $currentHandlerClass = 'current_handler_class';
+ $handlers = [
+ $currentHandler => $currentHandlerClass,
+ ];
+ $data = ['data'];
+
+ $this->scopeConfigMock->expects($this->once())
+ ->method('getValue')
+ ->with($configPath, ScopeInterface::SCOPE_STORE)
+ ->willReturn($currentHandler);
+
+ $indexerMock = $this->getMockBuilder(IndexerInterface::class)
+ ->getMockForAbstractClass();
+
+ $this->objectManagerMock->expects($this->once())
+ ->method('create')
+ ->with($currentHandlerClass, $data)
+ ->willReturn($indexerMock);
+
+ $indexerMock->expects($this->once())
+ ->method('isAvailable')
+ ->willReturn(true);
+
+ $this->model = new IndexerHandlerFactory(
+ $this->objectManagerMock,
+ $this->scopeConfigMock,
+ $configPath,
+ $handlers
+ );
+
+ $this->assertEquals($indexerMock, $this->model->create($data));
+ }
+
+ /**
+ * @expectedException \LogicException
+ * @expectedExceptionMessage There is no such indexer handler: current_handler
+ */
+ public function testCreateWithoutHandlers()
+ {
+ $configPath = 'config_path';
+ $currentHandler = 'current_handler';
+ $handlers = [];
+ $data = ['data'];
+
+ $this->scopeConfigMock->expects($this->once())
+ ->method('getValue')
+ ->with($configPath, ScopeInterface::SCOPE_STORE)
+ ->willReturn($currentHandler);
+
+ $this->model = new IndexerHandlerFactory(
+ $this->objectManagerMock,
+ $this->scopeConfigMock,
+ $configPath,
+ $handlers
+ );
+
+ $this->model->create($data);
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage current_handler indexer handler doesn't implement
+ */
+ public function testCreateWithWrongHandler()
+ {
+ $configPath = 'config_path';
+ $currentHandler = 'current_handler';
+ $currentHandlerClass = 'current_handler_class';
+ $handlers = [
+ $currentHandler => $currentHandlerClass,
+ ];
+ $data = ['data'];
+
+ $this->scopeConfigMock->expects($this->once())
+ ->method('getValue')
+ ->with($configPath, ScopeInterface::SCOPE_STORE)
+ ->willReturn($currentHandler);
+
+ $indexerMock = $this->getMockBuilder(\stdClass::class)
+ ->getMockForAbstractClass();
+
+ $this->objectManagerMock->expects($this->once())
+ ->method('create')
+ ->with($currentHandlerClass, $data)
+ ->willReturn($indexerMock);
+
+ $this->model = new IndexerHandlerFactory(
+ $this->objectManagerMock,
+ $this->scopeConfigMock,
+ $configPath,
+ $handlers
+ );
+
+ $this->model->create($data);
+ }
+
+ /**
+ * @expectedException \LogicException
+ * @expectedExceptionMessage Indexer handler is not available: current_handler
+ */
+ public function testCreateWithoutAvailableHandler()
+ {
+ $configPath = 'config_path';
+ $currentHandler = 'current_handler';
+ $currentHandlerClass = 'current_handler_class';
+ $handlers = [
+ $currentHandler => $currentHandlerClass,
+ ];
+ $data = ['data'];
+
+ $this->scopeConfigMock->expects($this->once())
+ ->method('getValue')
+ ->with($configPath, ScopeInterface::SCOPE_STORE)
+ ->willReturn($currentHandler);
+
+ $indexerMock = $this->getMockBuilder(IndexerInterface::class)
+ ->getMockForAbstractClass();
+
+ $this->objectManagerMock->expects($this->once())
+ ->method('create')
+ ->with($currentHandlerClass, $data)
+ ->willReturn($indexerMock);
+
+ $indexerMock->expects($this->once())
+ ->method('isAvailable')
+ ->willReturn(false);
+
+ $this->model = new IndexerHandlerFactory(
+ $this->objectManagerMock,
+ $this->scopeConfigMock,
+ $configPath,
+ $handlers
+ );
+
+ $this->model->create($data);
+ }
+}
diff --git a/app/code/Magento/CatalogUrlRewrite/Model/CategoryBasedProductRewriteGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/CategoryBasedProductRewriteGenerator.php
new file mode 100644
index 0000000000000..58025ad03f0b4
--- /dev/null
+++ b/app/code/Magento/CatalogUrlRewrite/Model/CategoryBasedProductRewriteGenerator.php
@@ -0,0 +1,61 @@
+productScopeRewriteGenerator = $productScopeRewriteGenerator;
+ }
+
+ /**
+ * Generate product url rewrites based on category
+ *
+ * @param \Magento\Catalog\Model\Product $product
+ * @param \Magento\Catalog\Model\Category $category
+ * @return \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[]
+ */
+ public function generate(Product $product, Category $category)
+ {
+ if ($product->getVisibility() == Visibility::VISIBILITY_NOT_VISIBLE) {
+ return [];
+ }
+
+ $storeId = $product->getStoreId();
+
+ $urls = $this->productScopeRewriteGenerator->isGlobalScope($storeId)
+ ? $this->productScopeRewriteGenerator->generateForGlobalScope([$category], $product)
+ : $this->productScopeRewriteGenerator->generateForSpecificStoreView($storeId, [$category], $product);
+
+ $this->product = null;
+ return $urls;
+ }
+}
diff --git a/app/code/Magento/CatalogUrlRewrite/Model/ProductScopeRewriteGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/ProductScopeRewriteGenerator.php
new file mode 100644
index 0000000000000..94464ec05d824
--- /dev/null
+++ b/app/code/Magento/CatalogUrlRewrite/Model/ProductScopeRewriteGenerator.php
@@ -0,0 +1,171 @@
+storeViewService = $storeViewService;
+ $this->storeManager = $storeManager;
+ $this->objectRegistryFactory = $objectRegistryFactory;
+ $this->canonicalUrlRewriteGenerator = $canonicalUrlRewriteGenerator;
+ $this->categoriesUrlRewriteGenerator = $categoriesUrlRewriteGenerator;
+ $this->currentUrlRewritesRegenerator = $currentUrlRewritesRegenerator;
+ $this->anchorUrlRewriteGenerator = $anchorUrlRewriteGenerator;
+ }
+
+ /**
+ * Check is global scope
+ *
+ * @param int|null $storeId
+ * @return bool
+ */
+ public function isGlobalScope($storeId)
+ {
+ return null === $storeId || $storeId == Store::DEFAULT_STORE_ID;
+ }
+
+ /**
+ * Generate url rewrites for global scope
+ *
+ * @param Product $product
+ * @param \Magento\Framework\Data\Collection $productCategories
+ * @return array
+ */
+ public function generateForGlobalScope($productCategories, Product $product)
+ {
+ $urls = [];
+ $productId = $product->getEntityId();
+
+ foreach ($product->getStoreIds() as $id) {
+ if (!$this->isGlobalScope($id)
+ && !$this->storeViewService->doesEntityHaveOverriddenUrlKeyForStore($id, $productId, Product::ENTITY)
+ ) {
+ $urls = array_merge($urls, $this->generateForSpecificStoreView($id, $productCategories, $product));
+ }
+ }
+
+ return $urls;
+ }
+
+ /**
+ * Generate list of urls for specific store view
+ *
+ * @param int $storeId
+ * @param \Magento\Framework\Data\Collection $productCategories
+ * @param \Magento\Catalog\Model\Product $product
+ * @return \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[]
+ */
+ public function generateForSpecificStoreView($storeId, $productCategories, Product $product)
+ {
+ $categories = [];
+ foreach ($productCategories as $category) {
+ if ($this->isCategoryProperForGenerating($category, $storeId)) {
+ $categories[] = $category;
+ }
+ }
+ $productCategories = $this->objectRegistryFactory->create(['entities' => $categories]);
+ /**
+ * @var $urls \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[]
+ */
+ $urls = array_merge(
+ $this->canonicalUrlRewriteGenerator->generate($storeId, $product),
+ $this->categoriesUrlRewriteGenerator->generate($storeId, $product, $productCategories),
+ $this->currentUrlRewritesRegenerator->generate($storeId, $product, $productCategories),
+ $this->anchorUrlRewriteGenerator->generate($storeId, $product, $productCategories)
+ );
+
+ /* Reduce duplicates. Last wins */
+ $result = [];
+ foreach ($urls as $url) {
+ $result[$url->getTargetPath() . '-' . $url->getStoreId()] = $url;
+ }
+ $this->productCategories = null;
+ return $result;
+ }
+
+ /**
+ * Check possibility for url rewrite generation
+ *
+ * @param \Magento\Catalog\Model\Category $category
+ * @param int $storeId
+ * @return bool
+ */
+ public function isCategoryProperForGenerating(Category $category, $storeId)
+ {
+ if ($category->getParentId() != \Magento\Catalog\Model\Category::TREE_ROOT_ID) {
+ list(, $rootCategoryId) = $category->getParentIds();
+ return $rootCategoryId == $this->storeManager->getStore($storeId)->getRootCategoryId();
+ }
+ return false;
+ }
+}
diff --git a/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php
index db39a201d9c05..f8f8991f95a04 100644
--- a/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php
+++ b/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php
@@ -9,9 +9,8 @@
use Magento\CatalogUrlRewrite\Model\Product\CanonicalUrlRewriteGenerator;
use Magento\CatalogUrlRewrite\Model\Product\CategoriesUrlRewriteGenerator;
use Magento\CatalogUrlRewrite\Model\Product\CurrentUrlRewritesRegenerator;
-use Magento\CatalogUrlRewrite\Model\Product\AnchorUrlRewriteGenerator;
use Magento\CatalogUrlRewrite\Service\V1\StoreViewService;
-use Magento\Store\Model\Store;
+use Magento\Framework\App\ObjectManager;
use Magento\Catalog\Model\Product\Visibility;
/**
@@ -26,32 +25,55 @@ class ProductUrlRewriteGenerator
*/
const ENTITY_TYPE = 'product';
- /** @var \Magento\CatalogUrlRewrite\Service\V1\StoreViewService */
+ /**
+ * @deprecated
+ * @var \Magento\CatalogUrlRewrite\Service\V1\StoreViewService
+ */
protected $storeViewService;
/** @var \Magento\Catalog\Model\Product */
protected $product;
- /** @var \Magento\CatalogUrlRewrite\Model\Product\CurrentUrlRewritesRegenerator */
+ /**
+ * @deprecated
+ * @var \Magento\CatalogUrlRewrite\Model\Product\CurrentUrlRewritesRegenerator
+ */
protected $currentUrlRewritesRegenerator;
- /** @var \Magento\CatalogUrlRewrite\Model\Product\CategoriesUrlRewriteGenerator */
+ /**
+ * @deprecated
+ * @var \Magento\CatalogUrlRewrite\Model\Product\CategoriesUrlRewriteGenerator
+ */
protected $categoriesUrlRewriteGenerator;
- /** @var \Magento\CatalogUrlRewrite\Model\Product\CanonicalUrlRewriteGenerator */
+ /**
+ * @deprecated
+ * @var \Magento\CatalogUrlRewrite\Model\Product\CanonicalUrlRewriteGenerator
+ */
protected $canonicalUrlRewriteGenerator;
- /** @var \Magento\CatalogUrlRewrite\Model\ObjectRegistryFactory */
+ /**
+ * @deprecated
+ * @var \Magento\CatalogUrlRewrite\Model\ObjectRegistryFactory
+ */
protected $objectRegistryFactory;
- /** @var \Magento\CatalogUrlRewrite\Model\ObjectRegistry */
+ /**
+ * @deprecated
+ * @var \Magento\CatalogUrlRewrite\Model\ObjectRegistry
+ */
protected $productCategories;
- /** @var \Magento\Store\Model\StoreManagerInterface */
+ /**
+ * @deprecated
+ * @var \Magento\Store\Model\StoreManagerInterface
+ */
protected $storeManager;
- /** @var AnchorUrlRewriteGenerator */
- private $anchorUrlRewriteGenerator;
+ /**
+ * @var ProductScopeRewriteGenerator
+ */
+ private $productScopeRewriteGenerator;
/**
* @param \Magento\CatalogUrlRewrite\Model\Product\CanonicalUrlRewriteGenerator $canonicalUrlRewriteGenerator
@@ -78,17 +100,19 @@ public function __construct(
}
/**
- * @return AnchorUrlRewriteGenerator
+ * Retrieve Delegator for generation rewrites in different scopes
*
* @deprecated
+ * @return ProductScopeRewriteGenerator|mixed
*/
- private function getAnchorUrlRewriteGenerator()
+ private function getProductScopeRewriteGenerator()
{
- if ($this->anchorUrlRewriteGenerator === null) {
- $this->anchorUrlRewriteGenerator = \Magento\Framework\App\ObjectManager::getInstance()
- ->get(\Magento\CatalogUrlRewrite\Model\Product\AnchorUrlRewriteGenerator::class);
+ if (!$this->productScopeRewriteGenerator) {
+ $this->productScopeRewriteGenerator = ObjectManager::getInstance()
+ ->get(ProductScopeRewriteGenerator::class);
}
- return $this->anchorUrlRewriteGenerator;
+
+ return $this->productScopeRewriteGenerator;
}
/**
@@ -121,80 +145,49 @@ public function generate(Product $product)
/**
* Check is global scope
*
+ * @deprecated
* @param int|null $storeId
* @return bool
*/
protected function isGlobalScope($storeId)
{
- return null === $storeId || $storeId == Store::DEFAULT_STORE_ID;
+ return $this->getProductScopeRewriteGenerator()->isGlobalScope($storeId);
}
/**
* Generate list of urls for global scope
*
+ * @deprecated
* @param \Magento\Framework\Data\Collection $productCategories
* @return \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[]
*/
protected function generateForGlobalScope($productCategories)
{
- $urls = [];
- $productId = $this->product->getEntityId();
- foreach ($this->product->getStoreIds() as $id) {
- if (!$this->isGlobalScope($id)
- && !$this->storeViewService->doesEntityHaveOverriddenUrlKeyForStore($id, $productId, Product::ENTITY)
- ) {
- $urls = array_merge($urls, $this->generateForSpecificStoreView($id, $productCategories));
- }
- }
- return $urls;
+ return $this->getProductScopeRewriteGenerator()->generateForGlobalScope($productCategories, $this->product);
}
/**
* Generate list of urls for specific store view
*
+ * @deprecated
* @param int $storeId
* @param \Magento\Framework\Data\Collection $productCategories
* @return \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[]
*/
protected function generateForSpecificStoreView($storeId, $productCategories)
{
- $categories = [];
- foreach ($productCategories as $category) {
- if ($this->isCategoryProperForGenerating($category, $storeId)) {
- $categories[] = $category;
- }
- }
- $this->productCategories = $this->objectRegistryFactory->create(['entities' => $categories]);
- /**
- * @var $urls \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[]
- */
- $urls = array_merge(
- $this->canonicalUrlRewriteGenerator->generate($storeId, $this->product),
- $this->categoriesUrlRewriteGenerator->generate($storeId, $this->product, $this->productCategories),
- $this->currentUrlRewritesRegenerator->generate($storeId, $this->product, $this->productCategories),
- $this->getAnchorUrlRewriteGenerator()->generate($storeId, $this->product, $this->productCategories)
- );
-
- /* Reduce duplicates. Last wins */
- $result = [];
- foreach ($urls as $url) {
- $result[$url->getTargetPath() . '-' . $url->getStoreId()] = $url;
- }
- $this->productCategories = null;
- return $result;
+ return $this->getProductScopeRewriteGenerator()
+ ->generateForSpecificStoreView($storeId, $productCategories, $this->product);
}
/**
+ * @deprecated
* @param \Magento\Catalog\Model\Category $category
* @param int $storeId
* @return bool
*/
protected function isCategoryProperForGenerating($category, $storeId)
{
- if ($category->getParentId() != \Magento\Catalog\Model\Category::TREE_ROOT_ID) {
- list(, $rootCategoryId) = $category->getParentIds();
- return $rootCategoryId == $this->storeManager->getStore($storeId)->getRootCategoryId();
- }
- return false;
+ return $this->getProductScopeRewriteGenerator()->isCategoryProperForGenerating($category, $storeId);
}
}
diff --git a/app/code/Magento/CatalogUrlRewrite/Model/UrlRewriteBunchReplacer.php b/app/code/Magento/CatalogUrlRewrite/Model/UrlRewriteBunchReplacer.php
new file mode 100644
index 0000000000000..eb799dfe5991a
--- /dev/null
+++ b/app/code/Magento/CatalogUrlRewrite/Model/UrlRewriteBunchReplacer.php
@@ -0,0 +1,38 @@
+urlPersist = $urlPersist;
+ }
+
+ /**
+ * Do Bunch Replace, with default bunch value = 10000
+ *
+ * @param array $urls
+ * @param int $bunchSize
+ * @return void
+ */
+ public function doBunchReplace(array $urls, $bunchSize = 10000)
+ {
+ foreach (array_chunk($urls, $bunchSize) as $urlsBunch) {
+ $this->urlPersist->replace($urlsBunch);
+ }
+ }
+}
diff --git a/app/code/Magento/CatalogUrlRewrite/Observer/CategoryProcessUrlRewriteMovingObserver.php b/app/code/Magento/CatalogUrlRewrite/Observer/CategoryProcessUrlRewriteMovingObserver.php
index c891ab403f81b..24126015e3b08 100644
--- a/app/code/Magento/CatalogUrlRewrite/Observer/CategoryProcessUrlRewriteMovingObserver.php
+++ b/app/code/Magento/CatalogUrlRewrite/Observer/CategoryProcessUrlRewriteMovingObserver.php
@@ -8,7 +8,9 @@
use Magento\Catalog\Model\Category;
use Magento\CatalogUrlRewrite\Block\UrlKeyRenderer;
use Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGenerator;
+use Magento\CatalogUrlRewrite\Model\UrlRewriteBunchReplacer;
use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Framework\App\ObjectManager;
use Magento\Store\Model\ScopeInterface;
use Magento\UrlRewrite\Model\UrlPersistInterface;
use Magento\Framework\Event\ObserverInterface;
@@ -27,6 +29,11 @@ class CategoryProcessUrlRewriteMovingObserver implements ObserverInterface
/** @var UrlRewriteHandler */
protected $urlRewriteHandler;
+ /**
+ * @var UrlRewriteBunchReplacer
+ */
+ private $urlRewriteBunchReplacer;
+
/**
* @param CategoryUrlRewriteGenerator $categoryUrlRewriteGenerator
* @param UrlPersistInterface $urlPersist
@@ -45,6 +52,21 @@ public function __construct(
$this->urlRewriteHandler = $urlRewriteHandler;
}
+ /**
+ * Retrieve Url Rewrite Replacer based on bunches
+ *
+ * @deprecated
+ * @return UrlRewriteBunchReplacer
+ */
+ private function getUrlRewriteBunchReplacer()
+ {
+ if (!$this->urlRewriteBunchReplacer) {
+ $this->urlRewriteBunchReplacer = ObjectManager::getInstance()->get(UrlRewriteBunchReplacer::class);
+ }
+
+ return $this->urlRewriteBunchReplacer;
+ }
+
/**
* @param \Magento\Framework\Event\Observer $observer
* @return void
@@ -65,7 +87,7 @@ public function execute(\Magento\Framework\Event\Observer $observer)
$this->urlRewriteHandler->generateProductUrlRewrites($category)
);
$this->urlRewriteHandler->deleteCategoryRewritesForChildren($category);
- $this->urlPersist->replace($urlRewrites);
+ $this->getUrlRewriteBunchReplacer()->doBunchReplace($urlRewrites);
}
}
}
diff --git a/app/code/Magento/CatalogUrlRewrite/Observer/CategoryProcessUrlRewriteSavingObserver.php b/app/code/Magento/CatalogUrlRewrite/Observer/CategoryProcessUrlRewriteSavingObserver.php
index 806cfb8edb729..fe86bc363b49c 100644
--- a/app/code/Magento/CatalogUrlRewrite/Observer/CategoryProcessUrlRewriteSavingObserver.php
+++ b/app/code/Magento/CatalogUrlRewrite/Observer/CategoryProcessUrlRewriteSavingObserver.php
@@ -7,6 +7,8 @@
use Magento\Catalog\Model\Category;
use Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGenerator;
+use Magento\CatalogUrlRewrite\Model\UrlRewriteBunchReplacer;
+use Magento\Framework\App\ObjectManager;
use Magento\UrlRewrite\Model\UrlPersistInterface;
use Magento\Framework\Event\ObserverInterface;
@@ -18,6 +20,11 @@ class CategoryProcessUrlRewriteSavingObserver implements ObserverInterface
/** @var UrlPersistInterface */
protected $urlPersist;
+ /**
+ * @var UrlRewriteBunchReplacer
+ */
+ private $urlRewriteBunchReplacer;
+
/** @var UrlRewriteHandler */
protected $urlRewriteHandler;
@@ -36,6 +43,21 @@ public function __construct(
$this->urlRewriteHandler = $urlRewriteHandler;
}
+ /**
+ * Retrieve Url Rewrite Replacer based on bunches
+ *
+ * @deprecated
+ * @return UrlRewriteBunchReplacer
+ */
+ private function getUrlRewriteBunchReplacer()
+ {
+ if (!$this->urlRewriteBunchReplacer) {
+ $this->urlRewriteBunchReplacer = ObjectManager::getInstance()->get(UrlRewriteBunchReplacer::class);
+ }
+
+ return $this->urlRewriteBunchReplacer;
+ }
+
/**
* Generate urls for UrlRewrite and save it in storage
*
@@ -57,7 +79,8 @@ public function execute(\Magento\Framework\Event\Observer $observer)
$this->categoryUrlRewriteGenerator->generate($category),
$this->urlRewriteHandler->generateProductUrlRewrites($category)
);
- $this->urlPersist->replace($urlRewrites);
+
+ $this->getUrlRewriteBunchReplacer()->doBunchReplace($urlRewrites);
}
}
}
diff --git a/app/code/Magento/CatalogUrlRewrite/Observer/UrlRewriteHandler.php b/app/code/Magento/CatalogUrlRewrite/Observer/UrlRewriteHandler.php
index b02ef76d95146..ff914dc1adb20 100644
--- a/app/code/Magento/CatalogUrlRewrite/Observer/UrlRewriteHandler.php
+++ b/app/code/Magento/CatalogUrlRewrite/Observer/UrlRewriteHandler.php
@@ -6,8 +6,10 @@
namespace Magento\CatalogUrlRewrite\Observer;
use Magento\Catalog\Model\Category;
+use Magento\CatalogUrlRewrite\Model\CategoryBasedProductRewriteGenerator;
use Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGenerator;
use Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator;
+use Magento\Framework\App\ObjectManager;
use Magento\Framework\Event\Observer as EventObserver;
use Magento\UrlRewrite\Model\UrlPersistInterface;
use Magento\UrlRewrite\Service\V1\Data\UrlRewrite;
@@ -32,6 +34,11 @@ class UrlRewriteHandler
/** @var \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory */
protected $productCollectionFactory;
+ /**
+ * @var CategoryBasedProductRewriteGenerator
+ */
+ private $categoryBasedProductRewriteGenerator;
+
/**
* @param \Magento\CatalogUrlRewrite\Model\Category\ChildrenCategoriesProvider $childrenCategoriesProvider
* @param CategoryUrlRewriteGenerator $categoryUrlRewriteGenerator
@@ -116,11 +123,30 @@ public function getCategoryProductsUrlRewrites(Category $category, $storeId, $sa
$this->isSkippedProduct[] = $product->getId();
$product->setStoreId($storeId);
$product->setData('save_rewrites_history', $saveRewriteHistory);
- $productUrls = array_merge($productUrls, $this->productUrlRewriteGenerator->generate($product));
+ $productUrls = array_merge(
+ $productUrls,
+ $this->getCategoryBasedProductRewriteGenerator()->generate($product, $category)
+ );
}
return $productUrls;
}
+ /**
+ * Retrieve generator, which use single category for different products
+ *
+ * @deprecated
+ * @return CategoryBasedProductRewriteGenerator|mixed
+ */
+ private function getCategoryBasedProductRewriteGenerator()
+ {
+ if (!$this->categoryBasedProductRewriteGenerator) {
+ $this->categoryBasedProductRewriteGenerator = ObjectManager::getInstance()
+ ->get(CategoryBasedProductRewriteGenerator::class);
+ }
+
+ return $this->categoryBasedProductRewriteGenerator;
+ }
+
/**
* @param Category $category
* @return void
diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/CategoryBasedProductRewriteGeneratorTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/CategoryBasedProductRewriteGeneratorTest.php
new file mode 100644
index 0000000000000..c62475f3cc7cf
--- /dev/null
+++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/CategoryBasedProductRewriteGeneratorTest.php
@@ -0,0 +1,97 @@
+productScopeRewriteGeneratorMock = $this->getMockBuilder(ProductScopeRewriteGenerator::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->generator = new CategoryBasedProductRewriteGenerator(
+ $this->productScopeRewriteGeneratorMock
+ );
+ }
+
+ public function testGenerationWithGlobalScope()
+ {
+ $categoryMock = $this->getMockBuilder(Category::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $productMock = $this->getMockBuilder(Product::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $storeId = 1;
+ $urls = ['dummy-url.html'];
+
+ $productMock->expects($this->once())
+ ->method('getVisibility')
+ ->willReturn(2);
+ $productMock->expects($this->once())
+ ->method('getStoreId')
+ ->willReturn($storeId);
+ $this->productScopeRewriteGeneratorMock->expects($this->once())
+ ->method('isGlobalScope')
+ ->with($storeId)
+ ->willReturn(true);
+ $this->productScopeRewriteGeneratorMock->expects($this->once())
+ ->method('generateForGlobalScope')
+ ->with([$categoryMock], $productMock)
+ ->willReturn($urls);
+
+ $this->assertEquals($urls, $this->generator->generate($productMock, $categoryMock));
+ }
+
+ public function testGenerationWithSpecificStore()
+ {
+ $categoryMock = $this->getMockBuilder(Category::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $productMock = $this->getMockBuilder(Product::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $storeId = 1;
+ $urls = ['dummy-url.html'];
+
+ $productMock->expects($this->once())
+ ->method('getVisibility')
+ ->willReturn(2);
+ $productMock->expects($this->once())
+ ->method('getStoreId')
+ ->willReturn($storeId);
+ $this->productScopeRewriteGeneratorMock->expects($this->once())
+ ->method('isGlobalScope')
+ ->with($storeId)
+ ->willReturn(false);
+ $this->productScopeRewriteGeneratorMock->expects($this->once())
+ ->method('generateForSpecificStoreView')
+ ->with($storeId, [$categoryMock], $productMock)
+ ->willReturn($urls);
+
+ $this->assertEquals($urls, $this->generator->generate($productMock, $categoryMock));
+ }
+}
diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductScopeRewriteGeneratorTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductScopeRewriteGeneratorTest.php
new file mode 100644
index 0000000000000..99bb858e31b8f
--- /dev/null
+++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductScopeRewriteGeneratorTest.php
@@ -0,0 +1,182 @@
+currentUrlRewritesRegenerator = $this->getMockBuilder(
+ \Magento\CatalogUrlRewrite\Model\Product\CurrentUrlRewritesRegenerator::class
+ )->disableOriginalConstructor()->getMock();
+ $this->canonicalUrlRewriteGenerator = $this->getMockBuilder(
+ \Magento\CatalogUrlRewrite\Model\Product\CanonicalUrlRewriteGenerator::class
+ )->disableOriginalConstructor()->getMock();
+ $this->categoriesUrlRewriteGenerator = $this->getMockBuilder(
+ \Magento\CatalogUrlRewrite\Model\Product\CategoriesUrlRewriteGenerator::class
+ )->disableOriginalConstructor()->getMock();
+ $this->anchorUrlRewriteGenerator = $this->getMockBuilder(
+ \Magento\CatalogUrlRewrite\Model\Product\AnchorUrlRewriteGenerator::class
+ )->disableOriginalConstructor()->getMock();
+ $this->objectRegistryFactory = $this->getMockBuilder(
+ \Magento\CatalogUrlRewrite\Model\ObjectRegistryFactory::class
+ )->disableOriginalConstructor()->setMethods(['create'])->getMock();
+ $this->storeViewService = $this->getMockBuilder(\Magento\CatalogUrlRewrite\Service\V1\StoreViewService::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->storeManager = $this->getMock(StoreManagerInterface::class);
+
+ $this->productScopeGenerator = (new ObjectManager($this))->getObject(
+ \Magento\CatalogUrlRewrite\Model\ProductScopeRewriteGenerator::class,
+ [
+ 'canonicalUrlRewriteGenerator' => $this->canonicalUrlRewriteGenerator,
+ 'categoriesUrlRewriteGenerator' => $this->categoriesUrlRewriteGenerator,
+ 'currentUrlRewritesRegenerator' => $this->currentUrlRewritesRegenerator,
+ 'anchorUrlRewriteGenerator' => $this->anchorUrlRewriteGenerator,
+ 'objectRegistryFactory' => $this->objectRegistryFactory,
+ 'storeViewService' => $this->storeViewService,
+ 'storeManager' => $this->storeManager,
+ ]
+ );
+ }
+
+ public function testGenerationForGlobalScope()
+ {
+ $product = $this->getMock(\Magento\Catalog\Model\Product::class, [], [], '', false);
+ $product->expects($this->any())->method('getStoreId')->will($this->returnValue(null));
+ $product->expects($this->any())->method('getStoreIds')->will($this->returnValue([1]));
+ $this->storeViewService->expects($this->once())->method('doesEntityHaveOverriddenUrlKeyForStore')
+ ->will($this->returnValue(false));
+ $categoryMock = $this->getMockBuilder(Category::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $categoryMock->expects($this->once())
+ ->method('getParentId')
+ ->willReturn(1);
+ $this->initObjectRegistryFactory([]);
+ $canonical = new \Magento\UrlRewrite\Service\V1\Data\UrlRewrite();
+ $canonical->setTargetPath('category-1')
+ ->setStoreId(1);
+ $this->canonicalUrlRewriteGenerator->expects($this->any())->method('generate')
+ ->will($this->returnValue([$canonical]));
+ $categories = new \Magento\UrlRewrite\Service\V1\Data\UrlRewrite();
+ $categories->setTargetPath('category-2')
+ ->setStoreId(2);
+ $this->categoriesUrlRewriteGenerator->expects($this->any())->method('generate')
+ ->will($this->returnValue([$categories]));
+ $current = new \Magento\UrlRewrite\Service\V1\Data\UrlRewrite();
+ $current->setTargetPath('category-3')
+ ->setStoreId(3);
+ $this->currentUrlRewritesRegenerator->expects($this->any())->method('generate')
+ ->will($this->returnValue([$current]));
+ $anchorCategories = new \Magento\UrlRewrite\Service\V1\Data\UrlRewrite();
+ $anchorCategories->setTargetPath('category-4')
+ ->setStoreId(4);
+ $this->anchorUrlRewriteGenerator->expects($this->any())->method('generate')
+ ->will($this->returnValue([$anchorCategories]));
+
+ $this->assertEquals(
+ [
+ 'category-1-1' => $canonical,
+ 'category-2-2' => $categories,
+ 'category-3-3' => $current,
+ 'category-4-4' => $anchorCategories
+ ],
+ $this->productScopeGenerator->generateForGlobalScope([$categoryMock], $product)
+ );
+ }
+
+ public function testGenerationForSpecificStore()
+ {
+ $product = $this->getMock(\Magento\Catalog\Model\Product::class, [], [], '', false);
+ $product->expects($this->any())->method('getStoreId')->will($this->returnValue(1));
+ $product->expects($this->never())->method('getStoreIds');
+ $storeRootCategoryId = 'root-for-store-id';
+ $category = $this->getMock(\Magento\Catalog\Model\Category::class, [], [], '', false);
+ $category->expects($this->any())->method('getParentIds')
+ ->will($this->returnValue(['root-id', $storeRootCategoryId]));
+ $category->expects($this->any())->method('getParentId')->will($this->returnValue('parent_id'));
+ $category->expects($this->any())->method('getId')->will($this->returnValue('category_id'));
+ $store = $this->getMockBuilder(\Magento\Store\Model\Store::class)->disableOriginalConstructor()->getMock();
+ $store->expects($this->any())->method('getRootCategoryId')->will($this->returnValue($storeRootCategoryId));
+ $this->storeManager->expects($this->any())->method('getStore')->will($this->returnValue($store));
+ $this->initObjectRegistryFactory([$category]);
+ $canonical = new \Magento\UrlRewrite\Service\V1\Data\UrlRewrite();
+ $canonical->setTargetPath('category-1')
+ ->setStoreId(1);
+ $this->canonicalUrlRewriteGenerator->expects($this->any())->method('generate')
+ ->will($this->returnValue([$canonical]));
+ $this->categoriesUrlRewriteGenerator->expects($this->any())->method('generate')
+ ->will($this->returnValue([]));
+ $this->currentUrlRewritesRegenerator->expects($this->any())->method('generate')
+ ->will($this->returnValue([]));
+ $this->anchorUrlRewriteGenerator->expects($this->any())->method('generate')
+ ->will($this->returnValue([]));
+
+ $this->assertEquals(
+ ['category-1-1' => $canonical],
+ $this->productScopeGenerator->generateForSpecificStoreView(1, [$category], $product)
+ );
+ }
+
+ /**
+ * Test method
+ */
+ public function testSkipGenerationForGlobalScope()
+ {
+ $product = $this->getMock(\Magento\Catalog\Model\Product::class, [], [], '', false);
+ $product->expects($this->any())->method('getStoreIds')->will($this->returnValue([1, 2]));
+ $this->storeViewService->expects($this->exactly(2))->method('doesEntityHaveOverriddenUrlKeyForStore')
+ ->will($this->returnValue(true));
+
+ $this->assertEquals([], $this->productScopeGenerator->generateForGlobalScope([], $product));
+ }
+
+ /**
+ * @param array $entities
+ */
+ protected function initObjectRegistryFactory($entities)
+ {
+ $objectRegistry = $this->getMockBuilder(\Magento\CatalogUrlRewrite\Model\ObjectRegistry::class)
+ ->disableOriginalConstructor()->getMock();
+ $this->objectRegistryFactory->expects($this->any())->method('create')
+ ->with(['entities' => $entities])
+ ->will($this->returnValue($objectRegistry));
+ }
+}
diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductUrlRewriteGeneratorTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductUrlRewriteGeneratorTest.php
index 4086fe256790b..d88171b90bbee 100644
--- a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductUrlRewriteGeneratorTest.php
+++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductUrlRewriteGeneratorTest.php
@@ -9,6 +9,8 @@
namespace Magento\CatalogUrlRewrite\Test\Unit\Model;
use Magento\Catalog\Model\Category;
+use Magento\Catalog\Model\Product;
+use Magento\CatalogUrlRewrite\Model\ProductScopeRewriteGenerator;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
/**
@@ -46,6 +48,9 @@ class ProductUrlRewriteGeneratorTest extends \PHPUnit_Framework_TestCase
/** @var \Magento\Catalog\Model\ResourceModel\Category\Collection|\PHPUnit_Framework_MockObject_MockObject */
protected $categoriesCollection;
+ /** @var \PHPUnit_Framework_MockObject_MockObject */
+ private $productScopeRewriteGenerator;
+
/**
* Test method
*/
@@ -59,8 +64,6 @@ protected function setUp()
->will($this->returnValue($this->categoriesCollection));
$this->storeManager = $this->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class)
->disableOriginalConstructor()->getMock();
- $this->categoriesCollection->expects($this->exactly(2))->method('addAttributeToSelect')
- ->will($this->returnSelf());
$this->currentUrlRewritesRegenerator = $this->getMockBuilder(
\Magento\CatalogUrlRewrite\Model\Product\CurrentUrlRewritesRegenerator::class
)->disableOriginalConstructor()->getMock();
@@ -78,7 +81,9 @@ protected function setUp()
)->disableOriginalConstructor()->setMethods(['create'])->getMock();
$this->storeViewService = $this->getMockBuilder(\Magento\CatalogUrlRewrite\Service\V1\StoreViewService::class)
->disableOriginalConstructor()->getMock();
-
+ $this->productScopeRewriteGenerator = $this->getMockBuilder(
+ ProductScopeRewriteGenerator::class
+ )->disableOriginalConstructor()->getMock();
$this->productUrlRewriteGenerator = (new ObjectManager($this))->getObject(
\Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator::class,
[
@@ -92,172 +97,38 @@ protected function setUp()
);
$reflection = new \ReflectionClass(get_class($this->productUrlRewriteGenerator));
- $reflectionProperty = $reflection->getProperty('anchorUrlRewriteGenerator');
+ $reflectionProperty = $reflection->getProperty('productScopeRewriteGenerator');
$reflectionProperty->setAccessible(true);
- $reflectionProperty->setValue($this->productUrlRewriteGenerator, $this->anchorUrlRewriteGenerator);
- }
-
- /**
- * Test method
- */
- public function testGenerationForGlobalScope()
- {
- $this->product->expects($this->any())->method('getStoreId')->will($this->returnValue(null));
- $this->product->expects($this->any())->method('getStoreIds')->will($this->returnValue([1]));
- $this->storeViewService->expects($this->once())->method('doesEntityHaveOverriddenUrlKeyForStore')
- ->will($this->returnValue(false));
- $this->categoriesCollection->expects($this->any())->method('getIterator')
- ->willReturn(new \ArrayIterator([]));
- $this->initObjectRegistryFactory([]);
- $canonical = new \Magento\UrlRewrite\Service\V1\Data\UrlRewrite();
- $canonical->setTargetPath('category-1')
- ->setStoreId(1);
- $this->canonicalUrlRewriteGenerator->expects($this->any())->method('generate')
- ->will($this->returnValue([$canonical]));
- $categories = new \Magento\UrlRewrite\Service\V1\Data\UrlRewrite();
- $categories->setTargetPath('category-2')
- ->setStoreId(2);
- $this->categoriesUrlRewriteGenerator->expects($this->any())->method('generate')
- ->will($this->returnValue([$categories]));
- $current = new \Magento\UrlRewrite\Service\V1\Data\UrlRewrite();
- $current->setTargetPath('category-3')
- ->setStoreId(3);
- $this->currentUrlRewritesRegenerator->expects($this->any())->method('generate')
- ->will($this->returnValue([$current]));
- $anchorCategories = new \Magento\UrlRewrite\Service\V1\Data\UrlRewrite();
- $anchorCategories->setTargetPath('category-4')
- ->setStoreId(4);
- $this->anchorUrlRewriteGenerator->expects($this->any())->method('generate')
- ->will($this->returnValue([$anchorCategories]));
-
- $this->assertEquals(
- [
- 'category-1-1' => $canonical,
- 'category-2-2' => $categories,
- 'category-3-3' => $current,
- 'category-4-4' => $anchorCategories
- ],
- $this->productUrlRewriteGenerator->generate($this->product)
- );
+ $reflectionProperty->setValue($this->productUrlRewriteGenerator, $this->productScopeRewriteGenerator);
}
- /**
- * Test method
- */
- public function testGenerationForSpecificStore()
- {
- $this->product->expects($this->any())->method('getStoreId')->will($this->returnValue(1));
- $this->product->expects($this->never())->method('getStoreIds');
- $storeRootCategoryId = 'root-for-store-id';
- $category = $this->getMock(\Magento\Catalog\Model\Category::class, [], [], '', false);
- $category->expects($this->any())->method('getParentIds')
- ->will($this->returnValue(['root-id', $storeRootCategoryId]));
- $category->expects($this->any())->method('getParentId')->will($this->returnValue('parent_id'));
- $category->expects($this->any())->method('getId')->will($this->returnValue('category_id'));
- $store = $this->getMockBuilder(\Magento\Store\Model\Store::class)->disableOriginalConstructor()->getMock();
- $store->expects($this->any())->method('getRootCategoryId')->will($this->returnValue($storeRootCategoryId));
- $this->storeManager->expects($this->any())->method('getStore')->will($this->returnValue($store));
- $this->categoriesCollection->expects($this->any())->method('getIterator')
- ->willReturn(new \ArrayIterator([$category]));
- $this->initObjectRegistryFactory([$category]);
- $canonical = new \Magento\UrlRewrite\Service\V1\Data\UrlRewrite();
- $canonical->setTargetPath('category-1')
- ->setStoreId(1);
- $this->canonicalUrlRewriteGenerator->expects($this->any())->method('generate')
- ->will($this->returnValue([$canonical]));
- $this->categoriesUrlRewriteGenerator->expects($this->any())->method('generate')
- ->will($this->returnValue([]));
- $this->currentUrlRewritesRegenerator->expects($this->any())->method('generate')
- ->will($this->returnValue([]));
- $this->anchorUrlRewriteGenerator->expects($this->any())->method('generate')
- ->will($this->returnValue([]));
-
- $this->assertEquals(['category-1-1' => $canonical], $this->productUrlRewriteGenerator->generate($this->product));
- }
-
- /**
- * Test method
- */
- public function testSkipRootCategoryForCategoriesGenerator()
+ public function testGenerate()
{
- $this->product->expects($this->any())->method('getStoreId')->will($this->returnValue(1));
- $this->product->expects($this->never())->method('getStoreIds');
- $store = $this->getMockBuilder(\Magento\Store\Model\Store::class)->disableOriginalConstructor()->getMock();
- $store->expects($this->any())->method('getRootCategoryId')->will($this->returnValue('root-for-store-id'));
- $this->storeManager->expects($this->any())->method('getStore')->will($this->returnValue($store));
- $rootCategory = $this->getMock(\Magento\Catalog\Model\Category::class, [], [], '', false);
- $rootCategory->expects($this->any())->method('getParentIds')->will($this->returnValue([1, 2]));
- $rootCategory->expects($this->any())->method('getParentId')->will($this->returnValue(Category::TREE_ROOT_ID));
- $this->categoriesCollection->expects($this->any())->method('getIterator')
- ->willReturn(new \ArrayIterator([$rootCategory]));
- $this->initObjectRegistryFactory([]);
- $canonical = new \Magento\UrlRewrite\Service\V1\Data\UrlRewrite();
- $canonical->setTargetPath('category-1')
- ->setStoreId(1);
- $this->canonicalUrlRewriteGenerator->expects($this->any())->method('generate')
- ->will($this->returnValue([$canonical]));
- $this->categoriesUrlRewriteGenerator->expects($this->any())->method('generate')
- ->will($this->returnValue([]));
- $this->currentUrlRewritesRegenerator->expects($this->any())->method('generate')
- ->will($this->returnValue([]));
- $this->anchorUrlRewriteGenerator->expects($this->any())->method('generate')
- ->will($this->returnValue([]));
-
- $this->assertEquals(['category-1-1' => $canonical], $this->productUrlRewriteGenerator->generate($this->product));
- }
-
- /**
- * Test method
- */
- public function testSkipGenerationForNotStoreRootCategory()
- {
- $this->product->expects($this->any())->method('getStoreId')->will($this->returnValue(1));
- $this->product->expects($this->never())->method('getStoreIds');
- $category = $this->getMock(\Magento\Catalog\Model\Category::class, [], [], '', false);
- $category->expects($this->any())->method('getParentIds')
- ->will($this->returnValue(['root-id', 'root-for-store-id']));
- $store = $this->getMockBuilder(\Magento\Store\Model\Store::class)->disableOriginalConstructor()->getMock();
- $store->expects($this->any())->method('getRootCategoryId')->will($this->returnValue('not-root-id'));
- $this->storeManager->expects($this->any())->method('getStore')->will($this->returnValue($store));
- $this->categoriesCollection->expects($this->any())->method('getIterator')
- ->willReturn(new \ArrayIterator([$category]));
- $this->initObjectRegistryFactory([]);
- $canonical = new \Magento\UrlRewrite\Service\V1\Data\UrlRewrite();
- $canonical->setTargetPath('category-1')
- ->setStoreId(1);
- $this->canonicalUrlRewriteGenerator->expects($this->any())->method('generate')
- ->will($this->returnValue([$canonical]));
- $this->categoriesUrlRewriteGenerator->expects($this->any())->method('generate')
- ->will($this->returnValue([]));
- $this->currentUrlRewritesRegenerator->expects($this->any())->method('generate')
- ->will($this->returnValue([]));
- $this->anchorUrlRewriteGenerator->expects($this->any())->method('generate')
- ->will($this->returnValue([]));
-
- $this->assertEquals(['category-1-1' => $canonical], $this->productUrlRewriteGenerator->generate($this->product));
- }
-
- /**
- * Test method
- */
- public function testSkipGenerationForGlobalScope()
- {
- $this->product->expects($this->any())->method('getStoreIds')->will($this->returnValue([1, 2]));
- $this->storeViewService->expects($this->exactly(2))->method('doesEntityHaveOverriddenUrlKeyForStore')
- ->will($this->returnValue(true));
-
- $this->assertEquals([], $this->productUrlRewriteGenerator->generate($this->product));
- }
-
- /**
- * @param array $entities
- */
- protected function initObjectRegistryFactory($entities)
- {
- $objectRegistry = $this->getMockBuilder(\Magento\CatalogUrlRewrite\Model\ObjectRegistry::class)
- ->disableOriginalConstructor()->getMock();
- $this->objectRegistryFactory->expects($this->any())->method('create')
- ->with(['entities' => $entities])
- ->will($this->returnValue($objectRegistry));
+ $productMock = $this->getMockBuilder(Product::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $storeId = 1;
+ $urls = ['dummy-url.html'];
+
+ $productMock->expects($this->once())
+ ->method('getVisibility')
+ ->willReturn(2);
+ $productMock->expects($this->once())
+ ->method('getStoreId')
+ ->willReturn($storeId);
+ $productCategoriesMock = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Category\Collection::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $productCategoriesMock->expects($this->exactly(2))
+ ->method('addAttributeToSelect')
+ ->withConsecutive(['url_key'], ['url_path'])
+ ->willReturnSelf();
+ $productMock->expects($this->once())
+ ->method('getCategoryCollection')
+ ->willReturn($productCategoriesMock);
+ $this->productScopeRewriteGenerator->expects($this->once())
+ ->method('generateForSpecificStoreView')
+ ->willReturn($urls);
+ $this->assertEquals($urls, $this->productUrlRewriteGenerator->generate($productMock));
}
}
diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/UrlRewriteBunchReplacerTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/UrlRewriteBunchReplacerTest.php
new file mode 100644
index 0000000000000..7a44cc5d6f972
--- /dev/null
+++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/UrlRewriteBunchReplacerTest.php
@@ -0,0 +1,39 @@
+urlPersistMock = $this->getMock(UrlPersistInterface::class);
+ $this->urlRewriteBunchReplacer = new UrlRewriteBunchReplacer(
+ $this->urlPersistMock
+ );
+ }
+
+ public function testDoBunchReplace()
+ {
+ $urls = [[1], [2]];
+ $this->urlPersistMock->expects($this->exactly(2))
+ ->method('replace')
+ ->withConsecutive([[[1]]], [[[2]]]);
+ $this->urlRewriteBunchReplacer->doBunchReplace($urls, 1);
+ }
+}
diff --git a/app/code/Magento/Cms/Controller/Adminhtml/Page/InlineEdit.php b/app/code/Magento/Cms/Controller/Adminhtml/Page/InlineEdit.php
index c2e26220aee46..d317e55127a89 100644
--- a/app/code/Magento/Cms/Controller/Adminhtml/Page/InlineEdit.php
+++ b/app/code/Magento/Cms/Controller/Adminhtml/Page/InlineEdit.php
@@ -17,6 +17,11 @@
*/
class InlineEdit extends \Magento\Backend\App\Action
{
+ /**
+ * Authorization level of a basic admin session
+ */
+ const ADMIN_RESOURCE = 'Magento_Cms::save';
+
/** @var PostDataProcessor */
protected $dataProcessor;
diff --git a/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/DataProviderTest.php b/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/DataProviderTest.php
new file mode 100644
index 0000000000000..70fef18f3a77d
--- /dev/null
+++ b/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/DataProviderTest.php
@@ -0,0 +1,135 @@
+authorizationMock = $this->getMockBuilder(Authorization::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->reportingMock = $this->getMockBuilder(Reporting::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->searchCriteriaBuilderMock = $this->getMockBuilder(SearchCriteriaBuilder::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->requestInterfaceMock = $this->getMockBuilder(RequestInterface::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->filterBuilderMock = $this->getMockBuilder(FilterBuilder::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ /** @var ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject $objectManagerMock */
+ $objectManagerMock = $this->getMock(ObjectManagerInterface::class);
+ $objectManagerMock->expects($this->once())
+ ->method('get')
+ ->willReturn($this->authorizationMock);
+ ObjectManager::setInstance($objectManagerMock);
+
+ $this->dataProvider = new DataProvider(
+ $this->name,
+ $this->primaryFieldName,
+ $this->requestFieldName,
+ $this->reportingMock,
+ $this->searchCriteriaBuilderMock,
+ $this->requestInterfaceMock,
+ $this->filterBuilderMock
+ );
+ }
+
+ /**
+ * @covers \Magento\Cms\Ui\Component\DataProvider::prepareMetadata
+ */
+ public function testPrepareMetadata()
+ {
+ $this->authorizationMock->expects($this->once())
+ ->method('isAllowed')
+ ->with('Magento_Cms::save')
+ ->willReturn(false);
+
+ $metadata = [
+ 'cms_page_columns' => [
+ 'arguments' => [
+ 'data' => [
+ 'config' => [
+ 'editorConfig' => [
+ 'enabled' => false
+ ]
+ ]
+ ]
+ ]
+ ]
+ ];
+
+ $this->assertEquals(
+ $metadata,
+ $this->dataProvider->prepareMetadata()
+ );
+
+ }
+}
diff --git a/app/code/Magento/Cms/Ui/Component/DataProvider.php b/app/code/Magento/Cms/Ui/Component/DataProvider.php
index 53ba80e6ccb73..85b00d341fad8 100644
--- a/app/code/Magento/Cms/Ui/Component/DataProvider.php
+++ b/app/code/Magento/Cms/Ui/Component/DataProvider.php
@@ -7,11 +7,18 @@
use Magento\Framework\Api\FilterBuilder;
use Magento\Framework\Api\Search\SearchCriteriaBuilder;
+use Magento\Framework\App\ObjectManager;
use Magento\Framework\App\RequestInterface;
+use Magento\Framework\AuthorizationInterface;
use Magento\Framework\View\Element\UiComponent\DataProvider\Reporting;
class DataProvider extends \Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider
{
+ /**
+ * @var AuthorizationInterface
+ */
+ private $authorization;
+
/**
* @param string $name
* @param string $primaryFieldName
@@ -45,5 +52,47 @@ public function __construct(
$meta,
$data
);
+
+ $this->meta = array_replace_recursive($meta, $this->prepareMetadata());
+ }
+
+ /**
+ * @deprecated
+ * @return AuthorizationInterface|mixed
+ */
+ private function getAuthorizationInstance()
+ {
+ if ($this->authorization === null) {
+ $this->authorization = ObjectManager::getInstance()->get(AuthorizationInterface::class);
+ }
+ return $this->authorization;
+ }
+
+ /**
+ * Prepares Meta
+ *
+ * @return array
+ */
+ public function prepareMetadata()
+ {
+ $metadata = [];
+
+ if (!$this->getAuthorizationInstance()->isAllowed('Magento_Cms::save')) {
+ $metadata = [
+ 'cms_page_columns' => [
+ 'arguments' => [
+ 'data' => [
+ 'config' => [
+ 'editorConfig' => [
+ 'enabled' => false
+ ]
+ ]
+ ]
+ ]
+ ]
+ ];
+ }
+
+ return $metadata;
}
}
diff --git a/app/code/Magento/Ui/Component/Form/Element/DataType/Date.php b/app/code/Magento/Ui/Component/Form/Element/DataType/Date.php
index c074fcc056fc3..de363262275e5 100644
--- a/app/code/Magento/Ui/Component/Form/Element/DataType/Date.php
+++ b/app/code/Magento/Ui/Component/Form/Element/DataType/Date.php
@@ -32,8 +32,6 @@ class Date extends AbstractDataType
protected $wrappedComponent;
/**
- * Constructor
- *
* @param ContextInterface $context
* @param TimezoneInterface $localeDate
* @param ResolverInterface $localeResolver
@@ -70,6 +68,11 @@ public function prepare()
))->getOffset();
}
+ // Set date format pattern by current locale
+ $localeDateFormat = $this->localeDate->getDateFormat();
+ $config['options']['dateFormat'] = $localeDateFormat;
+ $config['outputDateFormat'] = $localeDateFormat;
+
$this->setData('config', $config);
parent::prepare();
diff --git a/app/code/Magento/Ui/Test/Unit/Component/Form/Element/DataType/DateTest.php b/app/code/Magento/Ui/Test/Unit/Component/Form/Element/DataType/DateTest.php
new file mode 100644
index 0000000000000..ef0743aa32947
--- /dev/null
+++ b/app/code/Magento/Ui/Test/Unit/Component/Form/Element/DataType/DateTest.php
@@ -0,0 +1,126 @@
+getMockBuilder(\Magento\Framework\View\Element\UiComponent\Processor::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->context = $this->getMockBuilder(\Magento\Framework\View\Element\UiComponent\ContextInterface::class)
+ ->getMockForAbstractClass();
+ $this->context->expects($this->any())
+ ->method('getProcessor')
+ ->willReturn($processorMock);
+
+ $this->localeDate = $this->getMockBuilder(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::class)
+ ->getMockForAbstractClass();
+
+ $this->localeResolver = $this->getMockBuilder(\Magento\Framework\Locale\ResolverInterface::class)
+ ->getMockForAbstractClass();
+ }
+
+ public function testPrepareWithTimeOffset()
+ {
+ $this->model = new Date(
+ $this->context,
+ $this->localeDate,
+ $this->localeResolver,
+ [],
+ [
+ 'config' => [
+ 'timeOffset' => 1,
+ ],
+ ]
+ );
+
+ $localeDateFormat = 'dd/MM/y';
+
+ $this->localeDate->expects($this->once())
+ ->method('getDateFormat')
+ ->willReturn($localeDateFormat);
+
+ $this->model->prepare();
+
+ $config = $this->model->getConfig();
+ $this->assertTrue(is_array($config));
+
+ $this->assertArrayHasKey('options', $config);
+ $this->assertArrayHasKey('dateFormat', $config['options']);
+ $this->assertEquals($localeDateFormat, $config['options']['dateFormat']);
+
+ $this->assertArrayHasKey('outputDateFormat', $config);
+ $this->assertEquals($localeDateFormat, $config['outputDateFormat']);
+ }
+
+ public function testPrepareWithoutTimeOffset()
+ {
+ $defaultDateFormat = 'MM/dd/y';
+
+ $this->model = new Date(
+ $this->context,
+ $this->localeDate,
+ $this->localeResolver,
+ [],
+ [
+ 'config' => [
+ 'options' => [
+ 'dateFormat' => $defaultDateFormat,
+ ],
+ 'outputDateFormat' => $defaultDateFormat,
+ ],
+ ]
+ );
+
+ $localeDateFormat = 'dd/MM/y';
+
+ $this->localeDate->expects($this->once())
+ ->method('getDateFormat')
+ ->willReturn($localeDateFormat);
+ $this->localeDate->expects($this->once())
+ ->method('getConfigTimezone')
+ ->willReturn('America/Los_Angeles');
+
+ $this->model->prepare();
+
+ $config = $this->model->getConfig();
+ $this->assertTrue(is_array($config));
+
+ $this->assertArrayHasKey('timeOffset', $config);
+
+ $this->assertArrayHasKey('options', $config);
+ $this->assertArrayHasKey('dateFormat', $config['options']);
+ $this->assertEquals($localeDateFormat, $config['options']['dateFormat']);
+
+ $this->assertArrayHasKey('outputDateFormat', $config);
+ $this->assertEquals($localeDateFormat, $config['outputDateFormat']);
+ }
+}
diff --git a/app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/datepicker.js b/app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/datepicker.js
index 8f0fb7b007caf..16c102b8367f4 100644
--- a/app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/datepicker.js
+++ b/app/code/Magento/Ui/view/base/web/js/lib/knockout/bindings/datepicker.js
@@ -8,8 +8,10 @@ define([
'underscore',
'jquery',
'mage/translate',
- 'mage/calendar'
-], function (ko, _, $, $t) {
+ 'mage/calendar',
+ 'moment',
+ 'mageUtils'
+], function (ko, _, $, $t, calendar, moment, utils) {
'use strict';
var defaults = {
@@ -46,7 +48,12 @@ define([
}
$(el).calendar(options);
- observable() && $(el).datepicker('setDate', observable());
+
+ observable() && $(el).datepicker(
+ 'setDate',
+ moment(observable(), utils.normalizeDate(config.options.dateFormat)).toDate()
+ );
+
$(el).blur();
ko.utils.registerEventHandler(el, 'change', function () {
diff --git a/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js b/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js
index 71f2834190436..aa30cf24805f0 100644
--- a/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js
+++ b/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js
@@ -9,8 +9,9 @@ define([
'moment',
'jquery/validate',
'jquery/ui',
- 'mage/translate'
-], function ($, _, utils, moment) {
+ 'mage/translate',
+ 'mageUtils'
+], function ($, _, utils, moment, validate, ui, $t, mageUtils) {
'use strict';
/**
@@ -682,9 +683,9 @@ define([
$.mage.__('Please use only letters (a-z or A-Z) or numbers (0-9) in this field. No spaces or other characters are allowed.')
],
"validate-date": [
- function(value) {
- var test = new Date(value);
- return utils.isEmptyNoTrim(value) || !isNaN(test);
+ function(value, params, additionalParams) {
+ var test = moment(value, additionalParams.dateFormat);
+ return utils.isEmptyNoTrim(value) || test.isValid();
},$.mage.__('Please enter a valid date.')
],
diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php
index f30c1bffa0075..4191ec1faa959 100644
--- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php
@@ -275,6 +275,35 @@ public function testCreateAllStoreCode($fixtureProduct)
$this->deleteProduct($fixtureProduct[ProductInterface::SKU]);
}
+ /**
+ * Test creating product with all store code on single store
+ *
+ * @param array $fixtureProduct
+ * @dataProvider productCreationProvider
+ */
+ public function testCreateAllStoreCodeForSingleWebsite($fixtureProduct)
+ {
+ $response = $this->saveProduct($fixtureProduct, 'all');
+ $this->assertArrayHasKey(ProductInterface::SKU, $response);
+
+ /** @var \Magento\Store\Model\StoreManagerInterface $storeManager */
+ $storeManager = \Magento\TestFramework\ObjectManager::getInstance()->get(
+ \Magento\Store\Model\StoreManagerInterface::class
+ );
+
+ foreach ($storeManager->getStores(true) as $store) {
+ $code = $store->getCode();
+ if ($code === Store::ADMIN_CODE) {
+ continue;
+ }
+ $this->assertArrayHasKey(
+ ProductInterface::SKU,
+ $this->getProduct($fixtureProduct[ProductInterface::SKU], $code)
+ );
+ }
+ $this->deleteProduct($fixtureProduct[ProductInterface::SKU]);
+ }
+
public function testCreateInvalidPriceFormat()
{
$this->_markTestAsRestOnly("In case of SOAP type casting is handled by PHP SoapServer, no need to test it");