From d70043caa2f1c19acf73985479a0869c9b000806 Mon Sep 17 00:00:00 2001 From: Maxim Medinskiy Date: Fri, 16 Sep 2016 14:02:55 +0300 Subject: [PATCH 01/24] MAGETWO-23764: Category/Product Indexer fails with mysql fatal on large catalog --- .../Catalog/Model/Indexer/Category/Product/Action/Full.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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..7cfa70beb6d4b 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 @@ -10,10 +10,12 @@ class Full extends \Magento\Catalog\Model\Indexer\Category\Product\AbstractActio /** * Refresh entities index * + * @param bool $useTempTable * @return $this */ - public function execute() + public function execute($useTempTable = false) { + $this->useTempTable = $useTempTable; $this->clearTmpData(); $this->reindex(); From 125cb46b3ebd95f6e2b278383924a02b744a4849 Mon Sep 17 00:00:00 2001 From: Sergii Kovalenko Date: Mon, 19 Sep 2016 00:49:11 -0700 Subject: [PATCH 02/24] MAGETWO-58277: Saving category on catalog with 20k+ products is very slow (from 5mins till 1 hour) --- .../Catalog/Model/ResourceModel/Category.php | 44 +++-- .../CategoryBasedProductRewriteGenerator.php | 62 +++++++ .../Model/ProductScopeRewriteGenerator.php | 170 ++++++++++++++++++ .../Model/ProductUrlRewriteGenerator.php | 69 +++---- .../Observer/UrlRewriteHandler.php | 28 ++- 5 files changed, 315 insertions(+), 58 deletions(-) create mode 100644 app/code/Magento/CatalogUrlRewrite/Model/CategoryBasedProductRewriteGenerator.php create mode 100644 app/code/Magento/CatalogUrlRewrite/Model/ProductScopeRewriteGenerator.php 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/CatalogUrlRewrite/Model/CategoryBasedProductRewriteGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/CategoryBasedProductRewriteGenerator.php new file mode 100644 index 0000000000000..e584ba9ed1d20 --- /dev/null +++ b/app/code/Magento/CatalogUrlRewrite/Model/CategoryBasedProductRewriteGenerator.php @@ -0,0 +1,62 @@ +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..f5a473d861504 --- /dev/null +++ b/app/code/Magento/CatalogUrlRewrite/Model/ProductScopeRewriteGenerator.php @@ -0,0 +1,170 @@ +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 + * @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..67fc1ba2a316a 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php @@ -11,7 +11,7 @@ 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; /** @@ -53,6 +53,11 @@ class ProductUrlRewriteGenerator /** @var AnchorUrlRewriteGenerator */ private $anchorUrlRewriteGenerator; + /** + * @var ProductScopeRewriteGenerator + */ + private $productScopeRewriteGenerator; + /** * @param \Magento\CatalogUrlRewrite\Model\Product\CanonicalUrlRewriteGenerator $canonicalUrlRewriteGenerator * @param \Magento\CatalogUrlRewrite\Model\Product\CurrentUrlRewritesRegenerator $currentUrlRewritesRegenerator @@ -91,6 +96,22 @@ private function getAnchorUrlRewriteGenerator() return $this->anchorUrlRewriteGenerator; } + /** + * Retrieve Delegator for generation rewrites in different scopes + * + * @deprecated + * @return ProductScopeRewriteGenerator|mixed + */ + private function getProductScopeRewriteGenerator() + { + if (!$this->productScopeRewriteGenerator) { + $this->productScopeRewriteGenerator = ObjectManager::getInstance() + ->get(ProductScopeRewriteGenerator::class); + } + + return $this->productScopeRewriteGenerator; + } + /** * Generate product url rewrites * @@ -126,7 +147,7 @@ public function generate(Product $product) */ protected function isGlobalScope($storeId) { - return null === $storeId || $storeId == Store::DEFAULT_STORE_ID; + return $this->getProductScopeRewriteGenerator()->isGlobalScope($storeId); } /** @@ -137,16 +158,7 @@ protected function isGlobalScope($storeId) */ 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); } /** @@ -158,30 +170,8 @@ protected function generateForGlobalScope($productCategories) */ 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); } /** @@ -191,10 +181,7 @@ protected function generateForSpecificStoreView($storeId, $productCategories) */ 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/Observer/UrlRewriteHandler.php b/app/code/Magento/CatalogUrlRewrite/Observer/UrlRewriteHandler.php index b02ef76d95146..757be550c47d0 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->productUrlRewriteGenerator->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 From e1533b9c3c00e929f4306526d3c241b967a7f3ff Mon Sep 17 00:00:00 2001 From: Sergii Kovalenko Date: Mon, 19 Sep 2016 01:27:42 -0700 Subject: [PATCH 03/24] MAGETWO-58277: Saving category on catalog with 20k+ products is very slow (from 5mins till 1 hour) --- .../Catalog/Controller/Adminhtml/Category.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category.php index 8f8f21e207bf5..7d7611e561df3 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 * From e8a068f5eb531d486d3e85122a8ff352e77a6d10 Mon Sep 17 00:00:00 2001 From: Sergii Kovalenko Date: Mon, 19 Sep 2016 01:50:26 -0700 Subject: [PATCH 04/24] MAGETWO-58277: Saving category on catalog with 20k+ products is very slow (from 5mins till 1 hour) --- .../Model/CategoryBasedProductRewriteGenerator.php | 1 - .../Model/ProductScopeRewriteGenerator.php | 3 ++- .../Model/ProductUrlRewriteGenerator.php | 14 -------------- .../Observer/UrlRewriteHandler.php | 2 +- 4 files changed, 3 insertions(+), 17 deletions(-) diff --git a/app/code/Magento/CatalogUrlRewrite/Model/CategoryBasedProductRewriteGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/CategoryBasedProductRewriteGenerator.php index e584ba9ed1d20..58025ad03f0b4 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/CategoryBasedProductRewriteGenerator.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/CategoryBasedProductRewriteGenerator.php @@ -36,7 +36,6 @@ public function __construct( $this->productScopeRewriteGenerator = $productScopeRewriteGenerator; } - /** * Generate product url rewrites based on category * diff --git a/app/code/Magento/CatalogUrlRewrite/Model/ProductScopeRewriteGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/ProductScopeRewriteGenerator.php index f5a473d861504..94464ec05d824 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/ProductScopeRewriteGenerator.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/ProductScopeRewriteGenerator.php @@ -17,6 +17,7 @@ /** * Class ProductScopeRewriteGenerator + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class ProductScopeRewriteGenerator { @@ -55,7 +56,6 @@ class ProductScopeRewriteGenerator */ private $canonicalUrlRewriteGenerator; - /** * @param StoreViewService $storeViewService * @param StoreManagerInterface $storeManager @@ -122,6 +122,7 @@ public function generateForGlobalScope($productCategories, Product $product) * * @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) diff --git a/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php index 67fc1ba2a316a..d0b28b8f9debb 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php @@ -82,20 +82,6 @@ public function __construct( $this->storeManager = $storeManager; } - /** - * @return AnchorUrlRewriteGenerator - * - * @deprecated - */ - private function getAnchorUrlRewriteGenerator() - { - if ($this->anchorUrlRewriteGenerator === null) { - $this->anchorUrlRewriteGenerator = \Magento\Framework\App\ObjectManager::getInstance() - ->get(\Magento\CatalogUrlRewrite\Model\Product\AnchorUrlRewriteGenerator::class); - } - return $this->anchorUrlRewriteGenerator; - } - /** * Retrieve Delegator for generation rewrites in different scopes * diff --git a/app/code/Magento/CatalogUrlRewrite/Observer/UrlRewriteHandler.php b/app/code/Magento/CatalogUrlRewrite/Observer/UrlRewriteHandler.php index 757be550c47d0..ff914dc1adb20 100644 --- a/app/code/Magento/CatalogUrlRewrite/Observer/UrlRewriteHandler.php +++ b/app/code/Magento/CatalogUrlRewrite/Observer/UrlRewriteHandler.php @@ -125,7 +125,7 @@ public function getCategoryProductsUrlRewrites(Category $category, $storeId, $sa $product->setData('save_rewrites_history', $saveRewriteHistory); $productUrls = array_merge( $productUrls, - $this->productUrlRewriteGenerator->generate($product, $category) + $this->getCategoryBasedProductRewriteGenerator()->generate($product, $category) ); } return $productUrls; From 1cd8893520fed35b86f951026aea9fffd199c97c Mon Sep 17 00:00:00 2001 From: Sergii Kovalenko Date: Mon, 19 Sep 2016 02:53:46 -0700 Subject: [PATCH 05/24] MAGETWO-58277: Saving category on catalog with 20k+ products is very slow (from 5mins till 1 hour) --- .../CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php index d0b28b8f9debb..b29f8538e75a8 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php @@ -50,9 +50,6 @@ class ProductUrlRewriteGenerator /** @var \Magento\Store\Model\StoreManagerInterface */ protected $storeManager; - /** @var AnchorUrlRewriteGenerator */ - private $anchorUrlRewriteGenerator; - /** * @var ProductScopeRewriteGenerator */ @@ -167,7 +164,6 @@ protected function generateForSpecificStoreView($storeId, $productCategories) */ protected function isCategoryProperForGenerating($category, $storeId) { - return $this->getProductScopeRewriteGenerator() - ->isCategoryProperForGenerating($category, $storeId); + return $this->getProductScopeRewriteGenerator()->isCategoryProperForGenerating($category, $storeId); } } From 1268884343bbf7340e64afd1d8db9206b36c9afb Mon Sep 17 00:00:00 2001 From: Sergii Kovalenko Date: Mon, 19 Sep 2016 04:42:14 -0700 Subject: [PATCH 06/24] MAGETWO-58277: Saving category on catalog with 20k+ products is very slow (from 5mins till 1 hour) --- .../Model/ProductUrlRewriteGenerator.php | 42 +++- ...tegoryBasedProductRewriteGeneratorTest.php | 97 +++++++++ .../ProductScopeRewriteGeneratorTest.php | 182 ++++++++++++++++ .../Model/ProductUrlRewriteGeneratorTest.php | 203 ++++-------------- 4 files changed, 349 insertions(+), 175 deletions(-) create mode 100644 app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/CategoryBasedProductRewriteGeneratorTest.php create mode 100644 app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductScopeRewriteGeneratorTest.php diff --git a/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php index b29f8538e75a8..5ea8dd45713d5 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php @@ -9,7 +9,6 @@ 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\Framework\App\ObjectManager; use Magento\Catalog\Model\Product\Visibility; @@ -26,28 +25,49 @@ 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; /** @@ -125,6 +145,7 @@ public function generate(Product $product) /** * Check is global scope * + * @deprecated * @param int|null $storeId * @return bool */ @@ -136,6 +157,7 @@ protected function isGlobalScope($storeId) /** * Generate list of urls for global scope * + * @deprecated * @param \Magento\Framework\Data\Collection $productCategories * @return \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[] */ @@ -147,6 +169,7 @@ protected function generateForGlobalScope($productCategories) /** * 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[] @@ -159,11 +182,12 @@ protected function generateForSpecificStoreView($storeId, $productCategories) /** * @param \Magento\Catalog\Model\Category $category + * @deprecated * @param int $storeId * @return bool */ protected function isCategoryProperForGenerating($category, $storeId) { - return $this->getProductScopeRewriteGenerator()->isCategoryProperForGenerating($category, $storeId); + return $this->getProductScopeRewriteGenerator()->isCategoryProperForGenerating($category, $storeId); } } 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..74f00cb053454 --- /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)); } } From b273f3ce3f1ee1f6261ef35da3d04605c4c9c350 Mon Sep 17 00:00:00 2001 From: Sergii Kovalenko Date: Mon, 19 Sep 2016 04:54:10 -0700 Subject: [PATCH 07/24] MAGETWO-58277: Saving category on catalog with 20k+ products is very slow (from 5mins till 1 hour) --- .../Magento/Catalog/Controller/Adminhtml/Category.php | 2 +- .../Model/ProductUrlRewriteGenerator.php | 2 +- .../Unit/Model/ProductScopeRewriteGeneratorTest.php | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category.php index 7d7611e561df3..071ba902f4fe0 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Category.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category.php @@ -71,7 +71,7 @@ private function resolveCategoryId() { $categoryId = (int)$this->getRequest()->getParam('id', false); - return $categoryId ?: (int)$this->getRequest()->getParam('entity_id', false); + return $categoryId ?: (int)$this->getRequest()->getParam('entity_id', false); } /** diff --git a/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php index 5ea8dd45713d5..f8f8991f95a04 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteGenerator.php @@ -181,8 +181,8 @@ protected function generateForSpecificStoreView($storeId, $productCategories) } /** - * @param \Magento\Catalog\Model\Category $category * @deprecated + * @param \Magento\Catalog\Model\Category $category * @param int $storeId * @return bool */ diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductScopeRewriteGeneratorTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductScopeRewriteGeneratorTest.php index 74f00cb053454..99bb858e31b8f 100644 --- a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductScopeRewriteGeneratorTest.php +++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductScopeRewriteGeneratorTest.php @@ -8,9 +8,13 @@ use Magento\Catalog\Model\Category; use Magento\CatalogUrlRewrite\Model\ProductScopeRewriteGenerator; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Store\Api\Data\StoreInterface; use Magento\Store\Model\StoreManagerInterface; +/** + * Class ProductScopeRewriteGeneratorTest + * @package Magento\CatalogUrlRewrite\Test\Unit\Model + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class ProductScopeRewriteGeneratorTest extends \PHPUnit_Framework_TestCase { /** @var \PHPUnit_Framework_MockObject_MockObject */ @@ -25,9 +29,6 @@ class ProductScopeRewriteGeneratorTest extends \PHPUnit_Framework_TestCase /** @var \PHPUnit_Framework_MockObject_MockObject */ private $anchorUrlRewriteGenerator; - /** @var \Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator */ - private $productUrlRewriteGenerator; - /** @var \Magento\CatalogUrlRewrite\Service\V1\StoreViewService|\PHPUnit_Framework_MockObject_MockObject */ private $storeViewService; @@ -178,5 +179,4 @@ protected function initObjectRegistryFactory($entities) ->with(['entities' => $entities]) ->will($this->returnValue($objectRegistry)); } - } From 328c0d056c7ba4297cc2ecde75c018a43dde623f Mon Sep 17 00:00:00 2001 From: Maxim Medinskiy Date: Mon, 19 Sep 2016 17:17:22 +0300 Subject: [PATCH 08/24] MAGETWO-23764: Category/Product Indexer fails with mysql fatal on large catalog --- .../Model/Indexer/Category/Product/Action/Full.php | 11 ++++++++--- .../Model/ResourceModel/MaxHeapTableSizeProcessor.php | 3 +++ .../MaxHeapTableSizeProcessorOnFullReindex.php | 3 +++ app/code/Magento/Catalog/etc/adminhtml/di.xml | 1 - 4 files changed, 14 insertions(+), 4 deletions(-) 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 7cfa70beb6d4b..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,15 +7,20 @@ 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 * - * @param bool $useTempTable * @return $this */ - public function execute($useTempTable = false) + public function execute() { - $this->useTempTable = $useTempTable; $this->clearTmpData(); $this->reindex(); 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/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 @@ - From 7eb9f02e260917631a2386fd48ab389a13254001 Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi Date: Mon, 19 Sep 2016 17:40:38 +0300 Subject: [PATCH 09/24] MAGETWO-33568: Customer is redirected to "Compare Products" Frontend page if tries to remove a Product from comparing --- .../Magento/Catalog/Helper/Product/Compare.php | 8 +++----- .../Test/Unit/Helper/Product/CompareTest.php | 16 +++------------- 2 files changed, 6 insertions(+), 18 deletions(-) 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/Test/Unit/Helper/Product/CompareTest.php b/app/code/Magento/Catalog/Test/Unit/Helper/Product/CompareTest.php index 29786ecdce969..bb780548f2495 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)); @@ -162,15 +157,10 @@ public function testGetPostDataClearList() $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) From 93e266f4f981384ffe3fb0d2aaff9125c78c39f6 Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi Date: Mon, 19 Sep 2016 18:07:41 +0300 Subject: [PATCH 10/24] MAGETWO-33568: Customer is redirected to "Compare Products" Frontend page if tries to remove a Product from comparing --- .../Magento/Catalog/Test/Unit/Helper/Product/CompareTest.php | 1 - 1 file changed, 1 deletion(-) 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 bb780548f2495..9f4d41aefd6bb 100644 --- a/app/code/Magento/Catalog/Test/Unit/Helper/Product/CompareTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Helper/Product/CompareTest.php @@ -154,7 +154,6 @@ public function testGetClearListUrl() public function testGetPostDataClearList() { //Data - $refererUrl = 'home/'; $clearUrl = 'catalog/product_compare/clear'; $postParams = [ Action::PARAM_NAME_URL_ENCODED => '' From deb642a17cc542cf068b7fe7a31aa31c2dcd5fb5 Mon Sep 17 00:00:00 2001 From: Sergii Kovalenko Date: Tue, 20 Sep 2016 03:05:04 -0700 Subject: [PATCH 11/24] MAGETWO-58277: Saving category on catalog with 20k+ products is very slow (from 5mins till 1 hour) --- .../Model/UrlRewriteBunchReplacer.php | 37 ++++++++++++++++++ ...ategoryProcessUrlRewriteMovingObserver.php | 24 +++++++++++- ...ategoryProcessUrlRewriteSavingObserver.php | 25 +++++++++++- .../Model/UrlRewriteBunchReplacerTest.php | 38 +++++++++++++++++++ 4 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 app/code/Magento/CatalogUrlRewrite/Model/UrlRewriteBunchReplacer.php create mode 100644 app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/UrlRewriteBunchReplacerTest.php diff --git a/app/code/Magento/CatalogUrlRewrite/Model/UrlRewriteBunchReplacer.php b/app/code/Magento/CatalogUrlRewrite/Model/UrlRewriteBunchReplacer.php new file mode 100644 index 0000000000000..31ad35e163990 --- /dev/null +++ b/app/code/Magento/CatalogUrlRewrite/Model/UrlRewriteBunchReplacer.php @@ -0,0 +1,37 @@ +urlPersist = $urlPersist; + } + + /** + * Do Bunch Replace, with default bunch value = 10000 + * + * @param array $urls + * @param int $bunchSize + */ + 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/Test/Unit/Model/UrlRewriteBunchReplacerTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/UrlRewriteBunchReplacerTest.php new file mode 100644 index 0000000000000..4f4a25ea8cd33 --- /dev/null +++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/UrlRewriteBunchReplacerTest.php @@ -0,0 +1,38 @@ +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); + } +} From eade86e0d7f5fef56c922dcfeb2724d6a08abc80 Mon Sep 17 00:00:00 2001 From: Sergii Kovalenko Date: Tue, 20 Sep 2016 03:22:05 -0700 Subject: [PATCH 12/24] MAGETWO-58277: Saving category on catalog with 20k+ products is very slow (from 5mins till 1 hour) --- .../CatalogUrlRewrite/Model/UrlRewriteBunchReplacer.php | 1 + .../Test/Unit/Model/UrlRewriteBunchReplacerTest.php | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogUrlRewrite/Model/UrlRewriteBunchReplacer.php b/app/code/Magento/CatalogUrlRewrite/Model/UrlRewriteBunchReplacer.php index 31ad35e163990..eb799dfe5991a 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/UrlRewriteBunchReplacer.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/UrlRewriteBunchReplacer.php @@ -27,6 +27,7 @@ public function __construct(UrlPersistInterface $urlPersist) * * @param array $urls * @param int $bunchSize + * @return void */ public function doBunchReplace(array $urls, $bunchSize = 10000) { diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/UrlRewriteBunchReplacerTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/UrlRewriteBunchReplacerTest.php index 4f4a25ea8cd33..7a44cc5d6f972 100644 --- a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/UrlRewriteBunchReplacerTest.php +++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/UrlRewriteBunchReplacerTest.php @@ -3,8 +3,9 @@ * Copyright © 2016 Magento. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\CatalogUrlRewrite\Model; +namespace Magento\CatalogUrlRewrite\Test\Unit\Model; +use Magento\CatalogUrlRewrite\Model\UrlRewriteBunchReplacer; use Magento\UrlRewrite\Model\UrlPersistInterface; class UrlRewriteBunchReplacerTest extends \PHPUnit_Framework_TestCase From 95d17ee6a5ec5375dd2ef7934d1b4f501ba29080 Mon Sep 17 00:00:00 2001 From: Sergii Kovalenko Date: Tue, 20 Sep 2016 05:44:06 -0700 Subject: [PATCH 13/24] MAGETWO-56512: Products created via REST API are not visible after enabling the product via scope = All Store Views --- .../Catalog/Model/ProductRepository.php | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ProductRepository.php b/app/code/Magento/Catalog/Model/ProductRepository.php index 9ceaa8bc9d049..2a5811f8e60a0 100644 --- a/app/code/Magento/Catalog/Model/ProductRepository.php +++ b/app/code/Magento/Catalog/Model/ProductRepository.php @@ -303,6 +303,7 @@ protected function initializeProductData(array $productData, $createNew) $product->setData($key, $value); } $this->assignProductToWebsites($product); + $this->assignAdminWebsiteToProduct($product); return $product; } @@ -314,16 +315,25 @@ protected function initializeProductData(array $productData, $createNew) private function assignProductToWebsites(\Magento\Catalog\Model\Product $product) { 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 = [$this->storeManager->getStore()->getWebsiteId()]; $product->setWebsiteIds(array_unique(array_merge($product->getWebsiteIds(), $websiteIds))); } } + /** + * Assign all websites to product if current product is admin + * + * @param Product $product + * @return void + */ + private function assignAdminWebsiteToProduct(\Magento\Catalog\Model\Product $product) + { + if ($this->storeManager->getStore(true)->getCode() == \Magento\Store\Model\Store::ADMIN_CODE) { + $websiteIds = array_keys($this->storeManager->getWebsites()); + $product->setWebsiteIds($websiteIds); + } + } + /** * @param ProductInterface $product * @param array $newEntry From 6fef16c88e51ab421d696d6c9071ed5dafa5c32d Mon Sep 17 00:00:00 2001 From: Sergii Kovalenko Date: Tue, 20 Sep 2016 05:50:23 -0700 Subject: [PATCH 14/24] MAGETWO-56512: Products created via REST API are not visible after enabling the product via scope = All Store Views --- app/code/Magento/Catalog/Model/ProductRepository.php | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ProductRepository.php b/app/code/Magento/Catalog/Model/ProductRepository.php index 2a5811f8e60a0..ccfcbc03c0f7a 100644 --- a/app/code/Magento/Catalog/Model/ProductRepository.php +++ b/app/code/Magento/Catalog/Model/ProductRepository.php @@ -303,7 +303,6 @@ protected function initializeProductData(array $productData, $createNew) $product->setData($key, $value); } $this->assignProductToWebsites($product); - $this->assignAdminWebsiteToProduct($product); return $product; } @@ -318,16 +317,7 @@ private function assignProductToWebsites(\Magento\Catalog\Model\Product $product $websiteIds = [$this->storeManager->getStore()->getWebsiteId()]; $product->setWebsiteIds(array_unique(array_merge($product->getWebsiteIds(), $websiteIds))); } - } - /** - * Assign all websites to product if current product is admin - * - * @param Product $product - * @return void - */ - private function assignAdminWebsiteToProduct(\Magento\Catalog\Model\Product $product) - { if ($this->storeManager->getStore(true)->getCode() == \Magento\Store\Model\Store::ADMIN_CODE) { $websiteIds = array_keys($this->storeManager->getWebsites()); $product->setWebsiteIds($websiteIds); From 70dde951969d08aa43e2c981622cadd3049bfb62 Mon Sep 17 00:00:00 2001 From: Sergii Kovalenko Date: Tue, 20 Sep 2016 06:24:05 -0700 Subject: [PATCH 15/24] MAGETWO-56512: Products created via REST API are not visible after enabling the product via scope = All Store Views --- .../Catalog/Model/ProductRepository.php | 13 +++-- .../Test/Unit/Model/ProductRepositoryTest.php | 51 ++++++++++++++++++- 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ProductRepository.php b/app/code/Magento/Catalog/Model/ProductRepository.php index ccfcbc03c0f7a..3db0892ad1c59 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 = []; + if (!$this->storeManager->hasSingleStore()) { - $websiteIds = [$this->storeManager->getStore()->getWebsiteId()]; - $product->setWebsiteIds(array_unique(array_merge($product->getWebsiteIds(), $websiteIds))); + $websiteIds = array_unique( + array_merge( + $product->getWebsiteIds(), + [$this->storeManager->getStore()->getWebsiteId()] + ) + ); } if ($this->storeManager->getStore(true)->getCode() == \Magento\Store\Model\Store::ADMIN_CODE) { $websiteIds = array_keys($this->storeManager->getWebsites()); - $product->setWebsiteIds($websiteIds); } + + $product->setWebsiteIds($websiteIds); } /** 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 = [ [ From 5ee42c4aa5780c7994c8fbf58edd04b56f7ed6c4 Mon Sep 17 00:00:00 2001 From: Sergii Kovalenko Date: Wed, 21 Sep 2016 00:36:46 -0700 Subject: [PATCH 16/24] MAGETWO-56512: Products created via REST API are not visible after enabling the product via scope = All Store Views --- .../Api/ProductRepositoryInterfaceTest.php | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) 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"); From 15fbf4c1cda2170acab8a458094d95dfeb9af864 Mon Sep 17 00:00:00 2001 From: Sergii Kovalenko Date: Wed, 21 Sep 2016 01:47:29 -0700 Subject: [PATCH 17/24] MAGETWO-56512: Products created via REST API are not visible after enabling the product via scope = All Store Views --- app/code/Magento/Catalog/Model/ProductRepository.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ProductRepository.php b/app/code/Magento/Catalog/Model/ProductRepository.php index 3db0892ad1c59..4385c8add37ae 100644 --- a/app/code/Magento/Catalog/Model/ProductRepository.php +++ b/app/code/Magento/Catalog/Model/ProductRepository.php @@ -313,12 +313,12 @@ protected function initializeProductData(array $productData, $createNew) */ private function assignProductToWebsites(\Magento\Catalog\Model\Product $product) { - $websiteIds = []; + $websiteIds = $product->getWebsiteIds(); if (!$this->storeManager->hasSingleStore()) { $websiteIds = array_unique( array_merge( - $product->getWebsiteIds(), + $websiteIds, [$this->storeManager->getStore()->getWebsiteId()] ) ); From 9d7fe886303fb9dcfc54216e20f70b677aa0e17d Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi Date: Thu, 22 Sep 2016 16:23:57 +0300 Subject: [PATCH 18/24] MAGETWO-55154: [GitHub] IndexerHandlerFactory: Indexer Object cast to String --- .../Model/Indexer/IndexerHandlerFactory.php | 6 +- .../Indexer/IndexerHandlerFactoryTest.php | 173 ++++++++++++++++++ 2 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/IndexerHandlerFactoryTest.php 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); + } +} From 910b93709170f94d0558b0e4d31f825ac96b6fbc Mon Sep 17 00:00:00 2001 From: Sergey Semenov Date: Thu, 22 Sep 2016 17:02:37 +0300 Subject: [PATCH 19/24] MAGETWO-57835: [Github] Cannot save customer dob attribute if admin interface locale is en_GB #6323 --- .../Component/Form/Element/DataType/Date.php | 16 +-- .../Form/Element/DataType/DateTest.php | 126 ++++++++++++++++++ .../js/lib/knockout/bindings/datepicker.js | 13 +- .../view/base/web/js/lib/validation/rules.js | 11 +- 4 files changed, 150 insertions(+), 16 deletions(-) create mode 100644 app/code/Magento/Ui/Test/Unit/Component/Form/Element/DataType/DateTest.php 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..bf29a700aece1 100644 --- a/app/code/Magento/Ui/Component/Form/Element/DataType/Date.php +++ b/app/code/Magento/Ui/Component/Form/Element/DataType/Date.php @@ -7,7 +7,6 @@ use Magento\Framework\Locale\ResolverInterface; use Magento\Framework\Stdlib\DateTime\TimezoneInterface; -use Magento\Framework\View\Element\UiComponentInterface; use Magento\Framework\View\Element\UiComponent\ContextInterface; /** @@ -22,18 +21,14 @@ class Date extends AbstractDataType * * @var string */ - protected $locale; + private $locale; /** - * Wrapped component - * - * @var UiComponentInterface + * @var TimezoneInterface */ - protected $wrappedComponent; + private $localeDate; /** - * Constructor - * * @param ContextInterface $context * @param TimezoneInterface $localeDate * @param ResolverInterface $localeResolver @@ -70,6 +65,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.') ], From 5632d2a9e75023c432c220db58d53dcca8768283 Mon Sep 17 00:00:00 2001 From: Sergey Semenov Date: Thu, 22 Sep 2016 17:10:58 +0300 Subject: [PATCH 20/24] MAGETWO-57835: [Github] Cannot save customer dob attribute if admin interface locale is en_GB #6323 --- .../Magento/Ui/Component/Form/Element/DataType/Date.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) 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 bf29a700aece1..de363262275e5 100644 --- a/app/code/Magento/Ui/Component/Form/Element/DataType/Date.php +++ b/app/code/Magento/Ui/Component/Form/Element/DataType/Date.php @@ -7,6 +7,7 @@ use Magento\Framework\Locale\ResolverInterface; use Magento\Framework\Stdlib\DateTime\TimezoneInterface; +use Magento\Framework\View\Element\UiComponentInterface; use Magento\Framework\View\Element\UiComponent\ContextInterface; /** @@ -21,12 +22,14 @@ class Date extends AbstractDataType * * @var string */ - private $locale; + protected $locale; /** - * @var TimezoneInterface + * Wrapped component + * + * @var UiComponentInterface */ - private $localeDate; + protected $wrappedComponent; /** * @param ContextInterface $context From 091efd3263a56da36c8bbbbe501b5884ded9c4ad Mon Sep 17 00:00:00 2001 From: Volodymyr Zaets Date: Thu, 22 Sep 2016 17:55:30 +0300 Subject: [PATCH 21/24] MAGETWO-57629: ACL not used on grid quick edits --- .../Controller/Adminhtml/Page/InlineEdit.php | 7 ++ .../Adminhtml/Page/InlineEditTest.php | 44 ++++++++- .../Ui/Component/Listing/DataProviderTest.php | 89 +++++++++++++++++++ .../Magento/Cms/Ui/Component/DataProvider.php | 54 +++++++++++ 4 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/DataProviderTest.php diff --git a/app/code/Magento/Cms/Controller/Adminhtml/Page/InlineEdit.php b/app/code/Magento/Cms/Controller/Adminhtml/Page/InlineEdit.php index c2e26220aee46..d5a8035a29f49 100644 --- a/app/code/Magento/Cms/Controller/Adminhtml/Page/InlineEdit.php +++ b/app/code/Magento/Cms/Controller/Adminhtml/Page/InlineEdit.php @@ -62,6 +62,13 @@ public function execute() ]); } + if (!$this->_authorization->isAllowed('Magento_Cms::save')) { + return $resultJson->setData([ + 'messages' => [__('Access denied'), __('You need more permissions to access this.')], + 'error' => true, + ]); + } + foreach (array_keys($postItems) as $pageId) { /** @var \Magento\Cms\Model\Page $page */ $page = $this->pageRepository->getById($pageId); diff --git a/app/code/Magento/Cms/Test/Unit/Controller/Adminhtml/Page/InlineEditTest.php b/app/code/Magento/Cms/Test/Unit/Controller/Adminhtml/Page/InlineEditTest.php index f153eda78da55..1af2b88c48207 100644 --- a/app/code/Magento/Cms/Test/Unit/Controller/Adminhtml/Page/InlineEditTest.php +++ b/app/code/Magento/Cms/Test/Unit/Controller/Adminhtml/Page/InlineEditTest.php @@ -45,6 +45,9 @@ class InlineEditTest extends \PHPUnit_Framework_TestCase /** @var InlineEdit */ protected $controller; + /** @var \Magento\Framework\AuthorizationInterface|\PHPUnit_Framework_MockObject_MockObject */ + private $authorization; + protected function setUp() { $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -54,11 +57,14 @@ protected function setUp() $this->messageCollection = $this->getMock(\Magento\Framework\Message\Collection::class, [], [], '', false); $this->message = $this->getMockForAbstractClass(\Magento\Framework\Message\MessageInterface::class); $this->cmsPage = $this->getMock(\Magento\Cms\Model\Page::class, [], [], '', false); + $this->authorization = $this->getMockBuilder(\Magento\Framework\AuthorizationInterface::class) + ->getMockForAbstractClass(); $this->context = $helper->getObject( \Magento\Backend\App\Action\Context::class, [ 'request' => $this->request, - 'messageManager' => $this->messageManager + 'messageManager' => $this->messageManager, + 'authorization' => $this->authorization, ] ); $this->dataProcessor = $this->getMock( @@ -147,6 +153,42 @@ public function prepareMocksForTestExecute() $this->jsonFactory->expects($this->once()) ->method('create') ->willReturn($this->resultJson); + + $this->authorization->expects($this->once()) + ->method('isAllowed') + ->with('Magento_Cms::save') + ->willReturn(true); + } + + public function testExecuteWithLowPermissions() + { + $this->request->expects($this->any()) + ->method('getParam') + ->willReturnMap( + [ + ['isAjax', null, true], + ['items', [], ['title' => '404 Not Found']] + ] + ); + $this->authorization->expects($this->once()) + ->method('isAllowed') + ->with('Magento_Cms::save') + ->willReturn(false); + $this->jsonFactory->expects($this->once()) + ->method('create') + ->willReturn($this->resultJson); + $this->resultJson->expects($this->once()) + ->method('setData') + ->with([ + 'messages' => [ + __('Access denied'), + __('You need more permissions to access this.') + ], + 'error' => true, + ]) + ->willReturnSelf(); + + $this->assertSame($this->resultJson, $this->controller->execute()); } public function testExecuteWithLocalizedException() 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..1c9f02cc90c27 --- /dev/null +++ b/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/DataProviderTest.php @@ -0,0 +1,89 @@ +authorizationMock = $this->getMockBuilder(\Magento\Framework\Authorization::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->reportingMock = $this->getMockBuilder(\Magento\Framework\View\Element\UiComponent\DataProvider\Reporting::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->searchCriteriaBuilderMock = $this->getMockBuilder(\Magento\Framework\Api\Search\SearchCriteriaBuilder::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->requestInterfaceMock = $this->getMockBuilder(\Magento\Framework\App\RequestInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->filterBuilderMock = $this->getMockBuilder(\Magento\Framework\Api\FilterBuilder::class) + ->disableOriginalConstructor() + ->getMock(); + + $objectManagerMock = $this->getMock(\Magento\Framework\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 + ); + } + + public function testPrepareMetadata() + { + $this->authorizationMock->expects($this->once()) + ->method('isAllowed') + ->with(DataProvider::ADMIN_RESOURCE) + ->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..627e338364266 100644 --- a/app/code/Magento/Cms/Ui/Component/DataProvider.php +++ b/app/code/Magento/Cms/Ui/Component/DataProvider.php @@ -7,11 +7,23 @@ 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 { + /** + * Authorization level of a basic admin session + */ + const ADMIN_RESOURCE = 'Magento_Cms::save'; + + /** + * @var AuthorizationInterface + */ + private $authorization; + /** * @param string $name * @param string $primaryFieldName @@ -45,5 +57,47 @@ public function __construct( $meta, $data ); + + $this->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(static::ADMIN_RESOURCE)) { + $metadata = [ + 'cms_page_columns' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'editorConfig' => [ + 'enabled' => true + ] + ] + ] + ] + ] + ]; + } + + return $metadata; } } + From 203a82eb5a683dbbd6d6c5b30e81e73bc69e5e80 Mon Sep 17 00:00:00 2001 From: Volodymyr Zaets Date: Fri, 23 Sep 2016 11:09:27 +0300 Subject: [PATCH 22/24] MAGETWO-57629: ACL not used on grid quick edits --- .../Controller/Adminhtml/Page/InlineEdit.php | 12 +++-- .../Adminhtml/Page/InlineEditTest.php | 44 +------------------ .../Magento/Cms/Ui/Component/DataProvider.php | 9 +--- 3 files changed, 8 insertions(+), 57 deletions(-) diff --git a/app/code/Magento/Cms/Controller/Adminhtml/Page/InlineEdit.php b/app/code/Magento/Cms/Controller/Adminhtml/Page/InlineEdit.php index d5a8035a29f49..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; @@ -62,13 +67,6 @@ public function execute() ]); } - if (!$this->_authorization->isAllowed('Magento_Cms::save')) { - return $resultJson->setData([ - 'messages' => [__('Access denied'), __('You need more permissions to access this.')], - 'error' => true, - ]); - } - foreach (array_keys($postItems) as $pageId) { /** @var \Magento\Cms\Model\Page $page */ $page = $this->pageRepository->getById($pageId); diff --git a/app/code/Magento/Cms/Test/Unit/Controller/Adminhtml/Page/InlineEditTest.php b/app/code/Magento/Cms/Test/Unit/Controller/Adminhtml/Page/InlineEditTest.php index 1af2b88c48207..f153eda78da55 100644 --- a/app/code/Magento/Cms/Test/Unit/Controller/Adminhtml/Page/InlineEditTest.php +++ b/app/code/Magento/Cms/Test/Unit/Controller/Adminhtml/Page/InlineEditTest.php @@ -45,9 +45,6 @@ class InlineEditTest extends \PHPUnit_Framework_TestCase /** @var InlineEdit */ protected $controller; - /** @var \Magento\Framework\AuthorizationInterface|\PHPUnit_Framework_MockObject_MockObject */ - private $authorization; - protected function setUp() { $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -57,14 +54,11 @@ protected function setUp() $this->messageCollection = $this->getMock(\Magento\Framework\Message\Collection::class, [], [], '', false); $this->message = $this->getMockForAbstractClass(\Magento\Framework\Message\MessageInterface::class); $this->cmsPage = $this->getMock(\Magento\Cms\Model\Page::class, [], [], '', false); - $this->authorization = $this->getMockBuilder(\Magento\Framework\AuthorizationInterface::class) - ->getMockForAbstractClass(); $this->context = $helper->getObject( \Magento\Backend\App\Action\Context::class, [ 'request' => $this->request, - 'messageManager' => $this->messageManager, - 'authorization' => $this->authorization, + 'messageManager' => $this->messageManager ] ); $this->dataProcessor = $this->getMock( @@ -153,42 +147,6 @@ public function prepareMocksForTestExecute() $this->jsonFactory->expects($this->once()) ->method('create') ->willReturn($this->resultJson); - - $this->authorization->expects($this->once()) - ->method('isAllowed') - ->with('Magento_Cms::save') - ->willReturn(true); - } - - public function testExecuteWithLowPermissions() - { - $this->request->expects($this->any()) - ->method('getParam') - ->willReturnMap( - [ - ['isAjax', null, true], - ['items', [], ['title' => '404 Not Found']] - ] - ); - $this->authorization->expects($this->once()) - ->method('isAllowed') - ->with('Magento_Cms::save') - ->willReturn(false); - $this->jsonFactory->expects($this->once()) - ->method('create') - ->willReturn($this->resultJson); - $this->resultJson->expects($this->once()) - ->method('setData') - ->with([ - 'messages' => [ - __('Access denied'), - __('You need more permissions to access this.') - ], - 'error' => true, - ]) - ->willReturnSelf(); - - $this->assertSame($this->resultJson, $this->controller->execute()); } public function testExecuteWithLocalizedException() diff --git a/app/code/Magento/Cms/Ui/Component/DataProvider.php b/app/code/Magento/Cms/Ui/Component/DataProvider.php index 627e338364266..2ce914651c9f8 100644 --- a/app/code/Magento/Cms/Ui/Component/DataProvider.php +++ b/app/code/Magento/Cms/Ui/Component/DataProvider.php @@ -14,11 +14,6 @@ class DataProvider extends \Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider { - /** - * Authorization level of a basic admin session - */ - const ADMIN_RESOURCE = 'Magento_Cms::save'; - /** * @var AuthorizationInterface */ @@ -81,14 +76,14 @@ private function getAuthorizationInstance() public function prepareMetadata() { $metadata = []; - if (!$this->getAuthorizationInstance()->isAllowed(static::ADMIN_RESOURCE)) { + if (!$this->getAuthorizationInstance()->isAllowed('Magento_Cms::save')) { $metadata = [ 'cms_page_columns' => [ 'arguments' => [ 'data' => [ 'config' => [ 'editorConfig' => [ - 'enabled' => true + 'enabled' => false ] ] ] From 29de7773c26adf56fb0ec7d85c0d673fcc5ce412 Mon Sep 17 00:00:00 2001 From: Volodymyr Zaets Date: Fri, 23 Sep 2016 11:46:20 +0300 Subject: [PATCH 23/24] MAGETWO-57629: ACL not used on grid quick edits --- .../Ui/Component/Listing/DataProviderTest.php | 60 ++++++++++++++++--- .../Magento/Cms/Ui/Component/DataProvider.php | 2 +- 2 files changed, 54 insertions(+), 8 deletions(-) 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 index 1c9f02cc90c27..70fef18f3a77d 100644 --- a/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/DataProviderTest.php +++ b/app/code/Magento/Cms/Test/Unit/Ui/Component/Listing/DataProviderTest.php @@ -8,41 +8,84 @@ use Magento\Cms\Ui\Component\DataProvider; use Magento\Framework\App\ObjectManager; +use Magento\Framework\Authorization; +use Magento\Framework\View\Element\UiComponent\DataProvider\Reporting; +use Magento\Framework\Api\Search\SearchCriteriaBuilder; +use Magento\Framework\App\RequestInterface; +use Magento\Framework\Api\FilterBuilder; +use Magento\Framework\ObjectManagerInterface; class DataProviderTest extends \PHPUnit_Framework_TestCase { + /** + * @var \Magento\Framework\Authorization|\PHPUnit_Framework_MockObject_MockObject + */ private $authorizationMock; + + /** + * @var \Magento\Framework\View\Element\UiComponent\DataProvider\Reporting|\PHPUnit_Framework_MockObject_MockObject + */ private $reportingMock; + + /** + * @var \Magento\Framework\Api\Search\SearchCriteriaBuilder|\PHPUnit_Framework_MockObject_MockObject + */ private $searchCriteriaBuilderMock; + + /** + * @var \Magento\Framework\App\RequestInterface|\PHPUnit_Framework_MockObject_MockObject + */ private $requestInterfaceMock; + + /** + * @var \Magento\Framework\Api\FilterBuilder|\PHPUnit_Framework_MockObject_MockObject + */ private $filterBuilderMock; + + /** + * @var \Magento\Cms\Ui\Component\DataProvider + */ + private $dataProvider; + + /** + * @var string + */ private $name = 'cms_page_listing_data_source'; + + /** + * @var string + */ private $primaryFieldName = 'page'; + + /** + * @var string + */ private $requestFieldName = 'id'; public function setUp() { - $this->authorizationMock = $this->getMockBuilder(\Magento\Framework\Authorization::class) + $this->authorizationMock = $this->getMockBuilder(Authorization::class) ->disableOriginalConstructor() ->getMock(); - $this->reportingMock = $this->getMockBuilder(\Magento\Framework\View\Element\UiComponent\DataProvider\Reporting::class) + $this->reportingMock = $this->getMockBuilder(Reporting::class) ->disableOriginalConstructor() ->getMock(); - $this->searchCriteriaBuilderMock = $this->getMockBuilder(\Magento\Framework\Api\Search\SearchCriteriaBuilder::class) + $this->searchCriteriaBuilderMock = $this->getMockBuilder(SearchCriteriaBuilder::class) ->disableOriginalConstructor() ->getMock(); - $this->requestInterfaceMock = $this->getMockBuilder(\Magento\Framework\App\RequestInterface::class) + $this->requestInterfaceMock = $this->getMockBuilder(RequestInterface::class) ->disableOriginalConstructor() ->getMock(); - $this->filterBuilderMock = $this->getMockBuilder(\Magento\Framework\Api\FilterBuilder::class) + $this->filterBuilderMock = $this->getMockBuilder(FilterBuilder::class) ->disableOriginalConstructor() ->getMock(); - $objectManagerMock = $this->getMock(\Magento\Framework\ObjectManagerInterface::class); + /** @var ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject $objectManagerMock */ + $objectManagerMock = $this->getMock(ObjectManagerInterface::class); $objectManagerMock->expects($this->once()) ->method('get') ->willReturn($this->authorizationMock); @@ -59,11 +102,14 @@ public function setUp() ); } + /** + * @covers \Magento\Cms\Ui\Component\DataProvider::prepareMetadata + */ public function testPrepareMetadata() { $this->authorizationMock->expects($this->once()) ->method('isAllowed') - ->with(DataProvider::ADMIN_RESOURCE) + ->with('Magento_Cms::save') ->willReturn(false); $metadata = [ diff --git a/app/code/Magento/Cms/Ui/Component/DataProvider.php b/app/code/Magento/Cms/Ui/Component/DataProvider.php index 2ce914651c9f8..4e1a4ac553093 100644 --- a/app/code/Magento/Cms/Ui/Component/DataProvider.php +++ b/app/code/Magento/Cms/Ui/Component/DataProvider.php @@ -53,7 +53,7 @@ public function __construct( $data ); - $this->meta = $this->prepareMetadata(); + $this->meta = array_replace_recursive($meta, $this->prepareMetadata()); } /** From e87751fc41f79f509270c6941ad1f4f200c220bf Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi Date: Fri, 23 Sep 2016 16:02:43 +0300 Subject: [PATCH 24/24] MAGETWO-57629: ACL not used on grid quick edits --- app/code/Magento/Cms/Ui/Component/DataProvider.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Cms/Ui/Component/DataProvider.php b/app/code/Magento/Cms/Ui/Component/DataProvider.php index 4e1a4ac553093..85b00d341fad8 100644 --- a/app/code/Magento/Cms/Ui/Component/DataProvider.php +++ b/app/code/Magento/Cms/Ui/Component/DataProvider.php @@ -73,7 +73,8 @@ private function getAuthorizationInstance() * * @return array */ - public function prepareMetadata() { + public function prepareMetadata() + { $metadata = []; if (!$this->getAuthorizationInstance()->isAllowed('Magento_Cms::save')) { @@ -95,4 +96,3 @@ public function prepareMetadata() { return $metadata; } } -