diff --git a/README.md b/README.md index 012dc46..dd78162 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ This is especially useful for creating short, memorable links for marketing camp - Hit Count: See how many times an alias is being visited (including the date/time of the last visit) - Test Interface: You can easily test if an alias works as expected (also with browser languages that differ from your default one) - Support for Fragment Identifiers: When the alias target is a page, you can specify the exact point where the browser should land (for example, `/target#point-in-page`) +- Sopport for POST Forwarding: When the users send POST requests to the alias, you can configure the package to forward that data via POST ### How It Works @@ -67,6 +68,7 @@ There you can manage all the URL aliases. - you create an alias named `/alias` that points to `/about` - `/alias` would resolve to `/about` - but `/alias/me` won't resolve to `/about/me` +- Forwarding files via POST is not supported: the package will only forward *normal* fields received via POST ## Do you really want to say thank you? diff --git a/controller.php b/controller.php index 957502e..0ef52fa 100644 --- a/controller.php +++ b/controller.php @@ -19,7 +19,7 @@ class Controller extends Package { protected $pkgHandle = 'url_aliases'; - protected $pkgVersion = '0.0.4'; + protected $pkgVersion = '0.9.0'; /** * {@inheritdoc} diff --git a/controllers/single_page/dashboard/system/url_aliases.php b/controllers/single_page/dashboard/system/url_aliases.php index 5dae5f2..32b72b9 100644 --- a/controllers/single_page/dashboard/system/url_aliases.php +++ b/controllers/single_page/dashboard/system/url_aliases.php @@ -111,6 +111,7 @@ public function saveUrlAlias(): JsonResponse ->setEnabled($post->getBoolean('enabled')) ->setAcceptAdditionalQuerystringParams($post->getBoolean('acceptAdditionalQuerystringParams')) ->setForwardQuerystringParams($post->getBoolean('forwardQuerystringParams')) + ->setForwardPost($post->getBoolean('forwardPost')) ; if ($urlAlias->getPath() === '') { throw new UserMessageException(t('Please specify the path of the alias Url')); @@ -273,6 +274,7 @@ private function serializeUrlAlias(UrlAlias $urlAlias, array $services): array 'targetValue' => $urlAlias->getTargetValue(), 'fragmentIdentifier' => $urlAlias->getFragmentIdentifier(), 'forwardQuerystringParams' => $urlAlias->isForwardQuerystringParams(), + 'forwardPost' => $urlAlias->isForwardPost(), 'firstHit' => ($d = $urlAlias->getFirstHit()) === null ? null : $d->getTimestamp(), 'lastHit' => ($d = $urlAlias->getLastHit()) === null ? null : $d->getTimestamp(), 'hitCount' => $urlAlias->getHitCount(), diff --git a/single_pages/dashboard/system/url-aliases.php b/single_pages/dashboard/system/url-aliases.php index b192231..e33f6c5 100644 --- a/single_pages/dashboard/system/url-aliases.php +++ b/single_pages/dashboard/system/url-aliases.php @@ -337,7 +337,7 @@ function ready() { `, }); - + let uaAcceptHeaderBuilderCounter = 0; Vue.component('ua-accept-header-builder', { @@ -658,7 +658,7 @@ function ready() { this.urlAliases.push(urlAlias); } }, - + testUrlAlias(urlAlias) { if (!urlAlias?.id || !urlAlias.enabled) { return; diff --git a/src/Concrete/Entity/Target.php b/src/Concrete/Entity/Target.php index 885cbf2..344f382 100644 --- a/src/Concrete/Entity/Target.php +++ b/src/Concrete/Entity/Target.php @@ -29,6 +29,11 @@ public function getTargetValue(): string; */ public function isForwardQuerystringParams(): bool; + /** + * Forward POST requests and received data? + */ + public function isForwardPost(): bool; + /** * Get the fragment identifier to be appended to page targets. */ diff --git a/src/Concrete/Entity/UrlAlias.php b/src/Concrete/Entity/UrlAlias.php index d3a0b38..ab4e86d 100644 --- a/src/Concrete/Entity/UrlAlias.php +++ b/src/Concrete/Entity/UrlAlias.php @@ -127,6 +127,15 @@ class UrlAlias implements Target */ protected $forwardQuerystringParams; + /** + * Forward POST requests and received data? + * + * @Doctrine\ORM\Mapping\Column(type="boolean", nullable=false, options={"comment":"Forward POST requests and received data?"}) + * + * @var bool + */ + protected $forwardPost; + /** * The date/time of the first hit. * @@ -176,6 +185,7 @@ public function __construct() $this->targetValue = ''; $this->fragmentIdentifier = ''; $this->forwardQuerystringParams = false; + $this->forwardPost = false; $this->firstHit = null; $this->lastHit = null; $this->hitCount = 0; @@ -377,6 +387,28 @@ public function setForwardQuerystringParams(bool $value): self return $this; } + /** + * Forward POST requests and received data? + * + * @see \Concrete\Package\UrlAliases\Entity\Target::isForwardPost() + */ + public function isForwardPost(): bool + { + return $this->forwardPost; + } + + /** + * Forward POST requests and received data? + * + * @return $this + */ + public function setForwardPost(bool $value): self + { + $this->forwardPost = $value; + + return $this; + } + /** * Get the date/time of the first hit. */ diff --git a/src/Concrete/Entity/UrlAlias/LocalizedTarget.php b/src/Concrete/Entity/UrlAlias/LocalizedTarget.php index 5bd23b4..2919b0a 100644 --- a/src/Concrete/Entity/UrlAlias/LocalizedTarget.php +++ b/src/Concrete/Entity/UrlAlias/LocalizedTarget.php @@ -273,4 +273,14 @@ public function isForwardQuerystringParams(): bool { return $this->getUrlAlias()->isForwardQuerystringParams(); } + + /** + * Forward POST requests and received data? + * + * @see \Concrete\Package\UrlAliases\Entity\Target::isForwardPost() + */ + public function isForwardPost(): bool + { + return $this->getUrlAlias()->isForwardPost(); + } } diff --git a/src/Concrete/RequestResolver.php b/src/Concrete/RequestResolver.php index d014854..e051af9 100644 --- a/src/Concrete/RequestResolver.php +++ b/src/Concrete/RequestResolver.php @@ -23,6 +23,10 @@ final class RequestResolver public const TESTFIELD_OVERRIDEACCEPTLANGUAGE = 'ua-testing_url_aliases_acceptlanguage'; + private const COMMON_RESPONSE_HEADERS = [ + 'Cache-Control' => 'private, no-store, no-cache, must-revalidate', + ]; + /** * @var \Concrete\Package\UrlAliases\Entity\UrlAliasRepository */ @@ -100,13 +104,11 @@ private function buildResponse(Request $request, bool $hitIt, bool $isTesting): if ($isTesting) { return $this->buildTestingResponse(t('Users will be redirected to: %s', $resolved->url)); } - $response = $this->responseFactory->redirect( - $resolved->url, - Response::HTTP_TEMPORARY_REDIRECT, - [ - 'Cache-Control' => 'private, no-store, no-cache, must-revalidate', - ] - ); + if ($target->isForwardPost() && $request->getMethod() === 'POST') { + $response = $this->buildForwardPostResponse($resolved->url, $request); + } else { + $response = $this->buildRedirectResponse($resolved->url); + } if ($hitIt) { $urlAlias->hit(); $this->repo->getEntityManager()->flush(); @@ -253,4 +255,54 @@ private function inspectLocale(string $locale): array return [$language, $script, $territory]; } + + private function buildRedirectResponse(string $targetUrl): Response + { + return $this->responseFactory->redirect($targetUrl, Response::HTTP_TEMPORARY_REDIRECT, self::COMMON_RESPONSE_HEADERS); + } + + private function buildForwardPostResponse(string $targetUrl, Request $request): Response + { + $charset = APP_CHARSET; + $hTargetUrl = htmlspecialchars($targetUrl, ENT_QUOTES, APP_CHARSET); + $html = << + + + + + +
+ +EOT + ; + $renderFields = null; + $renderFields = static function (array $data, string $namePrefix = '') use (&$renderFields, &$html): void { + foreach ($data as $key => $value) { + $key = (string) $key; + $name = $namePrefix === '' ? $key : "{$namePrefix}[{$key}]"; + if (is_array($value)) { + $renderFields($value, $name); + } else { + $escapedName = htmlspecialchars($name, ENT_QUOTES, APP_CHARSET); + $escapedValue = htmlspecialchars((string) $value, ENT_QUOTES, APP_CHARSET); + $html .= << + +EOT + ; + } + } + }; + $renderFields($request->request->all()); + $html .= <<<'EOT' + + + + +EOT + ; + + return new Response($html, Response::HTTP_OK, self::COMMON_RESPONSE_HEADERS); + } } diff --git a/views/dialogs/edit_url_alias.php b/views/dialogs/edit_url_alias.php index cc7a0b7..d7ec6c4 100644 --- a/views/dialogs/edit_url_alias.php +++ b/views/dialogs/edit_url_alias.php @@ -63,6 +63,12 @@ +
+ + +
@@ -115,6 +121,7 @@ function ready() { pathAndQuerystring: getPathAndQuerystring()) ?>, acceptAdditionalQuerystringParams: isAcceptAdditionalQuerystringParams()) ?>, forwardQuerystringParams: isForwardQuerystringParams()) ?>, + forwardPost: isForwardPost()) ?>, enabled: isEnabled()) ?>, askFragmentIdentifier: false, fragmentIdentifier: getFragmentIdentifier()) ?>, @@ -174,6 +181,7 @@ function ready() { acceptAdditionalQuerystringParams: this.acceptAdditionalQuerystringParams, enabled: this.enabled, forwardQuerystringParams: this.forwardQuerystringParams, + forwardPost: this.forwardPost, }; data.targetValue = this.$el.querySelector(`:scope [name="target_${data.targetType}"]`).value; const ev = new CustomEvent('ccm.url_aliases.saveUrlAlias', {