Files
MageSail/Magesail/Plugin/Store/TunnelStoreBaseUrlPlugin.php
T
snxraven cc456a4cfa feat(magesail): multi-tunnel registry, per-tunnel stores, and admin UX
- Add TunnelRegistry (var/magesail_tunnels.json) and TunnelProcessPaths;
  migrate legacy magesail_tunnel_store.json and PID/key files
- Provision unique store codes per tunnel; website/group selection;
  stop vs remove; per-tunnel NGINX map, cron, status/logtail
- Fix log path: use DirectoryList::LOG (not LOG_DIR)
- Ignore missing store codes for MAGE_RUN_* (stale nginx / magesail_tunnel)
- Allow duplicate local ports; Admin port presets 443/80/8080 + custom;
  update docs and system.xml comments
2026-03-21 00:49:07 -05:00

92 lines
3.4 KiB
PHP

<?php
declare(strict_types=1);
namespace MageSail\Magesail\Plugin\Store;
use Magento\Framework\App\Request\Http;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\UrlInterface;
use Magento\Store\Model\Store;
use MageSail\Magesail\Model\TunnelRequestDetector;
use MageSail\Magesail\Model\TunnelRegistry;
/**
* With tunnel proxy, HTTP_HOST is dev.myshop.local but store base URLs point at production (e.g. s1.x64.world).
* Rewrite scheme/host for page/link base URLs only — never for static/media/js or asset bases break (404).
* When persisted tunnel base URLs use a different path than production (e.g. no /pub/), use the tunnel path so
* backend URI validation matches the browser.
*/
class TunnelStoreBaseUrlPlugin
{
public function __construct(
private readonly RequestInterface $request,
private readonly TunnelRequestDetector $tunnelRequestDetector,
private readonly TunnelRegistry $tunnelRegistry
) {
}
/**
* @param Store $subject
* @param string $result
* @return string
*/
public function afterGetBaseUrl(Store $subject, $result, $type = null, $secure = null)
{
if (!$this->request instanceof Http || $result === '' || $result === null) {
return $result;
}
$effectiveType = $type ?? UrlInterface::URL_TYPE_LINK;
if (!\in_array($effectiveType, [
UrlInterface::URL_TYPE_LINK,
UrlInterface::URL_TYPE_DIRECT_LINK,
UrlInterface::URL_TYPE_WEB,
], true)) {
return $result;
}
if ($this->tunnelRequestDetector->getTunnelStoreCode($this->request) === null) {
return $result;
}
$parts = parse_url($result);
if ($parts === false || empty($parts['host'])) {
return $result;
}
$requestHost = $this->request->getHttpHost();
if ($requestHost === '' || strcasecmp((string) $parts['host'], $requestHost) === 0) {
return $result;
}
$scheme = $this->request->isSecure() ? 'https' : 'http';
$path = $this->pathForTunnelRewrite($scheme, $parts['path'] ?? '/', (string) $subject->getCode());
$query = isset($parts['query']) ? '?' . $parts['query'] : '';
$fragment = isset($parts['fragment']) ? '#' . $parts['fragment'] : '';
return $scheme . '://' . $requestHost . $path . $query . $fragment;
}
/**
* Prefer path from persisted tunnel base URL (matches holesail vhost) when production base path differs.
*/
private function pathForTunnelRewrite(string $scheme, string $fallbackPath, string $storeCode): string
{
$state = $this->tunnelRegistry->getByStoreCode($storeCode);
if ($state === null) {
return $fallbackPath;
}
$preferSecure = $scheme === 'https';
$ref = $preferSecure ? $state['secure_base_url'] : $state['unsecure_base_url'];
if (trim((string) $ref) === '') {
$ref = $preferSecure ? $state['unsecure_base_url'] : $state['secure_base_url'];
}
if (trim((string) $ref) === '') {
return $fallbackPath;
}
$parsed = parse_url((string) $ref);
if ($parsed === false) {
return $fallbackPath;
}
$path = $parsed['path'] ?? '';
if ($path === '' || $path === null) {
return '/';
}
return $path;
}
}