From 5e35593f2c3b88fffd6d06d8018b3068115eae7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BCrk?= Date: Thu, 18 Dec 2025 14:10:09 +0100 Subject: [PATCH] [BUGFIX] DPL-151: Mitigate "Undefined array key" in "LanguageService" Following issue has been reported by a user of the extension: ``` Core: Exception handler (WEB): Uncaught TYPO3 Exception: WebVision\DeeplWrite\Domain\Enum\RephraseSupportedDeepLLanguage::tryFrom(): Argument #1 ($language) must be of type string, null given, called in vendor/web-vision/deepl-write/Classes/Service/LanguageService.php on line 18 | TypeError thrown in file vendor/web-vision/deepl-write/Classes/Domain/Enum/RephraseSupportedDeepLLanguage.php in line 59. Core: Error handler (BE): PHP Warning: Undefined array key "deeplWriteLanguage" in vendor/web-vision/deepl-write/Classes/Service/LanguageService.php line 16 ``` In case the language configuration in the SiteConfig has not been done yet the array key does not exists and the current code tries to access the array with a key not existing in the array, honered with the above error and exception. The array access is now guarded using `null-coalsce` fallback in the `LangaugeService` and also ensuring that the result is really a string, falling back to an empty string and mitigates the issue. Functional tests have been added to cover the `LanguageService` and one test specifically added for the above mentioned issue failes if the change to fix the issue is reverted. > [!IMPORTANT] > Functional test infrastructure for this package not in place > yet and not active in github action workflow. Will be done > in a dedicated change. However, added tests works using the > functional test of the private deepltranslate root development > setup (internally). --- Classes/Service/LanguageService.php | 3 +- Tests/Functional/Service/DeeplServiceTest.php | 4 + .../Service/LanguageServiceTest.php | 164 ++++++++++++++++++ 3 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 Tests/Functional/Service/LanguageServiceTest.php diff --git a/Classes/Service/LanguageService.php b/Classes/Service/LanguageService.php index efd4570..e486ba1 100644 --- a/Classes/Service/LanguageService.php +++ b/Classes/Service/LanguageService.php @@ -13,8 +13,7 @@ public function getTargetLanguageForRephrasing(SiteInterface $site, int $targetL { $targetLanguage = $site->getLanguageById($targetLanguage); $targetLanguageConfiguration = $targetLanguage->toArray(); - $deeplWriteLanguage = $targetLanguageConfiguration['deeplWriteLanguage']; - + $deeplWriteLanguage = (string)($targetLanguageConfiguration['deeplWriteLanguage'] ?? ''); return RephraseSupportedDeepLLanguage::tryFrom($deeplWriteLanguage); } } diff --git a/Tests/Functional/Service/DeeplServiceTest.php b/Tests/Functional/Service/DeeplServiceTest.php index c8908ad..bf04cc4 100644 --- a/Tests/Functional/Service/DeeplServiceTest.php +++ b/Tests/Functional/Service/DeeplServiceTest.php @@ -10,6 +10,10 @@ final class DeeplServiceTest extends AbstractDeepLTestCase { + protected array $coreExtensionsToLoad = [ + 'typo3/cms-setup', + ]; + protected array $testExtensionsToLoad = [ 'web-vision/deepl-base', 'web-vision/deepl-write', diff --git a/Tests/Functional/Service/LanguageServiceTest.php b/Tests/Functional/Service/LanguageServiceTest.php new file mode 100644 index 0000000..5953a7a --- /dev/null +++ b/Tests/Functional/Service/LanguageServiceTest.php @@ -0,0 +1,164 @@ + [ + 'deepl_write' => [ + 'apiKey' => 'mock_server', + ], + ], + ]; + + #[Test] + public function getTargetLanguageForRephrasingReturnsNullIfDeeplWriteLanguageDoesNotExistsInSiteConfig(): void + { + $site = new Site( + identifier: 'dummy', + rootPageId: 1, + configuration: [ + 'languages' => [ + [ + 'languageId' => 0, + 'enabled' => true, + 'title' => 'English', + 'base' => '/', + 'locale' => 'en_US.UTF-8', + 'navigationTitle' => 'English', + 'flag' => 'us', + 'typo3Language' => 'default', + 'iso-639-1' => 'en', + 'hreflang' => 'en-us', + 'direction' => 'ltr', + 'websiteTitle' => '', + ], + [ + 'languageId' => 1, + 'enabled' => true, + 'title' => 'Deutsch', + 'base' => '/de/', + 'locale' => 'de_DE.UTF-8', + 'navigationTitle' => 'English', + 'flag' => 'us', + 'typo3Language' => 'de', + 'iso-639-1' => 'de', + 'hreflang' => 'de-de', + 'direction' => 'ltr', + 'websiteTitle' => '', + ], + ], + ], + settings: null, + ); + $targetSite = $this->get(LanguageService::class)->getTargetLanguageForRephrasing($site, 1); + static::assertNull($targetSite); + } + + #[Test] + public function getTargetLanguageForRephasingReturnsNullForInvalidConfiguredDeeplWriteLanguage(): void + { + $site = new Site( + identifier: 'dummy', + rootPageId: 1, + configuration: [ + 'languages' => [ + [ + 'languageId' => 0, + 'enabled' => true, + 'title' => 'English', + 'base' => '/', + 'locale' => 'en_US.UTF-8', + 'navigationTitle' => 'English', + 'flag' => 'us', + 'typo3Language' => 'default', + 'iso-639-1' => 'en', + 'hreflang' => 'en-us', + 'direction' => 'ltr', + 'websiteTitle' => '', + ], + [ + 'languageId' => 1, + 'enabled' => true, + 'title' => 'Deutsch', + 'base' => '/de/', + 'locale' => 'de_DE.UTF-8', + 'navigationTitle' => 'English', + 'flag' => 'us', + 'typo3Language' => 'de', + 'iso-639-1' => 'de', + 'hreflang' => 'de-de', + 'direction' => 'ltr', + 'websiteTitle' => '', + 'deeplWriteLanguage' => 'RU', + ], + ], + ], + settings: null, + ); + $targetSite = $this->get(LanguageService::class)->getTargetLanguageForRephrasing($site, 1); + static::assertNull($targetSite); + } + + #[Test] + public function getTargetLanguageForRephrasingReturnsValidConfiguredDeeplWriteLanguage(): void + { + $site = new Site( + identifier: 'dummy', + rootPageId: 1, + configuration: [ + 'languages' => [ + [ + 'languageId' => 0, + 'enabled' => true, + 'title' => 'English', + 'base' => '/', + 'locale' => 'en_US.UTF-8', + 'navigationTitle' => 'English', + 'flag' => 'us', + 'typo3Language' => 'default', + 'iso-639-1' => 'en', + 'hreflang' => 'en-us', + 'direction' => 'ltr', + 'websiteTitle' => '', + ], + [ + 'languageId' => 1, + 'enabled' => true, + 'title' => 'Deutsch', + 'base' => '/de/', + 'locale' => 'de_DE.UTF-8', + 'navigationTitle' => 'English', + 'flag' => 'us', + 'typo3Language' => 'de', + 'iso-639-1' => 'de', + 'hreflang' => 'de-de', + 'direction' => 'ltr', + 'websiteTitle' => '', + 'deeplWriteLanguage' => 'DE', + ], + ], + ], + settings: null, + ); + $targetSite = $this->get(LanguageService::class)->getTargetLanguageForRephrasing($site, 1); + static::assertSame('DE', $targetSite); + } +}