From 605e25682637dc0b63bd95d147995a48dad1a154 Mon Sep 17 00:00:00 2001 From: Markus Hofmann Date: Thu, 30 Oct 2025 10:46:06 +0100 Subject: [PATCH] [BUGFIX] Set correct autoconfigure for ProcessingInstruction During testing in another extension, it showed up, that `ProcessingInstruction` was not configured correctly. Change the autoload for this class and adopt all other classes using php attributes instead of registration via `Services.yaml`. With this change the autoload is made on the class, where it is needed and reduces the code inside the `Services.yaml` to the minimum. --- Classes/Client.php | 2 ++ Classes/Controller/Backend/AjaxController.php | 10 +++++++- Classes/Domain/Dto/CurrentPage.php | 4 +++- Classes/Domain/Dto/TranslateContext.php | 8 ++++++- ...teConfigSupportedLanguageItemsProcFunc.php | 7 +++++- Classes/Form/TranslationDropdownGenerator.php | 4 ---- Classes/Form/User/HasFormalitySupport.php | 7 +++++- .../AllowLanguageSynchronizationHook.php | 14 ++++++----- Classes/Hooks/PageRendererHook.php | 6 +++++ Classes/Hooks/TranslateHook.php | 7 +++++- Classes/Hooks/UsageProcessAfterFinishHook.php | 12 ++++++---- Classes/Service/DeeplService.php | 7 ++++++ Classes/Service/IconOverlayGenerator.php | 2 ++ Classes/Service/LanguageService.php | 7 ++++++ Classes/Service/ProcessingInstruction.php | 8 +++++++ Classes/Service/UsageService.php | 5 ++++ Classes/Widgets/UsageWidget.php | 3 +++ Configuration/Services.php | 21 ----------------- Configuration/Services.yaml | 23 ------------------- 19 files changed, 93 insertions(+), 64 deletions(-) diff --git a/Classes/Client.php b/Classes/Client.php index ffe2fe6e..30538470 100644 --- a/Classes/Client.php +++ b/Classes/Client.php @@ -12,11 +12,13 @@ use DeepL\TextResult; use DeepL\TranslateTextOptions; use DeepL\Usage; +use Symfony\Component\DependencyInjection\Attribute\AsAlias; use WebVision\Deepltranslate\Core\Exception\ApiKeyNotSetException; /** * @internal No public usage */ +#[AsAlias(id: ClientInterface::class, public: true)] final class Client extends AbstractClient { /** diff --git a/Classes/Controller/Backend/AjaxController.php b/Classes/Controller/Backend/AjaxController.php index 316d1a43..2a1ab818 100644 --- a/Classes/Controller/Backend/AjaxController.php +++ b/Classes/Controller/Backend/AjaxController.php @@ -6,10 +6,18 @@ use Psr\Http\Message\ServerRequestInterface; +use TYPO3\CMS\Backend\Attribute\Controller; use TYPO3\CMS\Core\Http\JsonResponse; use WebVision\Deepltranslate\Core\Configuration; -// @todo use #[Controller] if 12.4+ only support is established, see: TYPO3\CMS\Backend\Attribute\Controller; +/** + * Controller for fetching the DeepL settings via Ajax route for usage in JavaScript inside the backend + * + * Configured backend ajax route: deepl_check_configuration + * + * @internal No public API + */ +#[Controller] final class AjaxController { private Configuration $configuration; diff --git a/Classes/Domain/Dto/CurrentPage.php b/Classes/Domain/Dto/CurrentPage.php index 2470feb9..afad4b8a 100644 --- a/Classes/Domain/Dto/CurrentPage.php +++ b/Classes/Domain/Dto/CurrentPage.php @@ -4,6 +4,7 @@ namespace WebVision\Deepltranslate\Core\Domain\Dto; +use Symfony\Component\DependencyInjection\Attribute\Exclude; use WebVision\Deepltranslate\Core\Event\DeepLGlossaryIdEvent; /** @@ -14,8 +15,9 @@ * detecting the right page, * for example, while detecting a glossary. * - * @see DeepLGlossaryIdEvent for an usage example + * @see DeepLGlossaryIdEvent for a usage example */ +#[Exclude] final class CurrentPage { public function __construct( diff --git a/Classes/Domain/Dto/TranslateContext.php b/Classes/Domain/Dto/TranslateContext.php index 64f38abd..5a9e8f40 100644 --- a/Classes/Domain/Dto/TranslateContext.php +++ b/Classes/Domain/Dto/TranslateContext.php @@ -4,7 +4,13 @@ namespace WebVision\Deepltranslate\Core\Domain\Dto; -class TranslateContext +use Symfony\Component\DependencyInjection\Attribute\Exclude; + +/** + * DTO providing the data shipped to DeepL translation. + */ +#[Exclude] +final class TranslateContext { protected string $content = ''; diff --git a/Classes/Form/Item/SiteConfigSupportedLanguageItemsProcFunc.php b/Classes/Form/Item/SiteConfigSupportedLanguageItemsProcFunc.php index fb453a04..8307ad66 100644 --- a/Classes/Form/Item/SiteConfigSupportedLanguageItemsProcFunc.php +++ b/Classes/Form/Item/SiteConfigSupportedLanguageItemsProcFunc.php @@ -5,9 +5,14 @@ namespace WebVision\Deepltranslate\Core\Form\Item; use DeepL\Language; +use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; use WebVision\Deepltranslate\Core\Service\DeeplService; -class SiteConfigSupportedLanguageItemsProcFunc +/** + * Adds DeepL related fields to the Site configuration + */ +#[Autoconfigure(public: true)] +final class SiteConfigSupportedLanguageItemsProcFunc { private DeeplService $deeplService; diff --git a/Classes/Form/TranslationDropdownGenerator.php b/Classes/Form/TranslationDropdownGenerator.php index 376f3185..87914414 100644 --- a/Classes/Form/TranslationDropdownGenerator.php +++ b/Classes/Form/TranslationDropdownGenerator.php @@ -23,10 +23,6 @@ */ final class TranslationDropdownGenerator { - public function __construct() - { - } - /** * @param iterable $siteLanguages * @throws \Doctrine\DBAL\Exception diff --git a/Classes/Form/User/HasFormalitySupport.php b/Classes/Form/User/HasFormalitySupport.php index 9f6c5971..37d5c071 100644 --- a/Classes/Form/User/HasFormalitySupport.php +++ b/Classes/Form/User/HasFormalitySupport.php @@ -4,10 +4,15 @@ namespace WebVision\Deepltranslate\Core\Form\User; +use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; use TYPO3\CMS\Backend\Form\FormDataProvider\EvaluateDisplayConditions; use WebVision\Deepltranslate\Core\Service\DeeplService; -class HasFormalitySupport +/** + * Checks a language having support for formality or not. + */ +#[Autoconfigure(public: true)] +final class HasFormalitySupport { private DeeplService $deeplService; diff --git a/Classes/Hooks/AllowLanguageSynchronizationHook.php b/Classes/Hooks/AllowLanguageSynchronizationHook.php index a3faec2a..095ffc0f 100644 --- a/Classes/Hooks/AllowLanguageSynchronizationHook.php +++ b/Classes/Hooks/AllowLanguageSynchronizationHook.php @@ -4,10 +4,16 @@ namespace WebVision\Deepltranslate\Core\Hooks; +use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; use TYPO3\CMS\Core\DataHandling\DataHandler; use TYPO3\CMS\Core\Utility\MathUtility; -class AllowLanguageSynchronizationHook +/** + * Changes the `l10n_state` for fields with allowLanguageSynchronisation enabled to custom. + * This is required to allow overriding the translation. + */ +#[Autoconfigure(public: true)] +final class AllowLanguageSynchronizationHook { public function processDatamap_beforeStart(DataHandler $dataHandler): void { @@ -25,11 +31,7 @@ public function processDatamap_beforeStart(DataHandler $dataHandler): void $columnConfig = $GLOBALS['TCA'][$table]['columns'][$column]; - if (isset($columnConfig['config']['behaviour']) - && is_array($columnConfig['config']['behaviour']) - && isset($columnConfig['config']['behaviour']['allowLanguageSynchronization']) - && (bool)$columnConfig['config']['behaviour']['allowLanguageSynchronization'] === true - ) { + if ((bool)($columnConfig['config']['behaviour']['allowLanguageSynchronization'] ?? false) === true) { $l10nState[$column] = (($columnConfig['l10n_mode'] ?? '') === 'prefixLangTitle') ? 'custom' : 'parent'; diff --git a/Classes/Hooks/PageRendererHook.php b/Classes/Hooks/PageRendererHook.php index b52928cc..df30a2af 100644 --- a/Classes/Hooks/PageRendererHook.php +++ b/Classes/Hooks/PageRendererHook.php @@ -4,8 +4,14 @@ namespace WebVision\Deepltranslate\Core\Hooks; +use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; use TYPO3\CMS\Core\Page\PageRenderer; +/** + * Adds the labels from deepltranslate_core to the backend, so they are available, as the default core functionality + * is not working + */ +#[Autoconfigure(public: true)] final class PageRendererHook { /** diff --git a/Classes/Hooks/TranslateHook.php b/Classes/Hooks/TranslateHook.php index f90401e7..59fabbdd 100644 --- a/Classes/Hooks/TranslateHook.php +++ b/Classes/Hooks/TranslateHook.php @@ -4,6 +4,7 @@ namespace WebVision\Deepltranslate\Core\Hooks; +use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; use TYPO3\CMS\Core\DataHandling\DataHandler; use TYPO3\CMS\Core\Exception\SiteNotFoundException; use TYPO3\CMS\Core\Site\SiteFinder; @@ -12,7 +13,11 @@ use WebVision\Deepltranslate\Core\Exception\LanguageIsoCodeNotFoundException; use WebVision\Deepltranslate\Core\Exception\LanguageRecordNotFoundException; -class TranslateHook extends AbstractTranslateHook +/** + * The main translation rendering on localization. + */ +#[Autoconfigure(public: true)] +final class TranslateHook extends AbstractTranslateHook { /** * @param array{uid: int} $languageRecord diff --git a/Classes/Hooks/UsageProcessAfterFinishHook.php b/Classes/Hooks/UsageProcessAfterFinishHook.php index ba0d2710..e5fb1f01 100644 --- a/Classes/Hooks/UsageProcessAfterFinishHook.php +++ b/Classes/Hooks/UsageProcessAfterFinishHook.php @@ -4,6 +4,7 @@ namespace WebVision\Deepltranslate\Core\Hooks; +use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; use TYPO3\CMS\Core\Core\Environment; use TYPO3\CMS\Core\DataHandling\DataHandler; use TYPO3\CMS\Core\Localization\LanguageService; @@ -13,7 +14,12 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; use WebVision\Deepltranslate\Core\Service\UsageService; -class UsageProcessAfterFinishHook +/** + * This hook adds a FlashMessage, if the usage quota is reaching a critical level, so editors can take care + * on and ensure to either increase their quota in DeepL or stop translating to keep the hard limit untouched. + */ +#[Autoconfigure(public: true)] +final class UsageProcessAfterFinishHook { private UsageService $usageService; @@ -25,9 +31,7 @@ public function __construct( public function processCmdmap_afterFinish(DataHandler $dataHandler): void { - if (!isset($dataHandler->cmdmap['localization']['custom']['mode']) - || $dataHandler->cmdmap['localization']['custom']['mode'] !== 'deepl' - ) { + if (!isset($dataHandler->cmdmap['deepltranslate'])) { return; } diff --git a/Classes/Service/DeeplService.php b/Classes/Service/DeeplService.php index 40e3aea7..ecc9f0dd 100644 --- a/Classes/Service/DeeplService.php +++ b/Classes/Service/DeeplService.php @@ -7,6 +7,8 @@ use DeepL\Language; use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerAwareTrait; +use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; +use Symfony\Component\DependencyInjection\Attribute\Autowire; use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface; use TYPO3\CMS\Core\EventDispatcher\EventDispatcher; use WebVision\Deepltranslate\Core\ClientInterface; @@ -15,6 +17,10 @@ use WebVision\Deepltranslate\Core\Exception\ApiKeyNotSetException; use WebVision\Deepltranslate\Core\Utility\DeeplBackendUtility; +/** + * Main entry point for connecting TYPO3 backend to the DeepL API + */ +#[Autoconfigure(public: true)] final class DeeplService implements LoggerAwareInterface { use LoggerAwareTrait; @@ -25,6 +31,7 @@ final class DeeplService implements LoggerAwareInterface private ProcessingInstruction $processingInstruction; public function __construct( + #[Autowire(service: 'cache.deepltranslateCore')] FrontendInterface $cache, ClientInterface $client, ProcessingInstruction $processingInstruction, diff --git a/Classes/Service/IconOverlayGenerator.php b/Classes/Service/IconOverlayGenerator.php index 6405a42d..40324cb1 100644 --- a/Classes/Service/IconOverlayGenerator.php +++ b/Classes/Service/IconOverlayGenerator.php @@ -4,12 +4,14 @@ namespace WebVision\Deepltranslate\Core\Service; +use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; use TYPO3\CMS\Core\Imaging\Icon; use TYPO3\CMS\Core\Imaging\IconFactory; /** * @internal not part of public deepl extension api */ +#[Autoconfigure(public: true)] final class IconOverlayGenerator { private IconFactory $iconFactory; diff --git a/Classes/Service/LanguageService.php b/Classes/Service/LanguageService.php index 73426652..352a5597 100644 --- a/Classes/Service/LanguageService.php +++ b/Classes/Service/LanguageService.php @@ -4,10 +4,17 @@ namespace WebVision\Deepltranslate\Core\Service; +use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; use TYPO3\CMS\Core\Site\Entity\Site; use WebVision\Deepltranslate\Core\Exception\InvalidArgumentException; use WebVision\Deepltranslate\Core\Exception\LanguageRecordNotFoundException; +/** + * Service for detecting correct target and source languages from DeepL + * + * @internal No public API + */ +#[Autoconfigure(public: true)] final class LanguageService { protected DeeplService $deeplService; diff --git a/Classes/Service/ProcessingInstruction.php b/Classes/Service/ProcessingInstruction.php index fa1b2e0e..797a7d09 100644 --- a/Classes/Service/ProcessingInstruction.php +++ b/Classes/Service/ProcessingInstruction.php @@ -4,14 +4,22 @@ namespace WebVision\Deepltranslate\Core\Service; +use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; +use Symfony\Component\DependencyInjection\Attribute\Autowire; use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface; +/** + * This class defines instructions, how to work within DeepL translations + * @internal No public API + */ +#[Autoconfigure(public: true)] final class ProcessingInstruction { protected const PROCESSING_CACHE_IDENTIFIER = 'deepl-processing-cache'; private FrontendInterface $runtimeCache; public function __construct( + #[Autowire(service: 'cache.runtime')] FrontendInterface $runtimeCache ) { $this->runtimeCache = $runtimeCache; diff --git a/Classes/Service/UsageService.php b/Classes/Service/UsageService.php index 79486416..57f7ee0e 100644 --- a/Classes/Service/UsageService.php +++ b/Classes/Service/UsageService.php @@ -5,6 +5,7 @@ namespace WebVision\Deepltranslate\Core\Service; use DeepL\Usage; +use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; use TYPO3\CMS\Backend\Toolbar\Enumeration\InformationStatus; use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Localization\Locales; @@ -13,6 +14,10 @@ use WebVision\Deepltranslate\Core\Event\Listener\UsageToolBarEventListener; use WebVision\Deepltranslate\Core\Hooks\UsageProcessAfterFinishHook; +/** + * Service for getting the current count and limit of DeepL API + */ +#[Autoconfigure(public: true)] final class UsageService implements UsageServiceInterface { public function __construct( diff --git a/Classes/Widgets/UsageWidget.php b/Classes/Widgets/UsageWidget.php index f4587b1d..7376e41c 100644 --- a/Classes/Widgets/UsageWidget.php +++ b/Classes/Widgets/UsageWidget.php @@ -15,6 +15,9 @@ /** * `EXT:dashboard` widget compatible with TYPO3 v12 to display deepl api usage. * + * Cannot be autoconfigured, as this class depends on EXT:dashboard, which is not installed in every system. + * Registration and configuring is done in Configuration/Services.php + * * @internal implementation only and not part of public API. */ final class UsageWidget implements RequestAwareWidgetInterface, WidgetInterface diff --git a/Configuration/Services.php b/Configuration/Services.php index d51435c8..5292f082 100644 --- a/Configuration/Services.php +++ b/Configuration/Services.php @@ -5,11 +5,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; use TYPO3\CMS\Backend\View\BackendViewFactory; -use TYPO3\CMS\Core\DependencyInjection\SingletonPass; use TYPO3\CMS\Dashboard\WidgetRegistry; -use WebVision\Deepltranslate\Core\Form\Item\SiteConfigSupportedLanguageItemsProcFunc; -use WebVision\Deepltranslate\Core\Form\User\HasFormalitySupport; -use WebVision\Deepltranslate\Core\Hooks\TranslateHook; use WebVision\Deepltranslate\Core\Service\UsageService; use WebVision\Deepltranslate\Core\Widgets\UsageWidget; @@ -17,23 +13,6 @@ $services = $containerConfigurator ->services(); - $containerBuilder - ->registerForAutoconfiguration(TranslateHook::class) - ->addTag('deepl.TranslateHook'); - $containerBuilder - ->registerForAutoconfiguration(SiteConfigSupportedLanguageItemsProcFunc::class) - ->addTag('deepl.SiteConfigSupportedLanguageItemsProcFunc'); - $containerBuilder - ->registerForAutoconfiguration(HasFormalitySupport::class) - ->addTag('deepl.HasFormalitySupport'); - - $containerBuilder - ->addCompilerPass(new SingletonPass('deepl.TranslateHook')); - $containerBuilder - ->addCompilerPass(new SingletonPass('deepl.SiteConfigSupportedLanguageItemsProcFunc')); - $containerBuilder - ->addCompilerPass(new SingletonPass('deepl.HasFormalitySupport')); - /** * Check if WidgetRegistry is defined, which means that EXT:dashboard is available. * Registration directly in Services.yaml will break without EXT:dashboard installed! diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index f6dd83f1..11ad4e42 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -13,29 +13,6 @@ services: factory: ['@TYPO3\CMS\Core\Cache\CacheManager', 'getCache'] arguments: ['deepltranslate_core'] - WebVision\Deepltranslate\Core\Service\: - resource: '../Classes/Service/*' - public: true - - WebVision\Deepltranslate\Core\Hooks\: - resource: '../Classes/Hooks/*' - public: true - - WebVision\Deepltranslate\Core\Service\ProcessingInstruction: - arguments: - $runtimeCache: '@cache.runtime' - - WebVision\Deepltranslate\Core\Service\DeeplService: - public: true - arguments: - $cache: '@cache.deepltranslateCore' - - WebVision\Deepltranslate\Core\Controller\Backend\AjaxController: - public: true - - WebVision\Deepltranslate\Core\ClientInterface: - class: WebVision\Deepltranslate\Core\Client - WebVision\Deepltranslate\Core\Event\Listener\RenderLocalizationSelect: tags: - name: 'event.listener'