storeViewRegistry = $this->createMock(StoreViewRegistry::class); $this->storeViewRegistry->method('isKnownLanguage')->willReturnCallback(static function (string $language): bool { return in_array($language, ['en', 'de'], true); }); $this->storeViewRegistry->method('isKnownStoreCode')->willReturnCallback(static function (string $storeCode): bool { return in_array($storeCode, ['en_US', 'en_DE', 'de_US', 'de_DE'], true); }); $this->storeViewRegistry->method('getLanguageByStoreCode')->willReturnCallback(static function (string $storeCode): ?string { $map = [ 'en_US' => 'en', 'en_DE' => 'en', 'de_US' => 'de', 'de_DE' => 'de', ]; return $map[$storeCode] ?? null; }); $this->storeViewRegistry->method('getDefaultStoreCodeForLanguage')->willReturnCallback( static function (string $language): ?string { $map = [ 'en' => 'en_US', 'de' => 'de_US', ]; return $map[$language] ?? null; } ); $this->storeViewRegistry->method('isLanguageInWebsite')->willReturnCallback( static fn(string $language, int $websiteId): bool => $websiteId === 1 && in_array($language, ['en', 'de'], true) ); $this->storeViewRegistry->method('isStoreCodeInWebsite')->willReturnCallback( static fn(string $storeCode, int $websiteId): bool => $websiteId === 1 && in_array($storeCode, ['en_US', 'en_DE', 'de_US', 'de_DE'], true) ); $this->storeViewRegistry->method('getStoreCodeForLanguageInWebsite')->willReturnCallback( static function (string $language, int $websiteId): ?string { if ($websiteId !== 1) { return null; } return ['en' => 'en_US', 'de' => 'de_US'][$language] ?? null; } ); $defaultStore = $this->createMock(Store::class); $defaultStore->method('getCode')->willReturn('en_US'); $website = $this->createMock(Website::class); $website->method('getId')->willReturn(1); $website->method('getDefaultStore')->willReturn($defaultStore); $this->storeManager = $this->createMock(StoreManagerInterface::class); $this->storeManager->method('getWebsite')->willReturn($website); } /** * @dataProvider productPathProvider */ public function testResolvesLanguageFromProductPath(string $pathInfo, ?string $expectedLanguage): void { $resolver = new LanguageResolver($this->storeViewRegistry, $this->storeManager); self::assertSame($expectedLanguage, $resolver->resolveFromPath($pathInfo)); } /** * @return mixed[] */ public static function productPathProvider(): array { return [ 'english product path' => ['/en/product-a', 'en'], 'german product path' => ['/de/product-a', 'de'], 'english language root' => ['/en', 'en'], 'real store code is not language' => ['/en_US/product-a', null], 'unsupported prefix' => ['/fr/product-a', null], ]; } /** * @dataProvider stripProductPathProvider */ public function testStripsLanguagePrefixBeforeUrlRewrite(string $pathInfo, string $expectedPathInfo): void { $processor = new RequestPathProcessor(new LanguageResolver($this->storeViewRegistry, $this->storeManager)); self::assertSame($expectedPathInfo, $processor->stripLanguagePrefix($pathInfo)); } /** * @return mixed[] */ public static function stripProductPathProvider(): array { return [ 'english product path' => ['/en/product-a', '/product-a'], 'german product path' => ['/de/product-a', '/product-a'], 'nested product path' => ['/de/category/product-a', '/category/product-a'], 'language root' => ['/en', '/'], 'non language path unchanged' => ['/product-a', '/product-a'], ]; } /** * @dataProvider replaceProductPathProvider */ public function testReplacesLanguagePrefixForMarketSwitch(string $pathInfo, string $language, string $expectedPathInfo): void { $processor = new RequestPathProcessor(new LanguageResolver($this->storeViewRegistry, $this->storeManager)); self::assertSame($expectedPathInfo, $processor->replaceLanguagePrefix($pathInfo, $language)); } /** * @return mixed[] */ public static function replaceProductPathProvider(): array { return [ 'german product path switches to english' => [ '/de/privacy-policy-cookie-restriction-mode/', 'en', '/en/privacy-policy-cookie-restriction-mode/', ], 'english product path switches to german' => [ '/en/product-a', 'de', '/de/product-a', ], 'language root keeps trailing slash' => [ '/de/', 'en', '/en/', ], ]; } /** * @dataProvider storeMappingProvider */ public function testMapsProductPathLanguageAndMarketToRealStoreCode( string $language, ?string $market, ?string $expectedStoreCode ): void { $mapper = new StoreCodeMapper($this->storeViewRegistry, $this->storeManager); self::assertSame($expectedStoreCode, $mapper->map($language, $market)); } /** * @return mixed[] */ public static function storeMappingProvider(): array { return [ 'english US product path' => ['en', 'en_US', 'en_US'], 'english DE product path' => ['en', 'en_DE', 'en_DE'], 'german US product path' => ['de', 'de_US', 'de_US'], 'german DE product path' => ['de', 'de_DE', 'de_DE'], 'english path ignores german market and uses default' => ['en', 'de_DE', 'en_US'], 'unknown language has no default' => ['fr', null, null], ]; } public function testUsesLanguageSpecificDefaultStoreFromRegistry(): void { $mapper = new StoreCodeMapper($this->storeViewRegistry, $this->storeManager); self::assertSame('en_US', $mapper->getDefaultStoreCodeForLanguage('en')); self::assertSame('de_US', $mapper->getDefaultStoreCodeForLanguage('de')); } public function testUsesCurrentWebsiteWhenLanguageExistsInMultipleWebsites(): void { $registry = $this->createMock(StoreViewRegistry::class); $registry->expects(self::once()) ->method('getStoreCodeForLanguageInWebsite') ->with('de', 1) ->willReturn('de_EU'); $mapper = new StoreCodeMapper($registry, $this->storeManager); self::assertSame('de_EU', $mapper->getDefaultStoreCodeForLanguage('de')); } }