From dd6e414ad0927f7a52f5c02de666f7adf8df54b0 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 6 May 2024 14:08:15 +0200 Subject: [PATCH 1/5] [TASK] Streamline glossary list command Streamline glossary list command to be a better format und handling API information. - Fix a Bug with none existed glossary - Streamline command process - Streamline table formating - Implement IO object --- Classes/Command/GlossaryCommandTrait.php | 2 +- Classes/Command/GlossaryListCommand.php | 124 ++++++++++++----------- Documentation/Housekeeping/Index.rst | 7 -- 3 files changed, 68 insertions(+), 65 deletions(-) diff --git a/Classes/Command/GlossaryCommandTrait.php b/Classes/Command/GlossaryCommandTrait.php index e339b6d6..9bc6a3e0 100644 --- a/Classes/Command/GlossaryCommandTrait.php +++ b/Classes/Command/GlossaryCommandTrait.php @@ -22,4 +22,4 @@ public function injectGlossaryRepository(GlossaryRepository $glossaryRepository) { $this->glossaryRepository = $glossaryRepository; } -} \ No newline at end of file +} diff --git a/Classes/Command/GlossaryListCommand.php b/Classes/Command/GlossaryListCommand.php index 5cfe9320..92c0d375 100644 --- a/Classes/Command/GlossaryListCommand.php +++ b/Classes/Command/GlossaryListCommand.php @@ -4,104 +4,114 @@ namespace WebVision\WvDeepltranslate\Command; +use DateTime; +use DeepL\GlossaryInfo; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use WebVision\WvDeepltranslate\Service\DeeplGlossaryService; +use Symfony\Component\Console\Style\SymfonyStyle; class GlossaryListCommand extends Command { use GlossaryCommandTrait; + private SymfonyStyle $io; + protected function configure(): void { $this->addArgument( 'glossary_id', InputArgument::OPTIONAL, - 'Which glossary you want to fetch (id)?' + 'Which glossary you want to fetch (id)?', + null ); } protected function execute(InputInterface $input, OutputInterface $output): int { + $this->io = new SymfonyStyle($input, $output); + $this->io->title('Glossary List'); + $glossary_id = $input->getArgument('glossary_id'); - if ($glossary_id) { - $this->listAllGloassaryEntriesById($output, $glossary_id); - return 0; + if ($glossary_id !== null) { + $this->listAllGlossaryEntriesById($glossary_id); + } else { + $this->listAllGlossaryEntries(); } - $this->listAllGloassaryEntries($output); return Command::SUCCESS; } - private function listAllGloassaryEntries(OutputInterface $output): void + private function listAllGlossaryEntries(): void { $glossaries = $this->deeplGlossaryService->listGlossaries(); - if (empty($glossaries)) { - $output->writeln([ - '============', - 'No Glossaries found.', - 'Read more here: https://www.deepl.com/docs-api/managing-glossaries/listing-glossaries/', - '============', - ]); - + $this->io->writeln('Read more here: https://www.deepl.com/docs-api/managing-glossaries/listing-glossaries/'); + $this->io->newLine(); + if ($glossaries === []) { + $this->io->info('No Glossaries found.'); return; } - $output->writeln([ - '============', - 'Read more here: https://www.deepl.com/docs-api/managing-glossaries/listing-glossaries/', - '============', - ]); - - $headers = array_keys(get_object_vars($glossaries[0])); - $rows = []; - - foreach ($glossaries as $eachGlossary) { - $rows[] = $eachGlossary; - } + $headers = [ + 'Glossary ID', + 'Name', + 'Ready', + 'Source Language', + 'Target Language', + 'Creation Time', + 'Entry count', + ]; - $table = new Table($output); - $table - ->setHeaders($headers) - ->setRows($rows) - ->render(); + $rows = array_map(function (GlossaryInfo $glossary) { + return [ + 'glossaryId' => $glossary->glossaryId, + 'name' => $glossary->name, + 'ready' => $glossary->ready, + 'sourceLang' => $glossary->sourceLang, + 'targetLang' => $glossary->targetLang, + 'creationTime' => $glossary->creationTime->format(DateTime::ATOM), + 'entryCount' => $glossary->entryCount, + ]; + }, $glossaries); + + $this->io->table($headers, $rows); } - private function listAllGloassaryEntriesById(OutputInterface $output, string $id): void + private function listAllGlossaryEntriesById(string $id): void { - $information = $this->deeplGlossaryService->glossaryInformation($id); + $glossaryInformation = $this->deeplGlossaryService->glossaryInformation($id); + if ($glossaryInformation === null) { + $this->io->warning(sprintf('Glossary "%s" not found.', $id)); + return; + } + if ($glossaryInformation->entryCount === 0) { + $this->io->warning(sprintf('Glossary "%s" has no entries.', $id)); + return; + } $entries = $this->deeplGlossaryService->glossaryEntries($id); - - if ($information === null || $entries === null) { - $output->writeln( - [ - 'Glossary not found.', - ] - ); + if ($entries === null) { + $this->io->warning('The API giv entries.'); return; } - $output->writeln([ - '============', - 'List of Glossary entries', - '============', - ]); - $headers = [ - 'source_lang - ' . $information->sourceLang, - 'target_lang - ' . $information->targetLang, - ]; + $this->io->writeln([ + sprintf('Glossary entries from: %s', $glossaryInformation->glossaryId), + sprintf('Entries count: %s', $glossaryInformation->entryCount), + sprintf('Is ready: %s', $glossaryInformation->ready ? 'yes' : 'no'), + sprintf('Creation Time: %s', $glossaryInformation->creationTime->format(DateTime::ATOM)), + ]); + $this->io->newLine(); $rows = array_map(null, array_keys($entries->getEntries()), $entries->getEntries()); - - $table = new Table($output); - $table - ->setHeaders($headers) - ->setRows($rows) - ->render(); + $this->io->table( + [ + 'source_lang: ' . $glossaryInformation->sourceLang, + 'target_lang:' . $glossaryInformation->targetLang, + ], + $rows + ); } } diff --git a/Documentation/Housekeeping/Index.rst b/Documentation/Housekeeping/Index.rst index f279607f..c6869d17 100644 --- a/Documentation/Housekeeping/Index.rst +++ b/Documentation/Housekeeping/Index.rst @@ -17,13 +17,6 @@ you can use: vendor/bin/typo3 deepl:glossary:list -or, with `typo3_console`_ installed: - -.. code-block:: bash - - vendor/bin/typo3cms deepl:glossary:list - - This will give you an overview of API connected glossaries, number of entries, creation date and Glossary DeepL ID. From 0bf15e573a15b230fa24363056e793fea6513fff Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 6 May 2024 14:15:18 +0200 Subject: [PATCH 2/5] [TASK] Streamline glossary cleanup command Streamline glossary cleanup command, the impact is a better command output, more command options, clarified the command process and Fix some bug - Fix a Bug with GlossaryInfo object handling - Streamline command process - Streamline process formating - Implement more command options --- Build/phpstan/Core12/phpstan-baseline.neon | 5 - Classes/Command/GlossaryCleanupCommand.php | 163 ++++++++++++--------- Documentation/Housekeeping/Index.rst | 8 +- 3 files changed, 96 insertions(+), 80 deletions(-) diff --git a/Build/phpstan/Core12/phpstan-baseline.neon b/Build/phpstan/Core12/phpstan-baseline.neon index 81ffdd28..9a0f88c0 100644 --- a/Build/phpstan/Core12/phpstan-baseline.neon +++ b/Build/phpstan/Core12/phpstan-baseline.neon @@ -1,10 +1,5 @@ parameters: ignoreErrors: - - - message: "#^PHPDoc tag @throws with type Doctrine\\\\DBAL\\\\DBALException is not subtype of Throwable$#" - count: 2 - path: ../../../Classes/Command/GlossaryCleanupCommand.php - - message: "#^Method WebVision\\\\WvDeepltranslate\\\\Domain\\\\Repository\\\\GlossaryEntryRepository\\:\\:findEntriesByGlossary\\(\\) should return array\\ but returns array\\\\>\\.$#" count: 1 diff --git a/Classes/Command/GlossaryCleanupCommand.php b/Classes/Command/GlossaryCleanupCommand.php index 36aa2547..61a1c999 100644 --- a/Classes/Command/GlossaryCleanupCommand.php +++ b/Classes/Command/GlossaryCleanupCommand.php @@ -4,115 +4,138 @@ namespace WebVision\WvDeepltranslate\Command; -use Doctrine\DBAL\DBALException; +use DeepL\GlossaryInfo; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Helper\ProgressBar; -use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\Console\Style\SymfonyStyle; -use WebVision\WvDeepltranslate\Domain\Repository\GlossaryRepository; -use WebVision\WvDeepltranslate\Service\DeeplGlossaryService; +/** + * ToDo: Rename Command + * ToDo: Split command in housekeeping and remove glossary from API/remote storage + */ class GlossaryCleanupCommand extends Command { use GlossaryCommandTrait; + private SymfonyStyle $io; + protected function configure(): void { - $this->addOption( - 'yes', - 'y', - InputOption::VALUE_NONE, - 'Force deletion without asking' - ); + $this + ->addOption( + 'glossaryId', + null, + InputOption::VALUE_OPTIONAL, + 'Deleted single Glossary', + null + ) + ->addOption( + 'all', + null, + InputOption::VALUE_NONE, + 'Deleted all Glossaries', + ) + ->addOption( + 'notinsync', + null, + InputOption::VALUE_NONE, + 'Deleted all Glossaries without synchronization information', + ) + ; } - protected function interact(InputInterface $input, OutputInterface $output): void + protected function execute(InputInterface $input, OutputInterface $output): int { - if (empty($input->getOption('yes'))) { - $io = new SymfonyStyle($input, $output); - $yes = $io->ask('Really all delete? [yY]'); - if (strtolower($yes) !== 'y') { - $output->writeln('Abort.'); - exit; - } - $input->setOption('yes', true); + $this->io = new SymfonyStyle($input, $output); + $this->io->title('Glossary cleanup'); + + $question = new ConfirmationQuestion( + 'Do you will execute the glossary cleanup?', + false, + '/^(y|j)/i' + ); + + if (!$this->io->askQuestion($question)) { + $this->io->writeln('Delete not confirmed, process was cancel.'); + return Command::SUCCESS; } - } - /** - * @throws DBALException - */ - protected function execute( - InputInterface $input, - OutputInterface $output - ): int { - if ($input->getOption('yes') === false) { - $output->writeln('Deletion not confirmed. Cancel.'); - - return Command::INVALID; + // Remove single glossary by deepl-id + $glossaryId = $input->getOption('glossaryId'); + if ($glossaryId !== null) { + $this->removeGlossaries($glossaryId); } + // Remove all glossaries + if (!empty($input->getOption('all'))) { + $glossaries = $this->deeplGlossaryService->listGlossaries(); + if (empty($glossaries)) { + $this->io->writeln('No glossaries found with sync to API'); + return Command::FAILURE; + } - $this->removeAllGlossaryEntries($output); - $output->writeln('Success!'); + $this->removeGlossaries($glossaries); + } + // Remove glossaries without api sync id + if (!empty($input->getOption('notinsync'))) { + $this->removeGlossariesWithNoSync(); + } + + $this->io->writeln('Success!'); return Command::SUCCESS; } + private function removeGlossary(string $id): bool + { + $this->deeplGlossaryService->deleteGlossary($id); + return $this->glossaryRepository->removeGlossarySync($id); + } + /** - * @throws DBALException + * @param GlossaryInfo[] $glossaries */ - private function removeAllGlossaryEntries(OutputInterface $output): void + private function removeGlossaries(array $glossaries): void { - $glossaries = $this->deeplGlossaryService->listGlossaries(); - - if (empty($glossaries['glossaries'])) { - $output->writeln('No glossaries found with sync to API'); - return; - } - - $progress = new ProgressBar($output, count($glossaries)); - $progress->start(); - - $removedGlossary = []; + $rows = []; + $this->io->progressStart(count($glossaries)); foreach ($glossaries as $glossary) { - $id = $glossary->glossaryId; - $this->deeplGlossaryService->deleteGlossary($id); - $databaseUpdated = $this->glossaryRepository->removeGlossarySync($id); - $removedGlossary[$id] = $databaseUpdated; - $progress->advance(); + $dbUpdated = $this->removeGlossary($glossary->glossaryId); + $rows[] = [$glossary->glossaryId, $dbUpdated ? 'yes' : 'no']; + $this->io->progressAdvance(); } - $progress->finish(); - - $table = new Table($output); + $this->io->progressFinish(); - $table->setHeaders([ - 'Glossary ID', - 'Database sync removed', - ]); - foreach ($removedGlossary as $glossaryId => $dbUpdated) { - $table->addRow([$glossaryId, $dbUpdated ? 'yes' : 'no']); - } - - $output->writeln(''); - $table->render(); - $output->writeln(''); + $this->io->table( + [ + 'Glossary ID', + 'Database sync removed', + ], + $rows + ); + } + private function removeGlossariesWithNoSync(): void + { $findNotConnected = $this->glossaryRepository->getGlossariesDeeplConnected(); if (count($findNotConnected) === 0) { - $output->writeln('No glossaries with sync mismatch.'); + $this->io->writeln('No glossaries with sync mismatch.'); } + + $this->io->progressStart(count($findNotConnected)); foreach ($findNotConnected as $notConnected) { $this->glossaryRepository->removeGlossarySync($notConnected['glossary_id']); + $this->io->progressAdvance(); } + $this->io->progressFinish(); - $output->writeln([ - sprintf('Found %d glossaries with possible sync mismatch. Cleaned up.', count($findNotConnected)), - ]); + $this->io->writeln( + sprintf('Found %d glossaries with possible sync mismatch. Cleaned up.', count($findNotConnected)) + ); } } diff --git a/Documentation/Housekeeping/Index.rst b/Documentation/Housekeeping/Index.rst index c6869d17..460c0656 100644 --- a/Documentation/Housekeeping/Index.rst +++ b/Documentation/Housekeeping/Index.rst @@ -27,15 +27,13 @@ Due to sync failures it is useful, to delete all DeepL glossaries. .. code-block:: bash - vendor/bin/typo3 deepl:glossary:cleanup - -or, with `typo3_console`_ installed: + vendor/bin/typo3 deepl:glossary:cleanup --all .. code-block:: bash - vendor/bin/typo3cms deepl:glossary:cleanup + vendor/bin/typo3 deepl:glossary:cleanup --glossaryId 123-123 -This command retrieves information about all glossaries in DeepL API +This command retrieves information about all glossaries or one glossary in DeepL API registered and deletes them from API. Additionally, each glossary ID is checked against the database and if found, the database record is updated. From d0d78730dfb500176dbf501da605c532a62ab247 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 6 May 2024 14:17:18 +0200 Subject: [PATCH 3/5] [TASK] Streamline glossary sync command Streamline glossary sync command, the impact is a better command output clarified the command process and Fix a bug - Fix a Bug with pageId command option handling - Streamline command process - Streamline process formating - Handle Exception output --- Build/phpstan/Core11/phpstan-baseline.neon | 5 --- Classes/Command/GlossarySyncCommand.php | 46 +++++++++++++--------- Documentation/Housekeeping/Index.rst | 6 --- 3 files changed, 27 insertions(+), 30 deletions(-) diff --git a/Build/phpstan/Core11/phpstan-baseline.neon b/Build/phpstan/Core11/phpstan-baseline.neon index bf33b3c1..91357e56 100644 --- a/Build/phpstan/Core11/phpstan-baseline.neon +++ b/Build/phpstan/Core11/phpstan-baseline.neon @@ -1,10 +1,5 @@ parameters: ignoreErrors: - - - message: "#^Access to constant OK on an unknown class TYPO3\\\\CMS\\\\Core\\\\Type\\\\ContextualFeedbackSeverity\\.$#" - count: 1 - path: ../../../Classes/Controller/GlossarySyncController.php - - message: "#^Method WebVision\\\\WvDeepltranslate\\\\Domain\\\\Repository\\\\GlossaryEntryRepository\\:\\:findEntriesByGlossary\\(\\) should return array\\ but returns array\\\\>\\.$#" count: 1 diff --git a/Classes/Command/GlossarySyncCommand.php b/Classes/Command/GlossarySyncCommand.php index 45d27fb7..e766c0cb 100644 --- a/Classes/Command/GlossarySyncCommand.php +++ b/Classes/Command/GlossarySyncCommand.php @@ -4,18 +4,19 @@ namespace WebVision\WvDeepltranslate\Command; +use Exception; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -use TYPO3\CMS\Core\Exception\SiteNotFoundException; -use WebVision\WvDeepltranslate\Domain\Repository\GlossaryRepository; -use WebVision\WvDeepltranslate\Service\DeeplGlossaryService; +use Symfony\Component\Console\Style\SymfonyStyle; class GlossarySyncCommand extends Command { use GlossaryCommandTrait; + private SymfonyStyle $io; + protected function configure(): void { $this @@ -24,25 +25,32 @@ protected function configure(): void 'p', InputOption::VALUE_OPTIONAL, 'Page to sync, not set, sync all glossaries', - 0 + null ); } - /** - * @throws SiteNotFoundException - */ - protected function execute( - InputInterface $input, - OutputInterface $output - ): int { - $pageId = (int)$input->getOption('pageId'); - $glossaries = [$pageId]; - if ($pageId === 0) { - $glossaries = $this->glossaryRepository->findAllGlossaries(); - } - - foreach ($glossaries as $glossary) { - $this->deeplGlossaryService->syncGlossaries($glossary['uid']); + protected function execute(InputInterface $input, OutputInterface $output): int + { + $this->io = new SymfonyStyle($input, $output); + $this->io->title('Glossary Sync'); + + try { + $pageId = $input->getOption('pageId'); + if ($pageId !== null) { + $glossaries[] = ['uid' => (int)$pageId]; + } else { + $glossaries = $this->glossaryRepository->findAllGlossaries(); + } + + $this->io->progressStart(count($glossaries)); + foreach ($glossaries as $glossary) { + $this->deeplGlossaryService->syncGlossaries($glossary['uid']); + $this->io->progressAdvance(); + } + $this->io->progressFinish(); + } catch (Exception $exception) { + $this->io->error(sprintf('%s (%s)', $exception->getMessage(), $exception->getCode())); + return Command::FAILURE; } return Command::SUCCESS; diff --git a/Documentation/Housekeeping/Index.rst b/Documentation/Housekeeping/Index.rst index 460c0656..e93fa839 100644 --- a/Documentation/Housekeeping/Index.rst +++ b/Documentation/Housekeeping/Index.rst @@ -60,12 +60,6 @@ CLI Command). vendor/bin/typo3 deepl:glossary:sync -or, with `typo3_console`_ installed: - -.. code-block:: bash - - vendor/bin/typo3cms deepl:glossary:sync - Accepts pageId as option. If not given, syncs all available glossaries. .. _typo3_console: https://extensions.typo3.org/extension/typo3_console From 01b7f2f54e60fe2797bcc81554750a8e113c65a3 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 6 May 2024 14:21:22 +0200 Subject: [PATCH 4/5] [TASK] Streamline glossary sync controller Update flashMassage for user interaction and denied calls with not right configuration. --- Build/phpstan/Core12/phpstan-baseline.neon | 5 -- Classes/Controller/GlossarySyncController.php | 75 ++++++++++++------- .../FailedToCreateGlossaryException.php | 10 +++ Classes/Service/DeeplGlossaryService.php | 12 ++- Resources/Private/Language/locallang.xlf | 16 ++-- 5 files changed, 76 insertions(+), 42 deletions(-) create mode 100644 Classes/Exception/FailedToCreateGlossaryException.php diff --git a/Build/phpstan/Core12/phpstan-baseline.neon b/Build/phpstan/Core12/phpstan-baseline.neon index 9a0f88c0..5a3e531b 100644 --- a/Build/phpstan/Core12/phpstan-baseline.neon +++ b/Build/phpstan/Core12/phpstan-baseline.neon @@ -145,11 +145,6 @@ parameters: count: 1 path: ../../../Classes/Service/DeeplGlossaryService.php - - - message: "#^PHPDoc tag @throws with type Doctrine\\\\DBAL\\\\DBALException\\|Doctrine\\\\DBAL\\\\Driver\\\\Exception\\|Doctrine\\\\DBAL\\\\Exception\\|TYPO3\\\\CMS\\\\Core\\\\Exception\\\\SiteNotFoundException is not subtype of Throwable$#" - count: 1 - path: ../../../Classes/Service/DeeplGlossaryService.php - - message: "#^Offset 'pid' does not exist on array\\|null\\.$#" count: 1 diff --git a/Classes/Controller/GlossarySyncController.php b/Classes/Controller/GlossarySyncController.php index f007f0ce..57c0a8ea 100644 --- a/Classes/Controller/GlossarySyncController.php +++ b/Classes/Controller/GlossarySyncController.php @@ -5,12 +5,14 @@ namespace WebVision\WvDeepltranslate\Controller; use Psr\Http\Message\ServerRequestInterface; +use TYPO3\CMS\Backend\Utility\BackendUtility; +use TYPO3\CMS\Core\Domain\Repository\PageRepository; use TYPO3\CMS\Core\Exception; use TYPO3\CMS\Core\Http\RedirectResponse; use TYPO3\CMS\Core\Messaging\FlashMessage; use TYPO3\CMS\Core\Messaging\FlashMessageService; -use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Utility\LocalizationUtility; +use WebVision\WvDeepltranslate\Exception\FailedToCreateGlossaryException; use WebVision\WvDeepltranslate\Exception\InvalidArgumentException; use WebVision\WvDeepltranslate\Service\DeeplGlossaryService; @@ -18,10 +20,14 @@ class GlossarySyncController { protected DeeplGlossaryService $deeplGlossaryService; + private FlashMessageService $flashMessageService; + public function __construct( - DeeplGlossaryService $deeplGlossaryService + DeeplGlossaryService $deeplGlossaryService, + FlashMessageService $flashMessageService ) { $this->deeplGlossaryService = $deeplGlossaryService; + $this->flashMessageService = $flashMessageService; } /** @@ -33,36 +39,49 @@ public function update(ServerRequestInterface $request): RedirectResponse $processingParameters = $request->getQueryParams(); if (!isset($processingParameters['uid'])) { - throw new InvalidArgumentException( - 'No ID given for glossary synchronization', - 1676935668643 - ); + $this->flashMessageService + ->getMessageQueueByIdentifier() + ->enqueue((new FlashMessage( + 'No ID given for glossary synchronization', + '', + 2, + true + ))); + return new RedirectResponse($processingParameters['returnUrl']); } - $this->deeplGlossaryService->syncGlossaries((int)$processingParameters['uid']); - - if ((new \TYPO3\CMS\Core\Information\Typo3Version())->getMajorVersion() >= 12) { - $severity = \TYPO3\CMS\Core\Type\ContextualFeedbackSeverity::OK; - } else { - $severity = \TYPO3\CMS\Core\Messaging\AbstractMessage::OK; + // Check page configuration of glossary type + /** @var array{uid: int, doktype: string|int, module: string} $pages */ + $pages = BackendUtility::getRecord('pages', (int)$processingParameters['uid']); + if ((int)$pages['doktype'] !== PageRepository::DOKTYPE_SYSFOLDER && $pages['module'] !== 'glossary') { + $this->flashMessageService->getMessageQueueByIdentifier()->enqueue(new FlashMessage( + sprintf('Page "%d" not configured for glossary synchronization.', $pages['uid']), + (string)LocalizationUtility::translate( + 'glossary.sync.title.invalid', + 'wv_deepltranslate' + ), + 2, + true + )); + return new RedirectResponse($processingParameters['returnUrl']); } - $flashMessage = GeneralUtility::makeInstance( - FlashMessage::class, - (string)LocalizationUtility::translate( - 'glossary.sync.message', - 'wv_deepltranslate' - ), - (string)LocalizationUtility::translate( - 'glossary.sync.title', - 'wv_deepltranslate' - ), - $severity, - true - ); - GeneralUtility::makeInstance(FlashMessageService::class) - ->getMessageQueueByIdentifier() - ->enqueue($flashMessage); + try { + $this->deeplGlossaryService->syncGlossaries((int)$processingParameters['uid']); + $this->flashMessageService->getMessageQueueByIdentifier()->enqueue(new FlashMessage( + (string)LocalizationUtility::translate('glossary.sync.message', 'wv_deepltranslate'), + (string)LocalizationUtility::translate('glossary.sync.title', 'wv_deepltranslate'), + 0, // OK + true + )); + } catch (FailedToCreateGlossaryException $exception) { + $this->flashMessageService->getMessageQueueByIdentifier()->enqueue(new FlashMessage( + (string)LocalizationUtility::translate('glossary.sync.message.invalid', 'wv_deepltranslate'), + (string)LocalizationUtility::translate('glossary.sync.title.invalid', 'wv_deepltranslate'), + 2, // Error + true + )); + } return new RedirectResponse($processingParameters['returnUrl']); } diff --git a/Classes/Exception/FailedToCreateGlossaryException.php b/Classes/Exception/FailedToCreateGlossaryException.php new file mode 100644 index 00000000..3aff45a2 --- /dev/null +++ b/Classes/Exception/FailedToCreateGlossaryException.php @@ -0,0 +1,10 @@ +glossaryRepository - ->getGlossaryInformationForSync($uid); + $glossaries = $this->glossaryRepository->getGlossaryInformationForSync($uid); + if (empty($glossaries)) { + throw new FailedToCreateGlossaryException( + 'Glossary can not created, the TYPO3 information are invalide.', + 1714987594661 + ); + } foreach ($glossaries as $glossaryInformation) { if ($glossaryInformation['glossary_id'] !== '') { diff --git a/Resources/Private/Language/locallang.xlf b/Resources/Private/Language/locallang.xlf index 76627e33..903ea2f1 100644 --- a/Resources/Private/Language/locallang.xlf +++ b/Resources/Private/Language/locallang.xlf @@ -115,17 +115,23 @@ Create new Glossary translation + + DeepL sync ready + Synchronization with DeepL is done. Your glossaries are ready to use. - - DeepL Sync ready + + DeepL glossary sync invalid - - Glossary synchronization with DeepL is pending. Your glossaries are not operational. + + Glossary synchronization with DeepL error. Your glossaries has no entries or is invalid. - DeepL Glossary is out of Sync + DeepL glossary is out of sync + + + Glossary synchronization with DeepL is pending. Your glossaries are not operational. From 122c5056839c44cad29ba9c6efb41eba6cb7bffc Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 17 May 2024 09:39:18 +0200 Subject: [PATCH 5/5] [TASK] Avoid return type from request parseBody After upgrade psr/http-message to 1.1.0 the method `getParsedBody()` can return an object in addition to array and null. To avoid errors use only `getQueryParams()` --- Classes/Event/Listener/GlossarySyncButtonProvider.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Classes/Event/Listener/GlossarySyncButtonProvider.php b/Classes/Event/Listener/GlossarySyncButtonProvider.php index 2f17d439..99038d68 100644 --- a/Classes/Event/Listener/GlossarySyncButtonProvider.php +++ b/Classes/Event/Listener/GlossarySyncButtonProvider.php @@ -32,7 +32,9 @@ public function __invoke(ModifyButtonBarEvent $event): void $buttons = $event->getButtons(); $request = $this->getRequest(); - $id = (int)($request->getParsedBody()['id'] ?? $request->getQueryParams()['id'] ?? 0); + $requestParams = $request->getQueryParams(); + + $id = (int)($requestParams['id'] ?? 0); $module = $request->getAttribute('module'); $normalizedParams = $request->getAttribute('normalizedParams'); $pageTSconfig = BackendUtility::getPagesTSconfig($id);