initiatione
This commit is contained in:
commit
627caccdaf
9 changed files with 346 additions and 0 deletions
57
src/DevOps/AppUrlNormalizer.php
Normal file
57
src/DevOps/AppUrlNormalizer.php
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace SumediaStage\DevOps;
|
||||
|
||||
use Shopware\Core\DevOps\Environment\EnvironmentHelperTransformerData;
|
||||
use Shopware\Core\DevOps\Environment\EnvironmentHelperTransformerInterface;
|
||||
|
||||
/**
|
||||
* Normalizes APP_URL by stripping the path component.
|
||||
*
|
||||
* This allows a Shopware installation licensed for "https://example.com" to run
|
||||
* under a subdirectory like "https://example.com/stage/" without triggering
|
||||
* AppUrlChangeDetectedException or plugin license violations.
|
||||
*
|
||||
* Configuration is injected via configure() by the SystemConfigSubscriber.
|
||||
*/
|
||||
class AppUrlNormalizer implements EnvironmentHelperTransformerInterface
|
||||
{
|
||||
private static bool $enabled = true;
|
||||
|
||||
private static ?string $baseUrl = null;
|
||||
|
||||
public static function configure(bool $enabled, ?string $baseUrl): void
|
||||
{
|
||||
self::$enabled = $enabled;
|
||||
self::$baseUrl = $baseUrl ?: null;
|
||||
}
|
||||
|
||||
public static function transform(EnvironmentHelperTransformerData $data): void
|
||||
{
|
||||
if ($data->getKey() !== 'APP_URL' || !self::$enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self::$baseUrl !== null) {
|
||||
$data->setValue(rtrim(self::$baseUrl, '/'));
|
||||
return;
|
||||
}
|
||||
|
||||
$url = $data->getValue();
|
||||
if (!\is_string($url)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$parsed = parse_url($url);
|
||||
if ($parsed === false || empty($parsed['host'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$normalized = ($parsed['scheme'] ?? 'https') . '://' . $parsed['host'];
|
||||
if (isset($parsed['port'])) {
|
||||
$normalized .= ':' . $parsed['port'];
|
||||
}
|
||||
|
||||
$data->setValue($normalized);
|
||||
}
|
||||
}
|
||||
62
src/Resources/config/config.xml
Normal file
62
src/Resources/config/config.xml
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/shopware/shopware/trunk/src/Core/System/SystemConfig/Schema/config.xsd">
|
||||
|
||||
<card>
|
||||
<title>Sumedia Stage</title>
|
||||
<title lang="de-DE">Sumedia Stage</title>
|
||||
|
||||
<input-field type="bool">
|
||||
<name>normalizeAppUrl</name>
|
||||
<label>Normalize APP_URL (strip subdirectory)</label>
|
||||
<label lang="de-DE">APP_URL normalisieren (Unterverzeichnis entfernen)</label>
|
||||
<helpText>
|
||||
TECHNICAL BACKGROUND: Shopware stores APP_URL alongside the Shop ID (core.app.shopId) and compares it on every request via ShopIdProvider. If live uses "https://example.com" but stage uses "https://example.com/stage/", Shopware throws AppUrlChangeDetectedException and plugins report license errors.
|
||||
|
||||
HOW IT WORKS: This plugin registers an EnvironmentHelperTransformer that intercepts every internal APP_URL read and strips the path component before Shopware sees it. Both live and stage then present the same base URL to Shopware.
|
||||
|
||||
Example: https://example.com/stage/ becomes https://example.com
|
||||
|
||||
Safe to enable on live instances – if APP_URL has no path, the transformer is a no-op.
|
||||
|
||||
Changes take effect after cache:clear.
|
||||
</helpText>
|
||||
<helpText lang="de-DE">
|
||||
TECHNISCHER HINTERGRUND: Shopware speichert APP_URL zusammen mit der Shop-ID (core.app.shopId) und vergleicht sie bei jedem Request via ShopIdProvider. Weichen Live ("https://example.com") und Stage ("https://example.com/stage/") ab, wirft Shopware eine AppUrlChangeDetectedException und Plugins melden Lizenzfehler.
|
||||
|
||||
FUNKTIONSWEISE: Das Plugin registriert einen EnvironmentHelperTransformer, der jeden internen APP_URL-Lesezugriff abfängt und den Pfad-Anteil entfernt, bevor Shopware ihn verarbeitet. Damit sehen Live und Stage dieselbe Basis-URL.
|
||||
|
||||
Beispiel: https://example.com/stage/ wird zu https://example.com
|
||||
|
||||
Auf Live-Instanzen ohne Pfad ist der Transformer wirkungslos.
|
||||
|
||||
Aenderungen greifen nach cache:clear.
|
||||
</helpText>
|
||||
<defaultValue>true</defaultValue>
|
||||
</input-field>
|
||||
|
||||
<input-field type="text">
|
||||
<name>baseUrl</name>
|
||||
<label>Base URL override (optional)</label>
|
||||
<label lang="de-DE">Basis-URL manuell setzen (optional)</label>
|
||||
<helpText>
|
||||
Leave empty for automatic detection – the transformer extracts scheme and host from APP_URL automatically.
|
||||
|
||||
Set this only if auto-detection produces a wrong result, e.g. behind a reverse proxy that alters the Host header.
|
||||
|
||||
Format: https://www.example.com (no trailing slash)
|
||||
</helpText>
|
||||
<helpText lang="de-DE">
|
||||
Leer lassen fuer automatische Erkennung – der Transformer extrahiert Scheme und Host automatisch aus APP_URL.
|
||||
|
||||
Nur setzen, wenn die automatische Erkennung ein falsches Ergebnis liefert, z. B. hinter einem Reverse-Proxy, der den Host-Header veraendert.
|
||||
|
||||
Format: https://www.example.com (kein abschliessender Slash)
|
||||
</helpText>
|
||||
<defaultValue></defaultValue>
|
||||
</input-field>
|
||||
|
||||
</card>
|
||||
|
||||
</config>
|
||||
BIN
src/Resources/config/plugin.png
Normal file
BIN
src/Resources/config/plugin.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
16
src/Resources/config/services.xml
Normal file
16
src/Resources/config/services.xml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" ?>
|
||||
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<services>
|
||||
|
||||
<service id="SumediaStage\Subscriber\SystemConfigSubscriber">
|
||||
<argument type="service" id="Shopware\Core\System\SystemConfig\SystemConfigService" />
|
||||
<tag name="kernel.event_subscriber" />
|
||||
</service>
|
||||
|
||||
</services>
|
||||
|
||||
</container>
|
||||
39
src/Subscriber/SystemConfigSubscriber.php
Normal file
39
src/Subscriber/SystemConfigSubscriber.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace SumediaStage\Subscriber;
|
||||
|
||||
use Shopware\Core\System\SystemConfig\SystemConfigService;
|
||||
use SumediaStage\DevOps\AppUrlNormalizer;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
|
||||
class SystemConfigSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
private bool $configured = false;
|
||||
|
||||
public function __construct(private readonly SystemConfigService $systemConfigService)
|
||||
{
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
KernelEvents::REQUEST => ['onKernelRequest', 512],
|
||||
];
|
||||
}
|
||||
|
||||
public function onKernelRequest(RequestEvent $event): void
|
||||
{
|
||||
if ($this->configured) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->configured = true;
|
||||
|
||||
$enabled = (bool) ($this->systemConfigService->get('SumediaStage.config.normalizeAppUrl') ?? true);
|
||||
$baseUrl = (string) ($this->systemConfigService->get('SumediaStage.config.baseUrl') ?? '');
|
||||
|
||||
AppUrlNormalizer::configure($enabled, $baseUrl ?: null);
|
||||
}
|
||||
}
|
||||
45
src/SumediaStage.php
Normal file
45
src/SumediaStage.php
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace SumediaStage;
|
||||
|
||||
use Shopware\Core\DevOps\Environment\EnvironmentHelper;
|
||||
use Shopware\Core\Framework\Plugin;
|
||||
use Shopware\Core\Framework\Plugin\Context\ActivateContext;
|
||||
use SumediaStage\DevOps\AppUrlNormalizer;
|
||||
|
||||
class SumediaStage extends Plugin
|
||||
{
|
||||
public function boot(): void
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
if (!$this->isAllowed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
EnvironmentHelper::addTransformer(AppUrlNormalizer::class);
|
||||
}
|
||||
|
||||
public function activate(ActivateContext $activateContext): void
|
||||
{
|
||||
if ((string) EnvironmentHelper::getVariable('APP_ENV') === 'prod') {
|
||||
throw new \RuntimeException(
|
||||
'SumediaStage must not be activated in production (APP_ENV=prod). '
|
||||
. 'This plugin is intended for staging and local environments only.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function isAllowed(): bool
|
||||
{
|
||||
if ((string) EnvironmentHelper::getVariable('APP_ENV') === 'prod') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((string) EnvironmentHelper::getVariable('SUMEDIA_STAGE_ENABLED', '1') === '0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue