Files
esun3d/app/code/Esun3d/LanguageUrlStoreResolver/ViewModel/LocaleSwitcher.php
T
2026-09-15 10:35:56 +08:00

168 lines
5.6 KiB
PHP

<?php
declare(strict_types=1);
namespace Esun3d\LanguageUrlStoreResolver\ViewModel;
use Esun3d\LanguageUrlStoreResolver\Model\StoreViewRegistry;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\UrlInterface;
use Magento\Framework\View\Element\Block\ArgumentInterface;
use Magento\Store\Model\ScopeInterface;
use Magento\Store\Model\StoreManagerInterface;
class LocaleSwitcher implements ArgumentInterface
{
public function __construct(
private StoreManagerInterface $storeManager,
private StoreViewRegistry $storeViewRegistry,
private ScopeConfigInterface $scopeConfig,
private UrlInterface $urlBuilder
) {
}
/**
* @return array{markets:array<string,mixed>,currentMarket:string,currentLanguage:string}
*/
public function getConfig(): array
{
$currentWebsite = $this->storeManager->getWebsite();
$currentWebsiteCode = (string)$currentWebsite->getCode();
$currentStoreCode = (string)$this->storeManager->getStore()->getCode();
$currentLanguage = $this->storeViewRegistry->getLanguageByStoreCode($currentStoreCode) ?: '';
$relativePath = $this->getRelativeContentPath($currentWebsiteCode, $currentLanguage);
$query = $this->getCleanQuery();
$markets = [];
foreach ($this->storeManager->getWebsites(false) as $website) {
$websiteId = (int)$website->getId();
$defaultStore = $website->getDefaultStore();
if (!$defaultStore || !$defaultStore->isActive()) {
continue;
}
$defaultLanguage = $this->storeViewRegistry->getLanguageByStoreCode((string)$defaultStore->getCode());
if ($defaultLanguage === null) {
continue;
}
$languages = [];
foreach ($website->getStores() as $store) {
if (!$store->isActive()) {
continue;
}
$language = $this->storeViewRegistry->getLanguageByStoreCode((string)$store->getCode());
if ($language === null) {
continue;
}
$languages[$language] = [
'label' => (string)$store->getName(),
'storeCode' => (string)$store->getCode(),
'url' => $this->buildUrl(
$this->getWebsiteBaseUrl((string)$website->getCode()),
$language,
$defaultLanguage,
$relativePath,
$query
),
];
}
if (!$languages) {
continue;
}
$targetLanguage = isset($languages[$currentLanguage]) ? $currentLanguage : $defaultLanguage;
$markets[(string)$website->getCode()] = [
'label' => (string)$website->getName(),
'websiteId' => $websiteId,
'defaultLanguage' => $defaultLanguage,
'url' => $languages[$targetLanguage]['url'] ?? reset($languages)['url'],
'languages' => $languages,
];
}
return [
'markets' => $markets,
'currentMarket' => $currentWebsiteCode,
'currentLanguage' => $currentLanguage,
];
}
private function getRelativeContentPath(string $websiteCode, string $currentLanguage): string
{
$currentPath = trim((string)parse_url($this->getRequestUri(), PHP_URL_PATH), '/');
$basePath = trim((string)parse_url($this->getWebsiteBaseUrl($websiteCode), PHP_URL_PATH), '/');
if ($basePath !== '' && ($currentPath === $basePath || str_starts_with($currentPath, $basePath . '/'))) {
$currentPath = ltrim(substr($currentPath, strlen($basePath)), '/');
}
$segments = $currentPath === '' ? [] : explode('/', $currentPath);
if ($segments && strtolower($segments[0]) === strtolower($currentLanguage)) {
array_shift($segments);
}
return implode('/', $segments);
}
/** @return array<string,mixed> */
private function getCleanQuery(): array
{
$query = [];
parse_str((string)parse_url($this->getRequestUri(), PHP_URL_QUERY), $query);
unset($query['market'], $query['store'], $query['___store'], $query['___from_store']);
return $query;
}
private function getRequestUri(): string
{
return isset($_SERVER['REQUEST_URI'])
? (string)$_SERVER['REQUEST_URI']
: $this->urlBuilder->getCurrentUrl();
}
/** @param array<string,mixed> $query */
private function buildUrl(
string $baseUrl,
string $language,
string $defaultLanguage,
string $relativePath,
array $query
): string {
$url = rtrim($baseUrl, '/') . '/';
if ($language !== $defaultLanguage) {
$url .= rawurlencode($language) . '/';
}
if ($relativePath !== '') {
$url .= ltrim($relativePath, '/');
}
if ($query) {
$url .= '?' . http_build_query($query);
}
return $url;
}
private function getWebsiteBaseUrl(string $websiteCode): string
{
$baseUrl = (string)$this->scopeConfig->getValue(
'web/secure/base_url',
ScopeInterface::SCOPE_WEBSITE,
$websiteCode
);
if ($baseUrl === '') {
$baseUrl = (string)$this->scopeConfig->getValue(
'web/unsecure/base_url',
ScopeInterface::SCOPE_WEBSITE,
$websiteCode
);
}
return $baseUrl;
}
}