From 9933a0d3f747e95e4711dd64560351928eb183ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Tue, 16 Jun 2026 11:17:24 +0200 Subject: [PATCH] feat: webhook form finisher for generic post requests addresses #869cupm97 --- .../Classes/Form/AbstractMappedFinisher.php | 43 +++++++++++++++++++ .../ep_theme/Classes/Form/BpnApiFinisher.php | 28 +++--------- .../ep_theme/Classes/Form/WebhookFinisher.php | 40 +++++++++++++++++ .../Configuration/Yaml/BaseSetup.yaml | 2 + .../Yaml/FormFinishersBackend.yaml | 31 +++++++++++++ .../Yaml/FormFinishersFrontend.yaml | 8 ++++ 6 files changed, 129 insertions(+), 23 deletions(-) create mode 100644 public/typo3conf/ext/ep_theme/Classes/Form/AbstractMappedFinisher.php create mode 100644 public/typo3conf/ext/ep_theme/Classes/Form/WebhookFinisher.php diff --git a/public/typo3conf/ext/ep_theme/Classes/Form/AbstractMappedFinisher.php b/public/typo3conf/ext/ep_theme/Classes/Form/AbstractMappedFinisher.php new file mode 100644 index 00000000..0c48a151 --- /dev/null +++ b/public/typo3conf/ext/ep_theme/Classes/Form/AbstractMappedFinisher.php @@ -0,0 +1,43 @@ +finisherContext->getFormValues(); + $mappingOption = (string)$this->parseOption('mapping'); + $mappings = GeneralUtility::trimExplode(',', $mappingOption, true); + + foreach ($mappings as $mapping) { + $parts = GeneralUtility::trimExplode(':', $mapping, true, 2); + if (2 !== count($parts)) { + continue; + } + + [$remote, $local] = $parts; + if ('' === $remote || '' === $local || false === array_key_exists($local, $formValues)) { + continue; + } + + $values[$remote] = $formValues[$local]; + } + + return $values; + } + + protected function logWarning(string $message, array $context = []): void + { + GeneralUtility::makeInstance(LogManager::class) + ->getLogger(static::class) + ->warning($message, array_merge([ + 'finisher' => static::class, + ], $context)); + } +} diff --git a/public/typo3conf/ext/ep_theme/Classes/Form/BpnApiFinisher.php b/public/typo3conf/ext/ep_theme/Classes/Form/BpnApiFinisher.php index 4b7cea0b..c115ebb4 100644 --- a/public/typo3conf/ext/ep_theme/Classes/Form/BpnApiFinisher.php +++ b/public/typo3conf/ext/ep_theme/Classes/Form/BpnApiFinisher.php @@ -3,10 +3,8 @@ namespace EP\EpTheme\Form; use EP\EpProducts\MyEP\ApiClient; -use TYPO3\CMS\Core\Utility\GeneralUtility; -use TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher; -class BpnApiFinisher extends AbstractFinisher +class BpnApiFinisher extends AbstractMappedFinisher { /** * @var ApiClient @@ -24,30 +22,14 @@ class BpnApiFinisher extends AbstractFinisher protected function executeInternal() { try { - $values = []; - $formValues = $this->finisherContext->getFormValues(); - $mappingOption = (string)$this->parseOption('mapping'); - $mappings = GeneralUtility::trimExplode(',', $mappingOption, true); - - foreach ($mappings as $mapping) { - $parts = GeneralUtility::trimExplode(':', $mapping, true, 2); - if (2 !== count($parts)) { - continue; - } - - [$remote, $local] = $parts; - if ('' === $remote || '' === $local || false === array_key_exists($local, $formValues)) { - continue; - } - - $values[$remote] = $formValues[$local]; - } - + $values = $this->buildPayload(); if ([] !== $values) { $this->apiClient->registerAddress($values); } } catch (\Throwable $e) { - // Intentionally ignore all errors so the form submission stays silent. + $this->logWarning('Bpn API finisher request failed.', [ + 'exception' => $e, + ]); } } } diff --git a/public/typo3conf/ext/ep_theme/Classes/Form/WebhookFinisher.php b/public/typo3conf/ext/ep_theme/Classes/Form/WebhookFinisher.php new file mode 100644 index 00000000..1c943952 --- /dev/null +++ b/public/typo3conf/ext/ep_theme/Classes/Form/WebhookFinisher.php @@ -0,0 +1,40 @@ +parseOption('url')); + if ('' === $url) { + return; + } + + $payload = $this->buildPayload(); + if ([] === $payload) { + return; + } + + $response = HttpClient::create()->request('POST', $url, [ + 'json' => $payload, + ]); + + $statusCode = $response->getStatusCode(); + if ($statusCode < 200 || $statusCode >= 300) { + $this->logWarning('Webhook finisher returned an unexpected response status.', [ + 'url' => $url, + 'statusCode' => $statusCode, + ]); + } + } catch (\Throwable $e) { + $this->logWarning('Webhook finisher request failed.', [ + 'exception' => $e, + ]); + } + } +} diff --git a/public/typo3conf/ext/ep_theme/Configuration/Yaml/BaseSetup.yaml b/public/typo3conf/ext/ep_theme/Configuration/Yaml/BaseSetup.yaml index e566b69a..7aa95971 100644 --- a/public/typo3conf/ext/ep_theme/Configuration/Yaml/BaseSetup.yaml +++ b/public/typo3conf/ext/ep_theme/Configuration/Yaml/BaseSetup.yaml @@ -23,6 +23,8 @@ TYPO3: finishersDefinition: BpnApiFinisher: implementationClassName: 'EP\EpTheme\Form\BpnApiFinisher' + WebhookFinisher: + implementationClassName: 'EP\EpTheme\Form\WebhookFinisher' AddReferrerFinisher: implementationClassName: 'EP\EpTheme\Form\AddReferrerFinisher' diff --git a/public/typo3conf/ext/ep_theme/Configuration/Yaml/FormFinishersBackend.yaml b/public/typo3conf/ext/ep_theme/Configuration/Yaml/FormFinishersBackend.yaml index 2edef0c8..fffa595f 100644 --- a/public/typo3conf/ext/ep_theme/Configuration/Yaml/FormFinishersBackend.yaml +++ b/public/typo3conf/ext/ep_theme/Configuration/Yaml/FormFinishersBackend.yaml @@ -12,6 +12,9 @@ TYPO3: 1000: value: 'BpnApiFinisher' label: 'BusPro Finisher' + 1050: + value: 'WebhookFinisher' + label: 'Webhook Finisher' 1100: value: 'AddReferrerFinisher' label: 'Referrer Finisher' @@ -31,6 +34,27 @@ TYPO3: propertyPath: 'options.mapping' propertyValidators: 10: 'NotEmpty' + 1050: + identifier: 'WebhookFinisher' + editors: + __inheritances: + 10: 'TYPO3.CMS.Form.mixins.formElementMixins.BaseCollectionEditorsMixin' + 100: + label: 'Webhook Finisher' + 110: + identifier: 'mapping' + templateName: 'Inspector-TextEditor' + label: 'Mapping' + propertyPath: 'options.mapping' + propertyValidators: + 10: 'NotEmpty' + 120: + identifier: 'url' + templateName: 'Inspector-TextEditor' + label: 'URL' + propertyPath: 'options.url' + propertyValidators: + 10: 'NotEmpty' 1100: identifier: 'AddReferrerFinisher' editors: @@ -46,6 +70,13 @@ TYPO3: predefinedDefaults: options: mapping: 'lastName:text-1,firstName:text-2,gender:singleselect-1,email:email-1,phone:telephone-1' + WebhookFinisher: + formEditor: + iconIdentifier: 'form-finisher' + predefinedDefaults: + options: + mapping: 'lastName:text-1,firstName:text-2,gender:singleselect-1,email:email-1,phone:telephone-1' + url: '' AddReferrerFinisher: formEditor: iconIdentifier: 'form-finisher' diff --git a/public/typo3conf/ext/ep_theme/Configuration/Yaml/FormFinishersFrontend.yaml b/public/typo3conf/ext/ep_theme/Configuration/Yaml/FormFinishersFrontend.yaml index 000c78da..2ed440f3 100644 --- a/public/typo3conf/ext/ep_theme/Configuration/Yaml/FormFinishersFrontend.yaml +++ b/public/typo3conf/ext/ep_theme/Configuration/Yaml/FormFinishersFrontend.yaml @@ -11,6 +11,14 @@ TYPO3: options: identifier: 'BpnApiFinisher' mapping: 'lastName:text-1,firstName:text-2,gender:singleselect-1,email:email-1,phone:telephone-1' + WebhookFinisher: + implementationClassName: 'EP\EpTheme\Form\WebhookFinisher' + formEditor: + label: 'Webhook Finisher' + options: + identifier: 'WebhookFinisher' + mapping: 'lastName:text-1,firstName:text-2,gender:singleselect-1,email:email-1,phone:telephone-1' + url: '' AddReferrerFinisher: implementationClassName: 'EP\EpTheme\Form\AddReferrerFinisher' formEditor: