diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Url.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Url.php new file mode 100644 index 000000000000..81bc3fbe51bf --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Url.php @@ -0,0 +1,62 @@ +config = $config; + } + + /** + * Set Attribute instance, Rewrite for redefine attribute scope + * + * @param Attribute $attribute + * @return $this + */ + public function setAttribute($attribute) + { + parent::setAttribute($attribute); + $this->setScope($attribute); + return $this; + } + + /** + * Redefine Attribute scope + * + * @param Attribute $attribute + * @return void + */ + private function setScope(Attribute $attribute): void + { + if ($this->config->getValue( + ProductScopeRewriteGenerator::URL_REWRITE_SCOPE_CONFIG_PATH, + ScopeInterface::SCOPE_STORE + ) == ProductScopeRewriteGenerator::WEBSITE_URL_REWRITE_SCOPE) { + $attribute->setIsGlobal(ScopedAttributeInterface::SCOPE_WEBSITE); + } else { + $attribute->setIsGlobal(ScopedAttributeInterface::SCOPE_STORE); + } + } +} diff --git a/app/code/Magento/Catalog/Setup/Patch/Data/UpdateProductUrlKeyBackendModel.php b/app/code/Magento/Catalog/Setup/Patch/Data/UpdateProductUrlKeyBackendModel.php new file mode 100644 index 000000000000..cb7ec396625e --- /dev/null +++ b/app/code/Magento/Catalog/Setup/Patch/Data/UpdateProductUrlKeyBackendModel.php @@ -0,0 +1,89 @@ +moduleDataSetup = $moduleDataSetup; + $this->eavSetupFactory = $eavSetupFactory; + } + + /** + * @inheritDoc + */ + public static function getDependencies() + { + return []; + } + + /** + * @inheritDoc + */ + public function getAliases() + { + return []; + } + + /** + * @inheritDoc + */ + public function apply() + { + $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]); + + $eavSetup->updateAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'url_key', + [ + 'backend_model' => Url::class + ] + ); + return $this; + } + + /** + * @inheritDoc + */ + public function revert() + { + $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]); + + $eavSetup->updateAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'url_key', + [ + 'backend_model' => '' + ] + ); + return $this; + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Backend/UrlTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Backend/UrlTest.php new file mode 100644 index 000000000000..b2d51731ac56 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Backend/UrlTest.php @@ -0,0 +1,54 @@ +config = $this->createMock(ScopeConfigInterface::class); + parent::setUp(); + } + + /** + * @return void + * @throws Exception + */ + public function testSetAttribute(): void + { + $attribute = $this->createMock(Attribute::class); + $attribute->expects($this->once()) + ->method('__call') + ->with('setIsGlobal', [ScopedAttributeInterface::SCOPE_WEBSITE]); + $this->config->expects($this->once()) + ->method('getValue') + ->with(ProductScopeRewriteGenerator::URL_REWRITE_SCOPE_CONFIG_PATH, ScopeInterface::SCOPE_STORE) + ->willReturn(ProductScopeRewriteGenerator::WEBSITE_URL_REWRITE_SCOPE); + + $url = new Url($this->config); + $url->setAttribute($attribute); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/GeneralTest.php b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/GeneralTest.php index 8a4a4ad46513..f568c828d15f 100644 --- a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/GeneralTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/GeneralTest.php @@ -1,75 +1,76 @@ attributeRepositoryMock = $this->getMockBuilder(AttributeRepositoryInterface::class) - ->getMockForAbstractClass(); - - $arrayManager = $this->objectManager->getObject(ArrayManager::class); - - $this->generalModifier = $this->objectManager->getObject( - General::class, - [ - 'attributeRepository' => $this->attributeRepositoryMock, - 'locator' => $this->locatorMock, - 'arrayManager' => $arrayManager, - ] - ); + $this->attributeRepositoryMock = $this->createMock(AttributeRepositoryInterface::class); + $this->arrayManager = $this->createMock(ArrayManager::class); + $this->locatorMock = $this->createMock(LocatorInterface::class); } /** - * {@inheritdoc} + * @return void + * @throws Exception */ - protected function createModel() + public function testModifyMeta(): void { - return $this->objectManager->getObject( - General::class, - [ - 'locator' => $this->locatorMock, - 'arrayManager' => $this->arrayManagerMock, - ] - ); - } - - public function testModifyMeta() - { - $this->arrayManagerMock->expects($this->any()) + $attribute = $this->createMock(Attribute::class); + $this->attributeRepositoryMock->expects($this->any()) + ->method('get') + ->willReturn($attribute); + $this->arrayManager->expects($this->any()) ->method('merge') ->willReturnArgument(2); + $store = $this->createMock(Store::class); + $this->locatorMock->expects($this->any())->method('getStore')->willReturn($store); + $product = $this->createMock(ProductInterface::class); + $this->locatorMock->expects($this->any())->method('getProduct')->willReturn($product); + + $generalModifier = new General($this->locatorMock, $this->arrayManager, $this->attributeRepositoryMock); $this->assertNotEmpty( - $this->getModel()->modifyMeta( + $generalModifier->modifyMeta( [ 'first_panel_code' => [ 'arguments' => [ @@ -86,27 +87,28 @@ public function testModifyMeta() } /** - * @param array $data - * @param int $defaultStatusValue - * @param array $expectedResult - * @throws NoSuchEntityException + * @param array $data + * @param int $defaultStatusValue + * @param array $expectedResult + * @return void + * @throws NoSuchEntityException + * @throws Exception * @dataProvider modifyDataDataProvider */ - public function testModifyDataNewProduct(array $data, int $defaultStatusValue, array $expectedResult) + public function testModifyDataNewProduct(array $data, int $defaultStatusValue, array $expectedResult): void { - $attributeMock = $this->getMockBuilder(AttributeInterface::class) - ->getMockForAbstractClass(); + $attributeMock = $this->createMock(AttributeInterface::class); $attributeMock ->method('getDefaultValue') ->willReturn($defaultStatusValue); $this->attributeRepositoryMock ->method('get') - ->with( - ProductAttributeInterface::ENTITY_TYPE_CODE, - ProductAttributeInterface::CODE_STATUS - ) ->willReturn($attributeMock); - $this->assertSame($expectedResult, $this->generalModifier->modifyData($data)); + $this->arrayManager->expects($this->any())->method('replace')->willReturn($data); + $product = $this->createMock(ProductInterface::class); + $this->locatorMock->expects($this->any())->method('getProduct')->willReturn($product); + $generalModifier = new General($this->locatorMock, $this->arrayManager, $this->attributeRepositoryMock); + $this->assertSame($expectedResult, $generalModifier->modifyData($data)); } /** @@ -117,7 +119,7 @@ public function testModifyDataNewProduct(array $data, int $defaultStatusValue, a * @param int $defaultStatus * @param int $statusAttributeValue * @param array $expectedResult - * @throws NoSuchEntityException + * @throws NoSuchEntityException|Exception * @dataProvider modifyDataOfExistingProductDataProvider */ public function testModifyDataOfExistingProduct( @@ -126,25 +128,26 @@ public function testModifyDataOfExistingProduct( int $defaultStatus, int $statusAttributeValue, array $expectedResult - ) { - $attributeMock = $this->getMockForAbstractClass(AttributeInterface::class); + ): void { + $attributeMock = $this->createMock(AttributeInterface::class); $attributeMock->expects($this->any()) ->method('getDefaultValue') ->willReturn($defaultStatus); $this->attributeRepositoryMock->expects($this->any()) ->method('get') - ->with( - ProductAttributeInterface::ENTITY_TYPE_CODE, - ProductAttributeInterface::CODE_STATUS - ) ->willReturn($attributeMock); - $this->productMock->expects($this->any()) + $product = $this->createMock(ProductInterface::class); + $product->expects($this->any()) ->method('getId') ->willReturn($modelId); - $this->productMock->expects($this->any()) + $product->expects($this->any()) ->method('getStatus') ->willReturn($statusAttributeValue); - $this->assertSame($expectedResult, current($this->generalModifier->modifyData($data))); + $this->locatorMock->expects($this->any())->method('getProduct')->willReturn($product); + $this->arrayManager->expects($this->any())->method('replace')->willReturn($data); + + $generalModifier = new General($this->locatorMock, $this->arrayManager, $this->attributeRepositoryMock); + $this->assertSame($expectedResult, current($generalModifier->modifyData($data))); } /** diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/General.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/General.php index 4e3b21939934..37de215536c2 100644 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/General.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/General.php @@ -392,6 +392,18 @@ protected function customizeNameListeners(array $meta) ] ); + $urlAttribute = $this->attributeRepository->get( + ProductAttributeInterface::ENTITY_TYPE_CODE, + ProductAttributeInterface::CODE_SEO_FIELD_URL_KEY + ); + $scopeLabel = ''; + if ($urlAttribute->isScopeGlobal()) { + $scopeLabel = '[GLOBAL]'; + } elseif ($urlAttribute->isScopeWebsite()) { + $scopeLabel = '[WEBSITE]'; + } elseif ($urlAttribute->isScopeStore()) { + $scopeLabel = '[STORE VIEW]'; + } $urlKeyConfig = [ 'tooltip' => [ 'link' => 'https://experienceleague.adobe.com/docs/commerce-admin/catalog/catalog/catalog-urls.html', @@ -399,6 +411,7 @@ protected function customizeNameListeners(array $meta) 'The URL key should consist of lowercase characters with hyphens to separate words.' ), ], + 'scopeLabel' => __($scopeLabel) ]; $urkKeyPath = $this->arrayManager->findPath( diff --git a/app/code/Magento/CatalogSearch/etc/adminhtml/system.xml b/app/code/Magento/CatalogSearch/etc/adminhtml/system.xml index f825d3ee50d8..278a78eaa132 100644 --- a/app/code/Magento/CatalogSearch/etc/adminhtml/system.xml +++ b/app/code/Magento/CatalogSearch/etc/adminhtml/system.xml @@ -1,8 +1,8 @@ diff --git a/app/code/Magento/CatalogUrlRewrite/Model/ProductScopeRewriteGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/ProductScopeRewriteGenerator.php index 3c230a73b03e..e5aa45595790 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/ProductScopeRewriteGenerator.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/ProductScopeRewriteGenerator.php @@ -1,7 +1,7 @@ mergeDataProviderPrototype; + $mergeDataProvider->merge(array_merge(...$this->generateCanonicalUrls($product, $storeId))); + $categories = []; + if ($this->isCategoryRewritesEnabled()) { + foreach ($productCategories as $category) { + if (!$this->isCategoryProperForGenerating($category, $storeId)) { + continue; + } - foreach ($productCategories as $category) { - if (!$this->isCategoryProperForGenerating($category, $storeId)) { - continue; + $categories[] = $this->getCategoryWithOverriddenUrlKey($storeId, $category); } - - $categories[] = $this->getCategoryWithOverriddenUrlKey($storeId, $category); } - - $mergeDataProvider->merge( - $this->canonicalUrlRewriteGenerator->generate($storeId, $product) - ); - $productCategories = $this->objectRegistryFactory->create(['entities' => $categories]); if ($isGlobalScope) { @@ -280,13 +287,38 @@ public function isCategoryProperForGenerating(Category $category, $storeId) return false; } + /** + * Generate product canonical URL in website or store view scope + * + * @param Product $product + * @param mixed $storeId + * @return array + * @throws NoSuchEntityException + */ + private function generateCanonicalUrls(Product $product, mixed $storeId): array + { + $urls = []; + if ($this->config->getValue(self::URL_REWRITE_SCOPE_CONFIG_PATH) === self::WEBSITE_URL_REWRITE_SCOPE) { + $currentStore = $this->storeManager->getStore($storeId); + $currentGroupId = $currentStore->getStoreGroupId(); + $storeList = $this->storeManager->getStores(); + foreach ($storeList as $store) { + if ($store->getStoreGroupId() === $currentGroupId) { + $urls[] = $this->canonicalUrlRewriteGenerator->generate($store->getId(), $product); + } + } + } else { + $urls[] = $this->canonicalUrlRewriteGenerator->generate($storeId, $product); + } + return $urls; + } + /** * Generate category URLs for the whole store group. * * @param int $storeId * @param Product $product * @param ObjectRegistry $productCategories - * * @return array * @throws NoSuchEntityException */ @@ -295,20 +327,24 @@ private function generateCategoryUrlsInStoreGroup( Product $product, ObjectRegistry $productCategories ): array { - $currentStore = $this->storeManager->getStore($storeId); - $currentGroupId = $currentStore->getStoreGroupId(); - $storeList = $this->storeManager->getStores(); $generatedUrls = []; - - foreach ($storeList as $store) { - if ($store->getStoreGroupId() === $currentGroupId && $this->isCategoryRewritesEnabled()) { - $groupStoreId = (int) $store->getId(); - $generatedUrls[] = $this->generateCategoryUrls( - $groupStoreId, - $product, - $productCategories - ); + if ($this->config->getValue(self::URL_REWRITE_SCOPE_CONFIG_PATH) === self::WEBSITE_URL_REWRITE_SCOPE) { + $currentStore = $this->storeManager->getStore($storeId); + $currentGroupId = $currentStore->getStoreGroupId(); + $storeList = $this->storeManager->getStores(); + + foreach ($storeList as $store) { + if ($store->getStoreGroupId() === $currentGroupId && $this->isCategoryRewritesEnabled()) { + $groupStoreId = (int)$store->getId(); + $generatedUrls[] = $this->generateCategoryUrls( + $groupStoreId, + $product, + $productCategories + ); + } } + } else { + $generatedUrls[] = $this->generateCategoryUrls($storeId, $product, $productCategories); } return array_merge(...$generatedUrls); @@ -375,7 +411,7 @@ private function getCategoryWithOverriddenUrlKey($storeId, Category $category) * * @return bool */ - private function isCategoryRewritesEnabled() + private function isCategoryRewritesEnabled(): bool { return (bool)$this->config->getValue('catalog/seo/generate_category_product_rewrites'); } diff --git a/app/code/Magento/CatalogUrlRewrite/Model/System/Config/Source/UrlRewriteContext.php b/app/code/Magento/CatalogUrlRewrite/Model/System/Config/Source/UrlRewriteContext.php new file mode 100644 index 000000000000..facb4f8ed4a6 --- /dev/null +++ b/app/code/Magento/CatalogUrlRewrite/Model/System/Config/Source/UrlRewriteContext.php @@ -0,0 +1,26 @@ + ProductScopeRewriteGenerator::WEBSITE_URL_REWRITE_SCOPE, 'label' => __('Website')], + ['value' => ProductScopeRewriteGenerator::STORE_VIEW_URL_REWRITE_SCOPE, 'label' => __('Store View')] + ]; + } +} diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductScopeRewriteGeneratorTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductScopeRewriteGeneratorTest.php index ee58a3debc24..17a584c2b357 100644 --- a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductScopeRewriteGeneratorTest.php +++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/ProductScopeRewriteGeneratorTest.php @@ -1,7 +1,7 @@ configMock->expects($this->any())->method('getValue') - ->with('catalog/seo/generate_category_product_rewrites') ->willReturn('1'); $product = $this->createMock(Product::class); $product->expects($this->any())->method('getStoreId')->willReturn(null); @@ -240,6 +239,7 @@ public function testGenerationForSpecificStore() ->willReturn([]); $this->categoryRepositoryMock->expects($this->once())->method('get')->willReturn($this->categoryMock); + $this->configMock->expects($this->any())->method('getValue')->willReturn('1'); $this->assertEquals( ['category-1_1' => $canonical], diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/System/Config/Source/UrlRewriteContextTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/System/Config/Source/UrlRewriteContextTest.php new file mode 100644 index 000000000000..927ab855275b --- /dev/null +++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/System/Config/Source/UrlRewriteContextTest.php @@ -0,0 +1,29 @@ +assertEquals( + [ + ['value' => 'website', 'label' => __('Website')], + ['value' => 'store_view', 'label' => __('Store View')] + ], + $contextRewriteOptions->toOptionArray() + ); + } +} diff --git a/app/code/Magento/CatalogUrlRewrite/etc/adminhtml/system.xml b/app/code/Magento/CatalogUrlRewrite/etc/adminhtml/system.xml index ccd077e61522..e36144588d5c 100644 --- a/app/code/Magento/CatalogUrlRewrite/etc/adminhtml/system.xml +++ b/app/code/Magento/CatalogUrlRewrite/etc/adminhtml/system.xml @@ -1,8 +1,8 @@ @@ -35,6 +35,11 @@ Warning! Turning this option off will result in permanent removal of category/product URL rewrites without an ability to restore them.]]> generate_category_product_rewrites + + + Magento\CatalogUrlRewrite\Model\System\Config\Source\UrlRewriteContext + When editing a product URL rewrites can be generated in website or in view scope. + diff --git a/app/code/Magento/CatalogUrlRewrite/etc/config.xml b/app/code/Magento/CatalogUrlRewrite/etc/config.xml index 116982c7da31..f8bac39a030a 100644 --- a/app/code/Magento/CatalogUrlRewrite/etc/config.xml +++ b/app/code/Magento/CatalogUrlRewrite/etc/config.xml @@ -1,8 +1,8 @@ @@ -10,6 +10,7 @@ 0 + store_view diff --git a/app/code/Magento/CatalogUrlRewrite/i18n/en_US.csv b/app/code/Magento/CatalogUrlRewrite/i18n/en_US.csv index 0def4f6de32e..4d9d2992e728 100644 --- a/app/code/Magento/CatalogUrlRewrite/i18n/en_US.csv +++ b/app/code/Magento/CatalogUrlRewrite/i18n/en_US.csv @@ -10,3 +10,5 @@ "Invalid URL key. The ""%1"" URL key can not be used to generate Latin URL key. Please use Latin letters and numbers to avoid generating URL key issues.","Invalid URL key. The ""%1"" URL key can not be used to generate Latin URL key. Please use Latin letters and numbers to avoid generating URL key issues." "Invalid URL key. The ""%1"" category name can not be used to generate Latin URL key. Please add URL key or change category name using Latin letters and numbers to avoid generating URL key issues.","Invalid URL key. The ""%1"" category name can not be used to generate Latin URL key. Please add URL key or change category name using Latin letters and numbers to avoid generating URL key issues." "Warning! Turning this option off will result in permanent removal of category/product URL rewrites without an ability to restore them.","Warning! Turning this option off will result in permanent removal of category/product URL rewrites without an ability to restore them." +"Product URL Rewrite Scope","Product URL Rewrite Scope" +"When editing a product, URL rewrites can be generated in website or in view scope.","When editing a product, URL rewrites can be generated in website or in view scope." diff --git a/dev/tests/integration/framework/Magento/TestFramework/ApplicationStateComparator/_files/state-skip-list.php b/dev/tests/integration/framework/Magento/TestFramework/ApplicationStateComparator/_files/state-skip-list.php index 17c42090fb2e..2ec1b38761dc 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/ApplicationStateComparator/_files/state-skip-list.php +++ b/dev/tests/integration/framework/Magento/TestFramework/ApplicationStateComparator/_files/state-skip-list.php @@ -272,6 +272,7 @@ ], '*-fromConstructed' => [ // phpcs:disable Generic.Files.LineLength.TooLong + Magento\Catalog\Model\Product\Attribute\Backend\Url\Interceptor::class => null, Magento\Customer\Model\Cache\GroupExcludedWebsiteCache::class => null, Magento\Sales\Model\ResourceModel\Grid::class => null, Magento\Sales\Model\ResourceModel\GridPool::class => null, diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserverTest.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserverTest.php index 3b1a36f84fa1..6de238d292d0 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserverTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserverTest.php @@ -1,7 +1,7 @@ productRepository = $this->objectManager->get(ProductRepositoryInterface::class); $this->urlPersist = $this->objectManager->get(UrlPersistInterface::class); $this->fixtures = $this->objectManager->get(DataFixtureStorageManager::class)->getStorage(); + $this->mutableConfig = $this->objectManager->get(MutableScopeConfigInterface::class); } /** @@ -714,6 +721,7 @@ public function testRemoveProductFromAllWebsites(): void ] public function testNotVisibleOnDefaultStoreVisibleOnDefaultScope() { + $this->mutableConfig->setValue('catalog/seo/generate_category_product_rewrites', 1); $category = $this->fixtures->get('category'); $product = $this->fixtures->get('product'); $secondStore = $this->fixtures->get('store2'); @@ -780,21 +788,21 @@ public function testUrlRewriteGenerationBasedOnScopeVisibility() ]; $actualResults = $this->getActualResults($productFilter); - $this->assertCount(4, $actualResults); + $this->assertCount(2, $actualResults); $productScopeStore1 = $this->productRepository->get($product->getSku(), true, 1); $productScopeStore1->setVisibility(Visibility::VISIBILITY_NOT_VISIBLE); $this->productRepository->save($productScopeStore1); $actualResults = $this->getActualResults($productFilter); - $this->assertCount(2, $actualResults); + $this->assertCount(1, $actualResults); $productGlobal = $this->productRepository->get($product->getSku(), true, Store::DEFAULT_STORE_ID); $productGlobal->setVisibility(Visibility::VISIBILITY_IN_CATALOG); $this->productRepository->save($productGlobal); $actualResults = $this->getActualResults($productFilter); - $this->assertCount(2, $actualResults); + $this->assertCount(1, $actualResults); $expected = [ [ @@ -803,13 +811,6 @@ public function testUrlRewriteGenerationBasedOnScopeVisibility() 'is_auto_generated' => 1, 'redirect_type' => 0, 'store_id' => $secondStore->getId(), - ], - [ - 'request_path' => $category->getUrlKey() . '/' . $product->getUrlKey() . '.html', - 'target_path' => 'catalog/product/view/id/' . $product->getId() . '/category/' . $category->getId(), - 'is_auto_generated' => 1, - 'redirect_type' => 0, - 'store_id' => $secondStore->getId(), ] ]; diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/UrlRewriteHandlerTest.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/UrlRewriteHandlerTest.php index 0ffc84173f71..3d1724df4201 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/UrlRewriteHandlerTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/UrlRewriteHandlerTest.php @@ -1,7 +1,7 @@ handler = $this->objectManager->create(UrlRewriteHandler::class); } + /** + * Checks category URLs rewrites generation with enabled `Use Categories Path for Product URLs` option and + * store's specific product URL key in store view context. + * + * @magentoDataFixture Magento/CatalogUrlRewrite/Fixtures/product_custom_url_key.php + * @magentoConfigFixture admin_store catalog/seo/product_use_categories 1 + * @magentoConfigFixture default/catalog/seo/generate_category_product_rewrites 1 + * @magentoConfigFixture default/catalog/seo/product_rewrite_context store_view + * + * @return void + * @throws NoSuchEntityException + */ + public function testGenerateProductUrlRewriteStoreViewContext(): void + { + $product = $this->productRepository->get('p002'); + $category = $this->getCategory('category 1'); + // change the category scope to the global + $category->setStoreId(1) + ->setChangedProductIds([$product->getId()]) + ->setAffectedProductIds([$product->getId()]) + ->setAnchorsAbove(false); + + $generatedUrls = $this->handler->generateProductUrlRewrites($category); + $actual = array_values( + array_map( + function (UrlRewrite $urlRewrite) { + return $urlRewrite->getRequestPath(); + }, + $generatedUrls + ) + ); + + $expected = [ + 'store-1-key.html', + 'cat-1/store-1-key.html' + ]; + self::assertEquals($expected, $actual, 'Generated URLs rewrites do not match.'); + } + /** * Checks category URLs rewrites generation with enabled `Use Categories Path for Product URLs` option and * store's specific product URL key. @@ -54,8 +94,12 @@ protected function setUp(): void * @magentoDataFixture Magento/CatalogUrlRewrite/Fixtures/product_custom_url_key.php * @magentoConfigFixture admin_store catalog/seo/product_use_categories 1 * @magentoConfigFixture default/catalog/seo/generate_category_product_rewrites 1 + * @magentoConfigFixture default/catalog/seo/product_rewrite_context website + * + * @return void + * @throws NoSuchEntityException */ - public function testGenerateProductUrlRewrites() + public function testGenerateProductUrlRewritesWebsiteContext(): void { $product = $this->productRepository->get('p002'); $category = $this->getCategory('category 1'); @@ -77,8 +121,10 @@ function (UrlRewrite $urlRewrite) { $expected = [ 'store-1-key.html', // the Default store + 'store-1-key.html', // the Secondary store 'cat-1/store-1-key.html', // the Default store with Category URL key, first store view 'cat-1/store-1-key.html', // the Default store with Category URL key, second store view + 'p002.html', // the Default store 'p002.html', // the Secondary store 'cat-1-2/p002.html', // the Secondary store with Category URL key, first store view 'cat-1-2/p002.html', // the Secondary store with Category URL key, second store view @@ -89,8 +135,11 @@ function (UrlRewrite $urlRewrite) { /** * @magentoDataFixture Magento/CatalogUrlRewrite/_files/category_with_products.php * @magentoConfigFixture default/catalog/seo/generate_category_product_rewrites 1 + * + * @return void + * @throws NoSuchEntityException */ - public function testGenerateProductUrlRewrites2() + public function testGenerateProductUrlRewrites2(): void { $product1 = $this->productRepository->get('simple'); $product2 = $this->productRepository->get('12345');