From 1f4a2f0f5646050f7d587ca10c77e3f1b66851e2 Mon Sep 17 00:00:00 2001 From: Stephen Abello Date: Thu, 4 Sep 2025 14:57:24 +0200 Subject: [PATCH 1/2] =?UTF-8?q?N=C2=B08579=20-=20Fix=20calls=20to=20Twig?= =?UTF-8?q?=20"spaceless"=20deprecated=20filter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sources/Application/TwigBase/Twig/Extension.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sources/Application/TwigBase/Twig/Extension.php b/sources/Application/TwigBase/Twig/Extension.php index 22844f858..09ddb718b 100644 --- a/sources/Application/TwigBase/Twig/Extension.php +++ b/sources/Application/TwigBase/Twig/Extension.php @@ -154,6 +154,12 @@ class Extension return twig_array_filter($oTwigEnv, $array, $arrow); }, ['needs_environment' => true]); + // @since 3.3.0 N°8579 + // Filter to remove spaces between HTML tags, overwrite the deprecated core "spaceless" filter + $aFilters[] = new TwigFilter('spaceless', function (?string $content) { + return trim(preg_replace('/>\s+<', $content ?? '')); + }, ['is_safe' => ['html']]); + return $aFilters; } From 4ed21dc21a9500243f4a7058d694c40a12948bd3 Mon Sep 17 00:00:00 2001 From: Stephen Abello Date: Mon, 22 Sep 2025 16:24:58 +0200 Subject: [PATCH 2/2] =?UTF-8?q?N=C2=B07920=20-=20Replace=20Symfony=20sendm?= =?UTF-8?q?ail=20transport=20with=20PHP=20mail()=20transport?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/composer/autoload_classmap.php | 1 + lib/composer/autoload_static.php | 1 + sources/Core/Email/EmailSymfony.php | 3 +- .../Transport/SymfonyPHPMailTransport.php | 98 +++++++++++++++++++ 4 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 sources/Core/Email/Transport/SymfonyPHPMailTransport.php diff --git a/lib/composer/autoload_classmap.php b/lib/composer/autoload_classmap.php index 4d2ac1dbf..d98cfc88e 100644 --- a/lib/composer/autoload_classmap.php +++ b/lib/composer/autoload_classmap.php @@ -419,6 +419,7 @@ return array( 'Combodo\\iTop\\Core\\Email\\EmailFactory' => $baseDir . '/sources/Core/Email/EmailFactory.php', 'Combodo\\iTop\\Core\\Email\\Transport\\SymfonyFileTransport' => $baseDir . '/sources/Core/Email/Transport/SymfonyFileTransport.php', 'Combodo\\iTop\\Core\\Email\\Transport\\SymfonyOAuthTransport' => $baseDir . '/sources/Core/Email/Transport/SymfonyOAuthTransport.php', + 'Combodo\\iTop\\Core\\Email\\Transport\\SymfonyPHPMailTransport' => $baseDir . '/sources/Core/Email/Transport/SymfonyPHPMailTransport.php', 'Combodo\\iTop\\Core\\Email\\iEMail' => $baseDir . '/sources/Core/Email/iEMail.php', 'Combodo\\iTop\\Core\\EventListener\\AttributeBlobEventListener' => $baseDir . '/sources/Core/EventListener/AttributeBlobEventListener.php', 'Combodo\\iTop\\Core\\Kpi\\KpiLogData' => $baseDir . '/sources/Core/Kpi/KpiLogData.php', diff --git a/lib/composer/autoload_static.php b/lib/composer/autoload_static.php index d0478b9c6..4b1fc5b95 100644 --- a/lib/composer/autoload_static.php +++ b/lib/composer/autoload_static.php @@ -784,6 +784,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f 'Combodo\\iTop\\Core\\Email\\EmailFactory' => __DIR__ . '/../..' . '/sources/Core/Email/EmailFactory.php', 'Combodo\\iTop\\Core\\Email\\Transport\\SymfonyFileTransport' => __DIR__ . '/../..' . '/sources/Core/Email/Transport/SymfonyFileTransport.php', 'Combodo\\iTop\\Core\\Email\\Transport\\SymfonyOAuthTransport' => __DIR__ . '/../..' . '/sources/Core/Email/Transport/SymfonyOAuthTransport.php', + 'Combodo\\iTop\\Core\\Email\\Transport\\SymfonyPHPMailTransport' => __DIR__ . '/../..' . '/sources/Core/Email/Transport/SymfonyPHPMailTransport.php', 'Combodo\\iTop\\Core\\Email\\iEMail' => __DIR__ . '/../..' . '/sources/Core/Email/iEMail.php', 'Combodo\\iTop\\Core\\EventListener\\AttributeBlobEventListener' => __DIR__ . '/../..' . '/sources/Core/EventListener/AttributeBlobEventListener.php', 'Combodo\\iTop\\Core\\Kpi\\KpiLogData' => __DIR__ . '/../..' . '/sources/Core/Kpi/KpiLogData.php', diff --git a/sources/Core/Email/EmailSymfony.php b/sources/Core/Email/EmailSymfony.php index 21c961125..1e648cf10 100644 --- a/sources/Core/Email/EmailSymfony.php +++ b/sources/Core/Email/EmailSymfony.php @@ -12,6 +12,7 @@ use AsyncSendEmail; use Combodo\iTop\Core\Authentication\Client\OAuth\OAuthClientProviderFactory; use Combodo\iTop\Core\Email\Transport\SymfonyFileTransport; use Combodo\iTop\Core\Email\Transport\SymfonyOAuthTransport; +use Combodo\iTop\Core\Email\Transport\SymfonyPHPMailTransport; use DOMDocument; use DOMXPath; use EMail; @@ -232,7 +233,7 @@ class EMailSymfony extends Email case 'PHPMail': default: // Use sendmail transport - $oTransport = Transport::fromDsn('sendmail://default'); + $oTransport = new SymfonyPHPMailTransport(); $oMailer = new Mailer($oTransport); } diff --git a/sources/Core/Email/Transport/SymfonyPHPMailTransport.php b/sources/Core/Email/Transport/SymfonyPHPMailTransport.php new file mode 100644 index 000000000..6c969c598 --- /dev/null +++ b/sources/Core/Email/Transport/SymfonyPHPMailTransport.php @@ -0,0 +1,98 @@ +getHeaders(); + + return $oHeaders->get('To')->getBodyAsString(); + } + + /** + * @param Email $oRawEmail + * + * @return string + */ + private function prepareSubject(Email $oRawEmail): string + { + $oHeaders = $oRawEmail->getHeaders(); + return $oHeaders->get('Subject')->getBodyAsString(); + } + + + /** + * @param Email $oRawEmail + * + * @return string + */ + public function prepareBody(Email $oRawEmail): string + { + return $oRawEmail->getBody() ? $oRawEmail->getBody()->bodyToString() : ''; + } + + /** + * @param Email $oRawEmail + * + * @return string + */ + public function prepareHeaders(Email $oRawEmail): string + { + $oHeaders = $oRawEmail->getPreparedHeaders(); + // Render all headers except "To" (mail() has a dedicated argument for that), including body headers + $sHeaders = ''; + foreach ($oHeaders->all() as $header) { + if (strtolower($header->getName()) !== 'to' && strtolower($header->getName()) !== 'subject') { + $sHeaders .= $header->toString() . "\r\n"; + } + } + + $oBodyHeader = $oRawEmail->getBody()->getPreparedHeaders(); + foreach ($oBodyHeader->all() as $header) { + $sHeaders .= $header->toString() . "\r\n"; + } + + // Remove trailing line break + $sHeaders = rtrim($sHeaders, "\r\n"); + return $sHeaders; + } + + protected function doSend(SentMessage $message): void + { + $oRawEmail = $message->getOriginalMessage(); + + if (!$oRawEmail instanceof Email) { + throw new \LogicException('SymfonyPHPMailTransport only supports Email instances.'); + } + + $sTo = $this->prepareTo($oRawEmail); + $sSubject = $this->prepareSubject($oRawEmail); + $sBody = $this->prepareBody($oRawEmail); + $sHeaders = $this->prepareHeaders($oRawEmail); + + $success = mail($sTo, $sSubject, $sBody, $sHeaders); + + + if (!$success) { + throw new \RuntimeException('The mail() function failed to send the message. Check server mail configuration.'); + } + } + + public function __toString(): string + { + return 'phpmail://default'; + } +} \ No newline at end of file