diff --git a/app/code/Magento/Catalog/Model/Category.php b/app/code/Magento/Catalog/Model/Category.php index 538a721d356d7..4592d7d9199f4 100644 --- a/app/code/Magento/Catalog/Model/Category.php +++ b/app/code/Magento/Catalog/Model/Category.php @@ -980,6 +980,8 @@ public function getProductCount() * @param bool $asCollection * @param bool $toLoad * @return \Magento\Framework\Data\Tree\Node\Collection|\Magento\Catalog\Model\ResourceModel\Category\Collection + * @deprecated The method doesn't consider onlyActive, onlyIncludeInMenu params + * @see \Magento\Catalog\Model\Category\GetCategoriesCollection */ public function getCategories($parent, $recursionLevel = 0, $sorted = false, $asCollection = false, $toLoad = true) { diff --git a/app/code/Magento/Catalog/Model/Category/GetCategoriesCollection.php b/app/code/Magento/Catalog/Model/Category/GetCategoriesCollection.php new file mode 100644 index 0000000000000..9b20468925d05 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Category/GetCategoriesCollection.php @@ -0,0 +1,63 @@ +categoryTreeFactory = $categoryTreeFactory; + } + + /** + * Returns collection + * + * @param int $parent + * @param int|null $recursionLevel + * @param bool|null $sorted + * @param bool|null $asCollection + * @param bool|null $toLoad + * @param bool|null $onlyActive + * @param bool|null $onlyIncludeInMenu + * @return NodeCollection|Collection + */ + public function execute( + int $parent, + ?int $recursionLevel = 0, + ?bool $sorted = false, + ?bool $asCollection = false, + ?bool $toLoad = true, + ?bool $onlyActive = true, + ?bool $onlyIncludeInMenu = true + ) { + $tree = $this->categoryTreeFactory->create(); + $nodes = $tree->loadNode($parent) + ->loadChildren($recursionLevel) + ->getChildren(); + + $tree->addCollectionDataParams(null, $sorted, $parent, $toLoad, $onlyActive, $onlyIncludeInMenu); + + return $asCollection ? $tree->getCollection() : $nodes; + } +} diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category.php b/app/code/Magento/Catalog/Model/ResourceModel/Category.php index e19286efc38c0..9615e368011a5 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Category.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Category.php @@ -137,7 +137,7 @@ public function __construct( $this->_categoryTreeFactory = $categoryTreeFactory; $this->_categoryCollectionFactory = $categoryCollectionFactory; $this->_eventManager = $eventManager; - $this->connectionName = 'catalog'; + $this->connectionName = 'catalog'; $this->indexerProcessor = $indexerProcessor; $this->serializer = $serializer ?: ObjectManager::getInstance() ->get(\Magento\Framework\Serialize\Serializer\Json::class); @@ -289,7 +289,7 @@ protected function _beforeSave(\Magento\Framework\DataObject $object) $object->setPosition($this->_getMaxPosition($object->getPath()) + 1); } $path = explode('/', (string)$object->getPath()); - $level = count($path) - ($object->getId() ? 1 : 0); + $level = count($path) - ($object->getId() ? 1 : 0); $toUpdateChild = array_diff($path, [$object->getId()]); if (!$object->hasPosition()) { @@ -696,7 +696,7 @@ public function getProductCount($category) $bind = ['category_id' => (int)$category->getId()]; $counts = $this->getConnection()->fetchOne($select, $bind); - return (int) $counts; + return (int)$counts; } /** @@ -708,6 +708,8 @@ public function getProductCount($category) * @param boolean $asCollection * @param boolean $toLoad * @return \Magento\Framework\Data\Tree\Node\Collection|\Magento\Catalog\Model\ResourceModel\Category\Collection + * @deprecated The method doesn't consider onlyActive, onlyIncludeInMenu params + * @see \Magento\Catalog\Model\Category\GetCategoriesCollection */ public function getCategories($parent, $recursionLevel = 0, $sorted = false, $asCollection = false, $toLoad = true) { @@ -1112,7 +1114,7 @@ public function delete($object) /** * Save entity's attributes into the object's resource * - * @param \Magento\Framework\Model\AbstractModel $object + * @param \Magento\Framework\Model\AbstractModel $object * @return $this * @throws \Exception */ diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category/Tree.php b/app/code/Magento/Catalog/Model/ResourceModel/Category/Tree.php index bcfa6ba3f8d0c..67b24ab979bbb 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Category/Tree.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Category/Tree.php @@ -176,6 +176,8 @@ public function getStoreId() * @param boolean $toLoad * @param boolean $onlyActive * @return $this + * @deprecated This method is not intended for usage in child classes + * @see addCollectionDataParams($collection, $sorted, $exclude, $toLoad, $onlyActive, $onlyIncludeInMenu) * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ @@ -236,6 +238,81 @@ public function addCollectionData( return $this; } + /** + * Add data params to collection + * + * @param Collection|null $collection + * @param boolean $sorted + * @param array $exclude + * @param boolean $toLoad + * @param boolean $onlyActive + * @param boolean $onlyIncludeInMenu + * @return $this + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) + */ + public function addCollectionDataParams( + $collection = null, + $sorted = false, + $exclude = [], + $toLoad = true, + $onlyActive = false, + $onlyIncludeInMenu = false + ) { + if ($collection === null) { + $collection = $this->getCollection($sorted); + } else { + $this->setCollection($collection); + } + + if (!is_array($exclude)) { + $exclude = [$exclude]; + } + + $nodeIds = []; + foreach ($this->getNodes() as $node) { + if (!in_array($node->getId(), $exclude)) { + $nodeIds[] = $node->getId(); + } + } + $collection->addIdFilter($nodeIds); + + if ($onlyActive) { + $disabledIds = $this->_getDisabledIds($collection, $nodeIds); + if ($disabledIds) { + $collection->addFieldToFilter('entity_id', ['nin' => $disabledIds]); + } + $collection->addAttributeToFilter('is_active', 1); + if ($onlyIncludeInMenu) { + $collection->addAttributeToFilter('include_in_menu', 1); + } + } + + if ($this->_joinUrlRewriteIntoCollection) { + $collection->joinUrlRewrite(); + $this->_joinUrlRewriteIntoCollection = false; + } + + if ($toLoad) { + $collection->load(); + + foreach ($collection as $category) { + $node = $this->getNodeById($category->getId()); + if ($node) { + $node->addData($category->getData()); + } + } + + foreach ($this->getNodes() as $node) { + if ($node->getParent() && !$collection->getItemById($node->getId())) { + $this->removeNode($node); + } + } + } + + return $this; + } + /** * Add inactive categories ids * diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Category/TreeTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Category/TreeTest.php index 6593f28641ec6..f92f5421fc1dc 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Category/TreeTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Category/TreeTest.php @@ -222,6 +222,6 @@ public function testAddCollectionData() $model->addNode($nodeMock); - $this->assertSame($model, $model->addCollectionData(null, false, [], false, true)); + $this->assertSame($model, $model->addCollectionDataParams(null, false, [], false, true, false)); } } diff --git a/app/code/Magento/CatalogUrlRewrite/Model/Category/Plugin/Store/View.php b/app/code/Magento/CatalogUrlRewrite/Model/Category/Plugin/Store/View.php index 31bb630718e55..26c0b9d67787a 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/Category/Plugin/Store/View.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/Category/Plugin/Store/View.php @@ -8,6 +8,7 @@ namespace Magento\CatalogUrlRewrite\Model\Category\Plugin\Store; use Magento\Catalog\Model\Category; +use Magento\Catalog\Model\Category\GetCategoriesCollection; use Magento\Catalog\Model\CategoryFactory; use Magento\Catalog\Model\Product; use Magento\Catalog\Model\ProductFactory; @@ -56,25 +57,33 @@ class View */ private $origStore; + /** + * @var GetCategoriesCollection + */ + private $getCategoriesCollection; + /** * @param UrlPersistInterface $urlPersist * @param CategoryFactory $categoryFactory * @param ProductFactory $productFactory * @param CategoryUrlRewriteGenerator $categoryUrlRewriteGenerator * @param ProductUrlRewriteGenerator $productUrlRewriteGenerator + * @param GetCategoriesCollection $getCategoriesCollection */ public function __construct( UrlPersistInterface $urlPersist, CategoryFactory $categoryFactory, ProductFactory $productFactory, CategoryUrlRewriteGenerator $categoryUrlRewriteGenerator, - ProductUrlRewriteGenerator $productUrlRewriteGenerator + ProductUrlRewriteGenerator $productUrlRewriteGenerator, + GetCategoriesCollection $getCategoriesCollection ) { $this->categoryUrlRewriteGenerator = $categoryUrlRewriteGenerator; $this->productUrlRewriteGenerator = $productUrlRewriteGenerator; $this->urlPersist = $urlPersist; $this->categoryFactory = $categoryFactory; $this->productFactory = $productFactory; + $this->getCategoriesCollection = $getCategoriesCollection; } /** @@ -154,7 +163,8 @@ protected function generateProductUrls(int $storeId): array protected function generateCategoryUrls(int $rootCategoryId, int $storeId): array { $urls = []; - $categories = $this->categoryFactory->create()->getCategories($rootCategoryId, 1, false, true, false); + $categories = $this->getCategoriesCollection + ->execute($rootCategoryId, 1, false, true, false, true, false); $categories->setStoreId($storeId); foreach ($categories as $category) { /** @var Category $category */ diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Category/Plugin/Store/ViewTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Category/Plugin/Store/ViewTest.php index 61557db883aa1..e891c9afe120e 100644 --- a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Category/Plugin/Store/ViewTest.php +++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Category/Plugin/Store/ViewTest.php @@ -88,6 +88,11 @@ class ViewTest extends TestCase */ private $productMock; + /** + * @var Category\GetCategoriesCollection|MockObject + */ + private $getCategoriesCollectionMock; + /** * @inheritdoc */ @@ -131,6 +136,7 @@ protected function setUp(): void ->disableOriginalConstructor() ->setMethods(['getCollection']) ->getMock(); + $this->getCategoriesCollectionMock = $this->createMock(Category\GetCategoriesCollection::class); $this->plugin = $this->objectManager->getObject( StoreViewPlugin::class, [ @@ -138,7 +144,8 @@ protected function setUp(): void 'categoryFactory' => $this->categoryFactoryMock, 'productFactory' => $this->productFactoryMock, 'categoryUrlRewriteGenerator' => $this->categoryUrlRewriteGeneratorMock, - 'productUrlRewriteGenerator' => $this->productUrlRewriteGeneratorMock + 'productUrlRewriteGenerator' => $this->productUrlRewriteGeneratorMock, + 'getCategoriesCollection' => $this->getCategoriesCollectionMock ] ); } @@ -171,12 +178,9 @@ public function testAfterSave(): void $categoryCollection->expects($this->any()) ->method('getIterator') ->willReturn(new \ArrayIterator([])); - $this->categoryMock->expects($this->once()) - ->method('getCategories') + $this->getCategoriesCollectionMock->expects($this->once()) + ->method('execute') ->willReturn($categoryCollection); - $this->categoryFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($this->categoryMock); $this->productFactoryMock->expects($this->once()) ->method('create') ->willReturn($this->productMock); diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Model/Category/Plugin/Store/ViewTest.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Model/Category/Plugin/Store/ViewTest.php new file mode 100644 index 0000000000000..9c937f00cbaca --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Model/Category/Plugin/Store/ViewTest.php @@ -0,0 +1,76 @@ +objectManager = Bootstrap::getObjectManager(); + $this->storeFactory = $this->objectManager->create(StoreFactory::class); + $this->urlRewriteCollectionFactory = $this->objectManager->get(UrlRewriteCollectionFactory::class); + } + + /** + * Verify that url will be generated for category which excluded for menu after creating store view + * + * @magentoAppArea adminhtml + * @magentoDataFixture Magento/CatalogUrlRewrite/_files/category_excluded_from_menu.php + * + * @return void + */ + public function testAfterSaveVerifyCategoryExcludedForMenuUrlRewrite(): void + { + $website = $this->objectManager->get(StoreManagerInterface::class) + ->getWebsite(); + + $store = $this->storeFactory->create(); + $store->setCode('custom_store_777') + ->setWebsiteId($website->getId()) + ->setGroupId($website->getDefaultGroupId()) + ->setName('Custom Test Store') + ->setSortOrder(10) + ->setIsActive(1) + ->save(); + + $urlRewriteCollection = $this->urlRewriteCollectionFactory->create(); + $urlRewriteCollection->addFieldToFilter(UrlRewrite::STORE_ID, $store->getId()) + ->addFieldToFilter(UrlRewrite::TARGET_PATH, 'catalog/category/view/id/' . 3); + + $this->assertCount(1, $urlRewriteCollection); + } +} diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/category_excluded_from_menu.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/category_excluded_from_menu.php new file mode 100644 index 0000000000000..9f1c1bf082c4e --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/category_excluded_from_menu.php @@ -0,0 +1,28 @@ +get(CategoryInterfaceFactory::class); + +/** @var $category Category */ +$category = $categoryFactory->create(); +$category->isObjectNew(true); +$category->setId(3) + ->setName('Category 123') + ->setParentId(2) + ->setPath('1/2/3') + ->setLevel(2) + ->setAvailableSortBy('name') + ->setDefaultSortBy('name') + ->setIncludeInMenu(false) + ->setIsActive(true) + ->setPosition(1) + ->save(); diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/category_excluded_from_menu_rollback.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/category_excluded_from_menu_rollback.php new file mode 100644 index 0000000000000..1e69bad0e86a4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/category_excluded_from_menu_rollback.php @@ -0,0 +1,10 @@ +requireDataFixture('Magento/Catalog/_files/categories_rollback.php');