diff --git a/Classes/Command/IndexerStatusCommand.php b/Classes/Command/IndexerStatusCommand.php new file mode 100644 index 000000000..1c2c4afa0 --- /dev/null +++ b/Classes/Command/IndexerStatusCommand.php @@ -0,0 +1,80 @@ +indexerStatusService = $indexerStatusService; + parent::__construct(); + } + + /** + * Configure command + */ + protected function configure() + { + $this->setHelp( + 'Shows the current status of the indexer. If mode is "short", only the status is' + . ' shown ("running" or "idle"), otherwise a detailed report is displayed.' + ); + + $this->addOption( + 'mode', + 'm', + InputOption::VALUE_OPTIONAL, + 'Mode, either "full" (default) or "short".', + 'full' + ); + } + + /** + * Runs the index process for ke_search + */ + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + if ($input->getOption('mode') === 'short') { + $output = $this->indexerStatusService->isRunning() ? 'running' : 'idle'; + } else { + $output = $this->indexerStatusService->getStatusReport(IndexerStatusService::INDEXER_STATUS_REPORT_FORMAT_PLAIN); + } + $io->writeln($output); + return self::SUCCESS; + } +} diff --git a/Classes/Controller/BackendModuleController.php b/Classes/Controller/BackendModuleController.php index 44c568d85..f67ed4cbb 100644 --- a/Classes/Controller/BackendModuleController.php +++ b/Classes/Controller/BackendModuleController.php @@ -455,13 +455,12 @@ public function getLastIndexingReport() */ public function printIndexerConfigurations($indexerConfigurations) { - $content = '

Indexer configurations

'; - // show indexer names + $content = '
'; if ($indexerConfigurations) { $content .= '
'; $content .= '
'; $content .= ''; - $content .= ''; + $content .= ''; foreach ($indexerConfigurations as $indexerConfiguration) { $content .= '' . '' @@ -490,46 +489,41 @@ public function printIndexerConfigurations($indexerConfigurations) */ public function printNumberOfRecords() { - $content = '

Index statistics

'; + $content = '
'; $numberOfRecords = $this->indexRepository->getTotalNumberOfRecords(); if ($numberOfRecords) { - $content .= - '

' - . LocalizationUtility::translate( - 'LLL:EXT:ke_search/Resources/Private/Language/locallang_mod.xlf:index_contains', - 'KeSearch' - ) - . ' ' - . $numberOfRecords - . ' ' + $content .= '

'; + $content .= '
'; + $content .= LocalizationUtility::translate( + 'LLL:EXT:ke_search/Resources/Private/Language/locallang_mod.xlf:index_contains', + 'KeSearch' + ) + . ' ' . $numberOfRecords . ' ' . LocalizationUtility::translate( 'LLL:EXT:ke_search/Resources/Private/Language/locallang_mod.xlf:records', 'KeSearch' - ) - . '

'; + ) . '.
' . chr(10); $lastRun = $this->registry->get('tx_kesearch', 'lastRun'); if ($lastRun) { - $content .= '

' - . LocalizationUtility::translate( - 'LLL:EXT:ke_search/Resources/Private/Language/locallang_mod.xlf:last_indexing', - 'KeSearch' - ) - . ' ' - . SearchHelper::formatTimestamp($lastRun['endTime']) - . '.

'; + $content .= LocalizationUtility::translate( + 'LLL:EXT:ke_search/Resources/Private/Language/locallang_mod.xlf:last_indexing', + 'KeSearch' + ) + . ' ' . SearchHelper::formatTimestamp($lastRun['endTime']); } + $content .= '
'; + $content .= '
'; $content .= '
'; $content .= '
TypeUIDPID
Indexer configurationTypeUIDPID
' . $this->encode($indexerConfiguration['title']) . '
'; $content .= ''; - $content .= ''; + $content .= ''; /** @var IndexRepository $indexRepository */ $indexRepository = GeneralUtility::makeInstance(IndexRepository::class); $results_per_type = $indexRepository->getNumberOfRecordsInIndexPerType(); - $first = true; foreach ($results_per_type as $type => $count) { $content .= ''; } diff --git a/Classes/Controller/IndexerStatusController.php b/Classes/Controller/IndexerStatusController.php index 221329029..f81aeb80c 100644 --- a/Classes/Controller/IndexerStatusController.php +++ b/Classes/Controller/IndexerStatusController.php @@ -8,48 +8,24 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Tpwd\KeSearch\Service\IndexerStatusService; -use Tpwd\KeSearch\Utility\TimeUtility; class IndexerStatusController { private ResponseFactoryInterface $responseFactory; private IndexerStatusService $indexerStatusService; - public function __construct(ResponseFactoryInterface $responseFactory, IndexerStatusService $indexerStatusService) { + public function __construct(ResponseFactoryInterface $responseFactory, IndexerStatusService $indexerStatusService) + { $this->responseFactory = $responseFactory; $this->indexerStatusService = $indexerStatusService; } public function getStatusAction(ServerRequestInterface $request): ResponseInterface { - $isRunning = $this->indexerStatusService->isRunning(); - $indexerStatus = []; - $html = '
Indexer is idle.
'; - - if ($isRunning) { - $indexerStartTime = $this->indexerStatusService->getIndexerStartTime(); - $indexerStatus = $this->indexerStatusService->getIndexerStatus(); - $html = '
Indexer is running.
'; - if ($indexerStatus['indexers'] ?? false) { - $html .= '
TypeCount
Type of indexed contentCount
' . $type . '' . $count . '
'; - foreach ($indexerStatus['indexers'] as $singleIndexerStatus) { - $statusLine = htmlspecialchars($singleIndexerStatus['statusText'], ENT_QUOTES, 'UTF-8'); - if ($singleIndexerStatus['status'] == $this->indexerStatusService::INDEXER_STATUS_RUNNING) { - $statusLine = ''; - } else { - $statusLine = ''; - } - $html .= $statusLine; - } - $html .= '
' . $statusLine . '
' . $statusLine . '
'; - $html .= '
Indexer is running since ' . TimeUtility::getRunningTimeHumanReadable($indexerStartTime) . '.' . '
'; - } - } - $result = [ - 'running' => $isRunning, - 'indexers' => $indexerStatus['indexers'] ?? [], - 'html' => $html, + 'running' => $this->indexerStatusService->isRunning(), + 'indexers' => $this->indexerStatusService->getIndexerStatus()['indexers'] ?? [], + 'html' => $this->indexerStatusService->getStatusReport(), ]; $response = $this->responseFactory->createResponse() @@ -60,5 +36,4 @@ public function getStatusAction(ServerRequestInterface $request): ResponseInterf return $response; } - } diff --git a/Classes/Indexer/IndexerRunner.php b/Classes/Indexer/IndexerRunner.php index f9985fe3b..403e48dbb 100644 --- a/Classes/Indexer/IndexerRunner.php +++ b/Classes/Indexer/IndexerRunner.php @@ -31,6 +31,7 @@ use Tpwd\KeSearch\Lib\SearchHelper; use Tpwd\KeSearch\Service\IndexerStatusService; use Tpwd\KeSearch\Utility\AdditionalWordCharactersUtility; +use Tpwd\KeSearch\Utility\TimeUtility; use TYPO3\CMS\Core\Log\Logger; use TYPO3\CMS\Core\Log\LogManager; use TYPO3\CMS\Core\Mail\MailMessage; @@ -233,7 +234,7 @@ public function startIndexing($verbose = true, $extConf = [], $mode = '', $index } $this->indexerStatusService->setFinishedStatus($indexerConfig); } - $content .= '
'; + $content .= '
' . chr(10); // process index cleanup $content .= $this->cleanUpIndex($indexingMode); @@ -247,13 +248,13 @@ public function startIndexing($verbose = true, $extConf = [], $mode = '', $index // log finishing $indexingTime = $this->endTime - $this->startTime; $content .= '
'; - $content .= '

Finished

'; + $content .= '

Finished

' . chr(10); $message = 'Indexing finished at ' . SearchHelper::formatTimestamp($this->endTime) . ' (took ' . $this->formatTime($indexingTime) . ').'; $content .= $message; $this->logger->info($message); - $message = '
Index contains ' . $this->indexRepository->getTotalNumberOfRecords() . ' entries.'; + $message = '
Index contains ' . $this->indexRepository->getTotalNumberOfRecords() . ' entries.'; $content .= $message; $this->logger->info($message); @@ -344,7 +345,7 @@ public function renderIndexingReport($searchObj, $message = '') } } - $content .= ''; + $content .= '' . chr(10); // duration, show sec or ms $content .= ''; @@ -355,9 +356,9 @@ public function renderIndexingReport($searchObj, $message = '') if ($duration > 1000) { $duration /= 1000; $duration = (int)$duration; - $content .= $duration . ' s.'; + $content .= TimeUtility::getSecondsHumanReadable($duration); } else { - $content .= $duration . ' ms.'; + $content .= $duration . ' ms'; } $content .= ''; } @@ -376,8 +377,9 @@ public function renderIndexingReport($searchObj, $message = '') public function createPlaintextReport($content) { $content = str_ireplace(['', '
', '
', '
', '
', '

'], chr(10), $content); - $report = preg_replace('~[ ]{2,}~', '', strip_tags($content)); - return $report; + $content = preg_replace('~[ ]{2,}~', '', strip_tags($content)); + $content = str_ireplace('Indexer configurationModeInfoTime', '', $content); + return $content; } /** @@ -501,7 +503,7 @@ public function cleanUpProcessAfterIndexing() public function cleanUpIndex(int $indexingMode) { $content = '
'; - $content .= '

Cleanup

'; + $content .= '

Cleanup

' . chr(10); if ($indexingMode == IndexerBase::INDEXING_MODE_FULL) { $this->logger->info('Cleanup started'); $startMicrotime = microtime(true); @@ -543,7 +545,7 @@ public function cleanUpIndex(int $indexingMode) // calculate duration of indexing process $duration = ceil((microtime(true) - $startMicrotime) * 1000); - $content .= 'Cleanup process took ' . $duration . ' ms.' . "\n"; + $content .= 'Cleanup process took ' . $duration . ' ms.' . "\n"; } else { $message = 'Skipping cleanup in incremental mode.'; $this->logger->info($message); diff --git a/Classes/Service/IndexerStatusService.php b/Classes/Service/IndexerStatusService.php index dabf12c74..3032902b6 100644 --- a/Classes/Service/IndexerStatusService.php +++ b/Classes/Service/IndexerStatusService.php @@ -3,6 +3,7 @@ namespace Tpwd\KeSearch\Service; use Tpwd\KeSearch\Lib\SearchHelper; +use Tpwd\KeSearch\Utility\TimeUtility; use TYPO3\CMS\Core\Registry; class IndexerStatusService @@ -14,6 +15,8 @@ class IndexerStatusService public const INDEXER_STATUS_SCHEDULED = 0; public const INDEXER_STATUS_RUNNING = 1; public const INDEXER_STATUS_FINISHED = 2; + public const INDEXER_STATUS_REPORT_FORMAT_HTML = 'html'; + public const INDEXER_STATUS_REPORT_FORMAT_PLAIN = 'plain'; private Registry $registry; @@ -58,7 +61,7 @@ public function setScheduledStatus(array $indexerConfig) 'totalRecords' => 0, 'statusText' => '"' . $indexerConfig['title'] . '"' - . ' is scheduled for execution' + . ' is scheduled for execution', ]; $this->setIndexerStatus($indexerStatus); } @@ -87,7 +90,7 @@ public function setRunningStatus(array $indexerConfig, int $currentRecordCount = 'totalRecords' => $totalRecordCount, 'statusText' => '"' . $indexerConfig['title'] . '"' - . ' is running' + . ' is running', ]; if ($currentRecordCount >= 0 && $totalRecordCount >= 0) { $indexerStatus['indexers'][$indexerConfig['uid']]['statusText'] .= @@ -121,18 +124,54 @@ public function setLastRunTime(int $startTime, int $endTime, int $indexingTime): [ 'startTime' => $startTime, 'endTime' => $endTime, - 'indexingTime' => $indexingTime + 'indexingTime' => $indexingTime, ] ); } /** * removes all entries from ke_search registry - * - * @return void */ public function clearAll(): void { $this->registry->removeAllByNamespace(self::INDEXER_STATUS_REGISTRY_NAMESPACE); } + + public function getStatusReport(string $format = self::INDEXER_STATUS_REPORT_FORMAT_HTML): string + { + $plain = []; + if ($this->isRunning()) { + $indexerStartTime = $this->getIndexerStartTime(); + $indexerStatus = $this->getIndexerStatus(); + $message = 'Indexer is running.'; + $html = '
' . $message . '
'; + $plain[] = $message; + if ($indexerStatus['indexers'] ?? false) { + $html .= '
'; + foreach ($indexerStatus['indexers'] as $singleIndexerStatus) { + $statusLine = htmlspecialchars($singleIndexerStatus['statusText'], ENT_QUOTES, 'UTF-8'); + if ($singleIndexerStatus['status'] == self::INDEXER_STATUS_RUNNING) { + $statusLine = ''; + } else { + $statusLine = ''; + } + $html .= $statusLine; + $plain[] = $singleIndexerStatus['statusText']; + } + $html .= '
' . $statusLine . '
' . $statusLine . '
'; + $message = 'Indexer is running since ' . TimeUtility::getRunningTimeHumanReadable($indexerStartTime) . '.'; + $html .= '
' . $message . '
'; + $plain[] = $message; + } + } else { + $message = 'Indexer is idle.'; + $html = '
' . $message . '
'; + $plain[] = $message; + } + + if ($format == self::INDEXER_STATUS_REPORT_FORMAT_PLAIN) { + return implode(chr(10), $plain); + } + return $html; + } } diff --git a/Classes/Utility/TimeUtility.php b/Classes/Utility/TimeUtility.php index 841f86275..579cd940d 100644 --- a/Classes/Utility/TimeUtility.php +++ b/Classes/Utility/TimeUtility.php @@ -26,21 +26,28 @@ public static function getRunningTimeHumanReadable(int $indexerStartTime): strin if ($indexerRunningTime < 0) { return ''; } - $indexerRunningTimeHMS = TimeUtility::getTimeHoursMinutesSeconds($indexerRunningTime); + return self::getSecondsHumanReadable($indexerRunningTime); + } + public static function getSecondsHumanReadable(int $seconds): string + { + $timeHMS = TimeUtility::getTimeHoursMinutesSeconds($seconds); $result = ''; - if ($indexerRunningTimeHMS['h']) { - $result .= ' ' . $indexerRunningTimeHMS['h'] . ' h'; + if ($timeHMS['h']) { + $result .= $timeHMS['h'] . ' h'; } - if ($indexerRunningTimeHMS['m']) { - $result .= ' ' . $indexerRunningTimeHMS['m'] . ' m'; + if (!empty($result)) { + $result .= ' '; } - if ($indexerRunningTimeHMS['s']) { - $result .= ' ' . $indexerRunningTimeHMS['s'] . ' s'; + if ($timeHMS['m']) { + $result .= $timeHMS['m'] . ' m'; + } + if (!empty($result)) { + $result .= ' '; + } + if ($timeHMS['s']) { + $result .= $timeHMS['s'] . ' s'; } - return $result; } - - } diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index ddedc714b..0329024aa 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -38,6 +38,12 @@ services: command: 'ke_search:removelock' description: 'Removes the ke_search lock' + Tpwd\KeSearch\Command\IndexerStatusCommand: + tags: + - name: 'console.command' + command: 'ke_search:indexerstatus' + description: 'Shows the status of the indexer' + Tpwd\KeSearch\Backend\Flexform: public: true diff --git a/Tests/Unit/Command/StartIndexerCommandTest.php b/Tests/Unit/Command/StartIndexerCommandTest.php index 3d53e961f..e033895e6 100644 --- a/Tests/Unit/Command/StartIndexerCommandTest.php +++ b/Tests/Unit/Command/StartIndexerCommandTest.php @@ -151,7 +151,7 @@ public function indexerOutputIsCorrectlyDisplayed(string $indexerResult, string public function dataProviderForIndexerOutput(): iterable { $indexerResult = <<
Running indexing process in full mode.
IndexerModeInfoTime
Pages10 pages have been selected for indexing in the main language.
+
Running indexing process in full mode.
Indexer configurationModeInfoTime
Pages10 pages have been selected for indexing in the main language.
3 languages (All languages, English, German) have been found.
2 pages have been indexed.
8 had no content or the content was not indexable.
@@ -160,13 +160,13 @@ public function dataProviderForIndexerOutput(): iterable

Indexing finished at 02/16/22, 18:36:34 (took 0 seconds).

Index contains 2 entries.

EOL; $plaintextResult = <<