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

183 lines
4.8 KiB
PHP

<?php
declare(strict_types=1);
namespace Esun3d\LanguageUrlStoreResolver\Model;
use Magento\Framework\UrlInterface;
use Magento\Store\Model\StoreManagerInterface;
class UrlPathConverter
{
/**
* @var Config
*/
private $config;
/**
* @var StoreCodeMapper
*/
private $storeCodeMapper;
/**
* @var StoreViewRegistry
*/
private $storeViewRegistry;
/**
* @var StoreManagerInterface
*/
private $storeManager;
public function __construct(
Config $config,
StoreCodeMapper $storeCodeMapper,
StoreViewRegistry $storeViewRegistry,
StoreManagerInterface $storeManager
) {
$this->config = $config;
$this->storeCodeMapper = $storeCodeMapper;
$this->storeViewRegistry = $storeViewRegistry;
$this->storeManager = $storeManager;
}
public function toLanguageUrl(string $url, string $language): string
{
$parts = parse_url($url);
if ($parts === false) {
return $url;
}
if ($this->isExternalUrl($parts)) {
return $url;
}
$path = $parts['path'] ?? '/';
$path = $path === '' ? '/' : $path;
$basePath = $this->getBasePath();
$relativePath = $this->stripBasePath($path, $basePath);
if ($this->config->shouldSkipPath($relativePath)) {
return $url;
}
$parts['path'] = $this->prependBasePath(
$basePath,
$this->convertRelativePath($relativePath, strtolower($language))
);
return $this->buildUrl($parts);
}
/**
* @param mixed[] $parts
*/
private function isExternalUrl(array $parts): bool
{
if (!isset($parts['host'])) {
return false;
}
$baseParts = parse_url($this->storeManager->getStore()->getBaseUrl(UrlInterface::URL_TYPE_WEB));
$baseHost = isset($baseParts['host']) ? strtolower($baseParts['host']) : '';
return strtolower((string)$parts['host']) !== $baseHost;
}
private function convertRelativePath(string $path, string $language): string
{
$path = '/' . ltrim($path, '/');
$segments = explode('/', trim($path, '/'), 2);
$firstSegment = $segments[0] ?? '';
$remainingPath = $segments[1] ?? '';
if ($this->storeCodeMapper->isRealStoreCodeInScope($firstSegment)) {
$language = $this->storeCodeMapper->languageFromStoreCode($firstSegment) ?? $language;
$path = $remainingPath === '' ? '/' : '/' . ltrim($remainingPath, '/');
}
if ($this->storeCodeMapper->isLanguageAllowed(strtolower($firstSegment))) {
$path = $remainingPath === '' ? '/' : '/' . ltrim($remainingPath, '/');
}
if ($this->storeCodeMapper->isDefaultLanguage($language)) {
return $path;
}
return $path === '/' ? '/' . $language . '/' : '/' . $language . $path;
}
private function getBasePath(): string
{
$baseParts = parse_url($this->storeManager->getStore()->getBaseUrl(UrlInterface::URL_TYPE_WEB));
$basePath = isset($baseParts['path']) ? rtrim($baseParts['path'], '/') : '';
return $basePath !== '' ? $basePath : '/';
}
private function stripBasePath(string $path, string $basePath): string
{
if ($basePath === '/' || $basePath === '') {
return '/' . ltrim($path, '/');
}
if ($path === $basePath) {
return '/';
}
if (strpos($path, $basePath . '/') === 0) {
return '/' . ltrim(substr($path, strlen($basePath)), '/');
}
return '/' . ltrim($path, '/');
}
private function prependBasePath(string $basePath, string $path): string
{
$path = '/' . ltrim($path, '/');
if ($basePath === '/' || $basePath === '') {
return $path;
}
return rtrim($basePath, '/') . $path;
}
/**
* @param mixed[] $parts
*/
private function buildUrl(array $parts): string
{
$url = '';
if (isset($parts['host'])) {
$url .= isset($parts['scheme']) ? $parts['scheme'] . '://' : '//';
if (isset($parts['user'])) {
$url .= $parts['user'];
if (isset($parts['pass'])) {
$url .= ':' . $parts['pass'];
}
$url .= '@';
}
$url .= $parts['host'];
if (isset($parts['port'])) {
$url .= ':' . $parts['port'];
}
}
$url .= $parts['path'] ?? '/';
if (isset($parts['query']) && $parts['query'] !== '') {
$url .= '?' . $parts['query'];
}
if (isset($parts['fragment']) && $parts['fragment'] !== '') {
$url .= '#' . $parts['fragment'];
}
return $url;
}
}