From c768d0fd5340eeb994dca1d8295d9b8409319011 Mon Sep 17 00:00:00 2001 From: Simon Praetorius <simon@praetorius.me> Date: Fri, 30 Aug 2024 16:06:28 +0200 Subject: [PATCH] [TASK] Avoid calls to TemplatePaths constructor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The constructor of Fluid's `TemplatePath` class allowed both a package name and a configuration array (containing `templateRootPaths`, `layoutRootPaths`, `partialRootPaths` and a `format`). It also tried to set defaults for TYPO3, without the base `TemplatePaths` class being part of TYPO3. To streamline Fluid's API and to untangle Fluid's configuration from TYPO3, both constructor variants have been soft-deprecated with Fluid v2.15 and will log deprecation notices with Fluid v4. In preparation of the switch to Fluid v4, all usages of the constructor are removed from the core. A lot of this work has already been done in previous patches. The remaining usages are related to the `FluidEmail` class, which unfortunately uses Fluid's `TemplatePaths` class as API. In all cases, the default mailer configuration is extended, which is part of the system configuration: from DefaultConfiguration.php: ``` 'MAIL' => [ // Mail configurations to tune how \TYPO3\CMS\Core\Mail\ classes will send their mails. //… 'format' => 'both', 'layoutRootPaths' => [ 0 => 'EXT:core/Resources/Private/Layouts/', 10 => 'EXT:backend/Resources/Private/Layouts/', ], 'partialRootPaths' => [ 0 => 'EXT:core/Resources/Private/Partials/', 10 => 'EXT:backend/Resources/Private/Partials/', ], 'templateRootPaths' => [ 0 => 'EXT:core/Resources/Private/Templates/Email/', 10 => 'EXT:backend/Resources/Private/Templates/Email/', ], ``` `format` is already problematic, because `both` is not a valid value to Fluid. So that value is *not* set in this patch because `FluidEmail` overwrites the value internally anyways once `txt`, `html` or `both` are rendered for an email. The three path arrays are set by using the appropriate setter methods of the `TemplatePaths` object and thus avoiding the deprecated constructor. Merges with additional paths are performed in the same way they were before. Due to slightly different implementations, changes to tests are necessary. The new implementation preserves numeric array keys, while the old implementation didn't. However, the order of the templates stays the same and overriding by key is still possible. Resolves: #104823 Releases: main Change-Id: Iee9e08e3320657bfffa4c069da94efcf0f9ebd2a Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/85832 Reviewed-by: Simon Praetorius <simon@praetorius.me> Tested-by: core-ci <typo3@b13.com> Reviewed-by: Markus Klein <markus.klein@typo3.org> Reviewed-by: Stefan Bürk <stefan@buerk.tech> Tested-by: Simon Praetorius <simon@praetorius.me> Tested-by: Markus Klein <markus.klein@typo3.org> Tested-by: Stefan Bürk <stefan@buerk.tech> --- typo3/sysext/core/Classes/Mail/FluidEmail.php | 8 +++++- .../Configuration/RecoveryConfiguration.php | 28 +++++++++---------- .../RecoveryConfigurationTest.php | 10 +++---- .../Tests/Unit/View/TemplatePathsTest.php | 18 ++++++------ .../Authentication/AuthenticationService.php | 10 +++++-- .../Classes/Task/SystemStatusUpdateTask.php | 11 ++++++-- .../Notification/StageChangeNotification.php | 15 +++++++++- 7 files changed, 64 insertions(+), 36 deletions(-) diff --git a/typo3/sysext/core/Classes/Mail/FluidEmail.php b/typo3/sysext/core/Classes/Mail/FluidEmail.php index 391fca08f7a2..a66b3a5d51af 100644 --- a/typo3/sysext/core/Classes/Mail/FluidEmail.php +++ b/typo3/sysext/core/Classes/Mail/FluidEmail.php @@ -77,7 +77,13 @@ class FluidEmail extends Email // we *could* unpack the paths and format to an array again, we should probably better // redesign this implementation and work on the main comment above along the way. // Also note methods like getViewHelperVariableContainer() are hard-bound to fluid, too. - $templatePaths = $templatePaths ?? new TemplatePaths($GLOBALS['TYPO3_CONF_VARS']['MAIL']); + if ($templatePaths === null) { + $templatePaths = new TemplatePaths(); + $templatePaths->setTemplateRootPaths($GLOBALS['TYPO3_CONF_VARS']['MAIL']['templateRootPaths'] ?? []); + $templatePaths->setLayoutRootPaths($GLOBALS['TYPO3_CONF_VARS']['MAIL']['layoutRootPaths'] ?? []); + $templatePaths->setPartialRootPaths($GLOBALS['TYPO3_CONF_VARS']['MAIL']['partialRootPaths'] ?? []); + } + $this->view->getRenderingContext()->setTemplatePaths($templatePaths); $this->view->assignMultiple($this->getDefaultVariables()); $this->format($GLOBALS['TYPO3_CONF_VARS']['MAIL']['format'] ?? self::FORMAT_BOTH); diff --git a/typo3/sysext/felogin/Classes/Configuration/RecoveryConfiguration.php b/typo3/sysext/felogin/Classes/Configuration/RecoveryConfiguration.php index 8e3ea9e3c96c..6e35ad31db55 100644 --- a/typo3/sysext/felogin/Classes/Configuration/RecoveryConfiguration.php +++ b/typo3/sysext/felogin/Classes/Configuration/RecoveryConfiguration.php @@ -65,20 +65,20 @@ class RecoveryConfiguration implements LoggerAwareInterface */ public function getMailTemplatePaths(): TemplatePaths { - $pathArray = array_replace_recursive( - [ - 'layoutRootPaths' => $GLOBALS['TYPO3_CONF_VARS']['MAIL']['layoutRootPaths'], - 'templateRootPaths' => $GLOBALS['TYPO3_CONF_VARS']['MAIL']['templateRootPaths'], - 'partialRootPaths' => $GLOBALS['TYPO3_CONF_VARS']['MAIL']['partialRootPaths'], - ], - [ - 'layoutRootPaths' => $this->settings['email']['layoutRootPaths'], - 'templateRootPaths' => $this->settings['email']['templateRootPaths'], - 'partialRootPaths' => $this->settings['email']['partialRootPaths'], - ] - ); - - return new TemplatePaths($pathArray); + $templatePaths = new TemplatePaths(); + $templatePaths->setTemplateRootPaths(array_replace( + $GLOBALS['TYPO3_CONF_VARS']['MAIL']['templateRootPaths'] ?? [], + $this->settings['email']['templateRootPaths'] ?? [], + )); + $templatePaths->setLayoutRootPaths(array_replace( + $GLOBALS['TYPO3_CONF_VARS']['MAIL']['layoutRootPaths'] ?? [], + $this->settings['email']['layoutRootPaths'] ?? [], + )); + $templatePaths->setPartialRootPaths(array_replace( + $GLOBALS['TYPO3_CONF_VARS']['MAIL']['partialRootPaths'] ?? [], + $this->settings['email']['partialRootPaths'] ?? [], + )); + return $templatePaths; } /** diff --git a/typo3/sysext/felogin/Tests/Unit/Configuration/RecoveryConfigurationTest.php b/typo3/sysext/felogin/Tests/Unit/Configuration/RecoveryConfigurationTest.php index d4dc934db760..1feff5f57c11 100644 --- a/typo3/sysext/felogin/Tests/Unit/Configuration/RecoveryConfigurationTest.php +++ b/typo3/sysext/felogin/Tests/Unit/Configuration/RecoveryConfigurationTest.php @@ -175,9 +175,9 @@ final class RecoveryConfigurationTest extends UnitTestCase $actualTemplatePaths = $this->subject->getMailTemplatePaths(); self::assertSame( [ - Environment::getPublicPath() . '/typo3/sysext/core/Resources/Private/Templates/', - Environment::getPublicPath() . '/typo3/sysext/backend/Resources/Private/Templates/', - '/some/path/to/a/template/folder/', + 0 => Environment::getPublicPath() . '/typo3/sysext/core/Resources/Private/Templates/', + 10 => Environment::getPublicPath() . '/typo3/sysext/backend/Resources/Private/Templates/', + 20 => '/some/path/to/a/template/folder/', ], $actualTemplatePaths->getTemplateRootPaths() ); @@ -195,8 +195,8 @@ final class RecoveryConfigurationTest extends UnitTestCase $actualTemplatePaths = $this->subject->getMailTemplatePaths(); self::assertSame( [ - Environment::getPublicPath() . '/typo3/sysext/core/Resources/Private/Templates/', - '/some/path/to/a/template/folder/', + 0 => Environment::getPublicPath() . '/typo3/sysext/core/Resources/Private/Templates/', + 10 => '/some/path/to/a/template/folder/', ], $actualTemplatePaths->getTemplateRootPaths() ); diff --git a/typo3/sysext/fluid/Tests/Unit/View/TemplatePathsTest.php b/typo3/sysext/fluid/Tests/Unit/View/TemplatePathsTest.php index d5ba5530433c..8e3c79a34cf4 100644 --- a/typo3/sysext/fluid/Tests/Unit/View/TemplatePathsTest.php +++ b/typo3/sysext/fluid/Tests/Unit/View/TemplatePathsTest.php @@ -77,15 +77,15 @@ final class TemplatePathsTest extends UnitTestCase return [$method, $set, $expected]; }; return [ - 'simple numeric index, template' => $generator(TemplatePaths::CONFIG_TEMPLATEROOTPATHS, 'numeric'), - 'alpha index, template' => $generator(TemplatePaths::CONFIG_TEMPLATEROOTPATHS, 'alpha'), - 'alpha-numeric index, template' => $generator(TemplatePaths::CONFIG_TEMPLATEROOTPATHS, 'alphanumeric'), - 'simple numeric index, partial' => $generator(TemplatePaths::CONFIG_PARTIALROOTPATHS, 'numeric'), - 'alpha index, partial' => $generator(TemplatePaths::CONFIG_PARTIALROOTPATHS, 'alpha'), - 'alpha-numeric index, partial' => $generator(TemplatePaths::CONFIG_PARTIALROOTPATHS, 'alphanumeric'), - 'simple numeric index, layout' => $generator(TemplatePaths::CONFIG_LAYOUTROOTPATHS, 'numeric'), - 'alpha index, layout' => $generator(TemplatePaths::CONFIG_LAYOUTROOTPATHS, 'alpha'), - 'alpha-numeric index, layout' => $generator(TemplatePaths::CONFIG_LAYOUTROOTPATHS, 'alphanumeric'), + 'simple numeric index, template' => $generator('templateRootPaths', 'numeric'), + 'alpha index, template' => $generator('templateRootPaths', 'alpha'), + 'alpha-numeric index, template' => $generator('templateRootPaths', 'alphanumeric'), + 'simple numeric index, partial' => $generator('partialRootPaths', 'numeric'), + 'alpha index, partial' => $generator('partialRootPaths', 'alpha'), + 'alpha-numeric index, partial' => $generator('partialRootPaths', 'alphanumeric'), + 'simple numeric index, layout' => $generator('layoutRootPaths', 'numeric'), + 'alpha index, layout' => $generator('layoutRootPaths', 'alpha'), + 'alpha-numeric index, layout' => $generator('layoutRootPaths', 'alphanumeric'), ]; } diff --git a/typo3/sysext/install/Classes/Authentication/AuthenticationService.php b/typo3/sysext/install/Classes/Authentication/AuthenticationService.php index 7ccab7498e46..56522d4260f8 100644 --- a/typo3/sysext/install/Classes/Authentication/AuthenticationService.php +++ b/typo3/sysext/install/Classes/Authentication/AuthenticationService.php @@ -41,9 +41,13 @@ class AuthenticationService public function __construct(protected readonly MailerInterface $mailer) { - $templateConfiguration = $GLOBALS['TYPO3_CONF_VARS']['MAIL']; - $templateConfiguration['templateRootPaths'][20] = 'EXT:install/Resources/Private/Templates/Email/'; - $this->templatePaths = new TemplatePaths($templateConfiguration); + $this->templatePaths = new TemplatePaths(); + $this->templatePaths->setTemplateRootPaths(array_replace( + $GLOBALS['TYPO3_CONF_VARS']['MAIL']['templateRootPaths'] ?? [], + [20 => 'EXT:install/Resources/Private/Templates/Email/'], + )); + $this->templatePaths->setLayoutRootPaths($GLOBALS['TYPO3_CONF_VARS']['MAIL']['layoutRootPaths'] ?? []); + $this->templatePaths->setPartialRootPaths($GLOBALS['TYPO3_CONF_VARS']['MAIL']['partialRootPaths'] ?? []); } /** diff --git a/typo3/sysext/reports/Classes/Task/SystemStatusUpdateTask.php b/typo3/sysext/reports/Classes/Task/SystemStatusUpdateTask.php index b4ffda55a096..46e0d12da39a 100644 --- a/typo3/sysext/reports/Classes/Task/SystemStatusUpdateTask.php +++ b/typo3/sysext/reports/Classes/Task/SystemStatusUpdateTask.php @@ -116,10 +116,15 @@ class SystemStatusUpdateTask extends AbstractTask $message .= implode(CRLF, $systemIssues); $message .= CRLF . CRLF; - $templateConfiguration = $GLOBALS['TYPO3_CONF_VARS']['MAIL']; - $templateConfiguration['templateRootPaths'][20] = 'EXT:reports/Resources/Private/Templates/Email/'; + $templatePaths = new TemplatePaths(); + $templatePaths->setTemplateRootPaths(array_replace( + $GLOBALS['TYPO3_CONF_VARS']['MAIL']['templateRootPaths'] ?? [], + [20 => 'EXT:reports/Resources/Private/Templates/Email/'], + )); + $templatePaths->setLayoutRootPaths($GLOBALS['TYPO3_CONF_VARS']['MAIL']['layoutRootPaths'] ?? []); + $templatePaths->setPartialRootPaths($GLOBALS['TYPO3_CONF_VARS']['MAIL']['partialRootPaths'] ?? []); - $email = GeneralUtility::makeInstance(FluidEmail::class, new TemplatePaths($templateConfiguration)); + $email = GeneralUtility::makeInstance(FluidEmail::class, $templatePaths); $email ->to(...$sendEmailsTo) ->format('plain') diff --git a/typo3/sysext/workspaces/Classes/Notification/StageChangeNotification.php b/typo3/sysext/workspaces/Classes/Notification/StageChangeNotification.php index c7bdee47bd8e..c27ab8d1ea00 100644 --- a/typo3/sysext/workspaces/Classes/Notification/StageChangeNotification.php +++ b/typo3/sysext/workspaces/Classes/Notification/StageChangeNotification.php @@ -141,7 +141,20 @@ class StageChangeNotification implements LoggerAwareInterface */ protected function sendEmail(array $recipientData, array $emailConfig, array $variablesForView): void { - $templatePaths = new TemplatePaths(array_replace_recursive($GLOBALS['TYPO3_CONF_VARS']['MAIL'], $emailConfig)); + $templatePaths = new TemplatePaths(); + $templatePaths->setTemplateRootPaths(array_replace( + $GLOBALS['TYPO3_CONF_VARS']['MAIL']['templateRootPaths'] ?? [], + $emailConfig['templateRootPaths'] ?? [], + )); + $templatePaths->setLayoutRootPaths(array_replace( + $GLOBALS['TYPO3_CONF_VARS']['MAIL']['layoutRootPaths'] ?? [], + $emailConfig['layoutRootPaths'] ?? [], + )); + $templatePaths->setPartialRootPaths(array_replace( + $GLOBALS['TYPO3_CONF_VARS']['MAIL']['partialRootPaths'] ?? [], + $emailConfig['partialRootPaths'] ?? [], + )); + $emailObject = GeneralUtility::makeInstance(FluidEmail::class, $templatePaths); $emailObject ->to(new Address($recipientData['email'], $recipientData['realName'] ?? '')) -- GitLab