TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,259 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Scheduler\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
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 Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use TYPO3\CMS\Core\Attribute\AsNonSchedulableCommand;
|
||||
|
||||
use TYPO3\CMS\Core\Core\Bootstrap;
|
||||
use TYPO3\CMS\Core\Utility\MathUtility;
|
||||
use TYPO3\CMS\Scheduler\Domain\Repository\SchedulerTaskRepository;
|
||||
use TYPO3\CMS\Scheduler\Scheduler;
|
||||
use TYPO3\CMS\Scheduler\Service\TaskService;
|
||||
use TYPO3\CMS\Scheduler\Task\AbstractTask;
|
||||
use TYPO3\CMS\Scheduler\Validation\Validator\TaskValidator;
|
||||
|
||||
/**
|
||||
* CLI command for the 'scheduler' extension which executes
|
||||
*
|
||||
* @internal Specific command implementation, not part of TYPO3 API.
|
||||
*/
|
||||
#[AsCommand('scheduler:run', 'Start the TYPO3 Scheduler from the command line.')]
|
||||
#[AsNonSchedulableCommand]
|
||||
class SchedulerCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var SymfonyStyle
|
||||
*/
|
||||
protected $io;
|
||||
|
||||
/**
|
||||
* Array of tasks UIDs that should be executed. Null if task option is not provided.
|
||||
*
|
||||
* @var int[]|null
|
||||
*/
|
||||
protected $overwrittenTaskList;
|
||||
|
||||
/**
|
||||
* This is true when the tasks should be marked as stopped instead of being executed.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $stopTasks = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $forceExecution;
|
||||
|
||||
public function __construct(
|
||||
protected readonly Scheduler $scheduler,
|
||||
protected readonly SchedulerTaskRepository $taskRepository,
|
||||
protected readonly TaskService $taskService,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the command by defining the name, options and arguments
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setHelp('If no parameter is given, the scheduler executes any tasks that are overdue to run.
|
||||
Call it like this: typo3/sysext/core/bin/typo3 scheduler:run --task=13 -f')
|
||||
->addOption(
|
||||
'task',
|
||||
'i',
|
||||
InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
|
||||
'UID of a specific task. Can be provided multiple times to execute multiple tasks sequentially.'
|
||||
)
|
||||
->addOption(
|
||||
'force',
|
||||
'f',
|
||||
InputOption::VALUE_NONE,
|
||||
'Force execution of the task which is passed with --task option'
|
||||
)
|
||||
->addOption(
|
||||
'stop',
|
||||
's',
|
||||
InputOption::VALUE_NONE,
|
||||
'Stop the task which is passed with --task option'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute scheduler tasks
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$this->io = new SymfonyStyle($input, $output);
|
||||
|
||||
// Make sure the _cli_ user is loaded
|
||||
Bootstrap::initializeBackendAuthentication();
|
||||
|
||||
$overwrittenTaskList = $input->getOption('task');
|
||||
$overwrittenTaskList = is_array($overwrittenTaskList) ? $overwrittenTaskList : [];
|
||||
$overwrittenTaskList = array_filter($overwrittenTaskList, static fn($value) => MathUtility::canBeInterpretedAsInteger($value));
|
||||
$overwrittenTaskList = array_map('intval', $overwrittenTaskList);
|
||||
if ($overwrittenTaskList !== []) {
|
||||
$this->overwrittenTaskList = $overwrittenTaskList;
|
||||
}
|
||||
|
||||
$this->forceExecution = (bool)$input->getOption('force');
|
||||
$this->stopTasks = $this->shouldStopTasks((bool)$input->getOption('stop'));
|
||||
return $this->loopTasks() ? Command::SUCCESS : Command::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the tasks should be stopped instead of being executed.
|
||||
*
|
||||
* Stopping is only performed when the --stop option is provided together with the --task option.
|
||||
*
|
||||
* @param bool $stopOption
|
||||
*/
|
||||
protected function shouldStopTasks(bool $stopOption): bool
|
||||
{
|
||||
if (!$stopOption) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->overwrittenTaskList !== []) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->io->isVerbose()) {
|
||||
$this->io->warning('Stopping tasks is only possible when the --task option is provided.');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop task
|
||||
*/
|
||||
protected function stopTask(AbstractTask $task)
|
||||
{
|
||||
$this->taskRepository->removeAllRegisteredExecutionsForTask($task);
|
||||
if ($this->io->isVeryVerbose()) {
|
||||
$this->io->writeln(sprintf('Task #%d was stopped', $task->getTaskUid()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return task a task for a given UID
|
||||
*/
|
||||
protected function getTask(int $taskUid): ?AbstractTask
|
||||
{
|
||||
$force = $this->stopTasks || $this->forceExecution;
|
||||
if ($force) {
|
||||
return $this->taskRepository->findByUid($taskUid);
|
||||
}
|
||||
|
||||
return $this->taskRepository->findNextExecutableTaskForUid($taskUid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute tasks in loop that are ready to execute
|
||||
*/
|
||||
protected function loopTasks(): bool
|
||||
{
|
||||
$hasError = false;
|
||||
do {
|
||||
$task = null;
|
||||
// Try getting the next task and execute it
|
||||
// If there are no more tasks to execute, an exception is thrown by \TYPO3\CMS\Scheduler\Scheduler::fetchTask()
|
||||
try {
|
||||
$task = $this->fetchNextTask();
|
||||
if ($task === null) {
|
||||
break;
|
||||
}
|
||||
try {
|
||||
$this->executeOrStopTask($task);
|
||||
} catch (\Exception $e) {
|
||||
$taskDetails = $this->taskService->getTaskDetailsFromTask($task);
|
||||
$messages = [
|
||||
$e->getMessage() . PHP_EOL,
|
||||
'Exception in scheduler task #' . $task->getTaskUid() . ' (' . $task->getTaskType() . ' - ' . $taskDetails['title'] . ')',
|
||||
];
|
||||
$messages[] = 'File: ' . $e->getFile() . ':' . $e->getLine();
|
||||
$this->io->getErrorStyle()->error($messages);
|
||||
$hasError = true;
|
||||
// We ignore any exception that may have been thrown during execution,
|
||||
// as this is a background process.
|
||||
// The exception message has been recorded to the database anyway
|
||||
continue;
|
||||
}
|
||||
} catch (\UnexpectedValueException $e) {
|
||||
$this->io->getErrorStyle()->error($e->getMessage());
|
||||
$hasError = true;
|
||||
continue;
|
||||
}
|
||||
} while ($task !== null);
|
||||
// Record the run in the system registry
|
||||
$this->scheduler->recordLastRun();
|
||||
return !$hasError;
|
||||
}
|
||||
|
||||
/**
|
||||
* When the --task option is provided, the next task is fetched from the provided task UIDs. Depending
|
||||
* on the --force option the task is fetched even if it is not marked for execution.
|
||||
*
|
||||
* Without the --task option we ask the scheduler for the next task with pending execution.
|
||||
*
|
||||
* @throws \UnexpectedValueException When no task is found by the provided UID or the task is not marked for execution.
|
||||
*/
|
||||
protected function fetchNextTask(): ?AbstractTask
|
||||
{
|
||||
if ($this->overwrittenTaskList === null) {
|
||||
return $this->taskRepository->findNextExecutableTask();
|
||||
}
|
||||
|
||||
if (count($this->overwrittenTaskList) === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$taskUid = (int)array_shift($this->overwrittenTaskList);
|
||||
$task = $this->getTask($taskUid);
|
||||
if (!(new TaskValidator())->isValid($task)) {
|
||||
throw new \UnexpectedValueException(
|
||||
sprintf('The task #%d is not scheduled for execution or does not exist.', $taskUid),
|
||||
1547675557
|
||||
);
|
||||
}
|
||||
return $task;
|
||||
}
|
||||
|
||||
/**
|
||||
* When in stop mode the given task is stopped. Otherwise the task is executed.
|
||||
*/
|
||||
protected function executeOrStopTask(AbstractTask $task): void
|
||||
{
|
||||
if ($this->stopTasks) {
|
||||
$this->stopTask($task);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->scheduler->executeTask($task);
|
||||
if ($this->io->isVeryVerbose()) {
|
||||
$this->io->writeln(sprintf('Task #%d was executed', $task->getTaskUid()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Scheduler\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Helper\QuestionHelper;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\ChoiceQuestion;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use TYPO3\CMS\Core\Attribute\AsNonSchedulableCommand;
|
||||
|
||||
use TYPO3\CMS\Core\Context\Context;
|
||||
use TYPO3\CMS\Core\Core\Bootstrap;
|
||||
use TYPO3\CMS\Core\Localization\LanguageService;
|
||||
use TYPO3\CMS\Core\Localization\LanguageServiceFactory;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Scheduler\Domain\Repository\SchedulerTaskRepository;
|
||||
use TYPO3\CMS\Scheduler\Scheduler;
|
||||
use TYPO3\CMS\Scheduler\Service\TaskService;
|
||||
|
||||
/**
|
||||
* CLI command for EXT:scheduler to execute tasks
|
||||
*/
|
||||
#[AsCommand('scheduler:execute', 'Execute given TYPO3 Scheduler tasks.')]
|
||||
#[AsNonSchedulableCommand]
|
||||
class SchedulerExecuteCommand extends Command
|
||||
{
|
||||
protected SymfonyStyle $io;
|
||||
|
||||
public function __construct(
|
||||
protected readonly Context $context,
|
||||
protected readonly SchedulerTaskRepository $taskRepository,
|
||||
protected readonly TaskService $taskService,
|
||||
protected Scheduler $scheduler,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addOption(
|
||||
'task',
|
||||
't',
|
||||
InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
|
||||
'Execute tasks by given id. To run all tasks of a group prefix the group id with "g:", e.g. "g:1"',
|
||||
);
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
// Make sure the _cli_ user is loaded
|
||||
Bootstrap::initializeBackendAuthentication();
|
||||
$this->io = new SymfonyStyle($input, $output);
|
||||
|
||||
if (count($input->getOption('task')) > 0) {
|
||||
$taskGroups = $this->taskRepository->getGroupedTasks()['taskGroupsWithTasks'];
|
||||
$tasksToRun = $this->getTasksToRun($taskGroups, $input->getOption('task'));
|
||||
$this->runTasks($tasksToRun, $taskGroups);
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$this->askForTasksAndRun($input, $output);
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
private function askForTasksAndRun(InputInterface $input, OutputInterface $output): void
|
||||
{
|
||||
/** @var QuestionHelper $questionHelper */
|
||||
$questionHelper = $this->getHelper('question');
|
||||
$taskGroups = $this->taskRepository->getGroupedTasks()['taskGroupsWithTasks'];
|
||||
$selectableTasks = $this->getSelectableTasks($taskGroups);
|
||||
if ($selectableTasks === []) {
|
||||
$this->io->note('No tasks available.');
|
||||
return;
|
||||
}
|
||||
|
||||
$tasksToRunQuestion = new ChoiceQuestion('Run tasks (comma-separated list): ', $selectableTasks);
|
||||
$tasksToRunQuestion->setAutocompleterValues(array_keys($selectableTasks));
|
||||
$tasksToRunQuestion->setMultiselect(true);
|
||||
$tasksToRun = $questionHelper->ask($input, $output, $tasksToRunQuestion);
|
||||
|
||||
$this->runTasks($tasksToRun, $taskGroups);
|
||||
}
|
||||
|
||||
private function runTasks($selectedTasks, $taskGroups): void
|
||||
{
|
||||
$taskUids = $this->getTaskUidsFromSelection($selectedTasks, $taskGroups);
|
||||
ksort($taskUids);
|
||||
$numLength = strlen((string)array_reverse($taskUids)[0]);
|
||||
|
||||
foreach ($taskUids as $taskUid) {
|
||||
try {
|
||||
$uid = (int)$taskUid;
|
||||
$task = $this->taskRepository->findByUid($uid);
|
||||
$additionalInformation = $task->getAdditionalInformation() === '' ? '' : ' (' . $task->getAdditionalInformation() . ')';
|
||||
$taskDetails = $this->taskService->getTaskDetailsFromTask($task);
|
||||
$space = str_repeat(' ', $numLength - strlen((string)$task->getTaskUid()));
|
||||
$this->io->writeln('[ <fg=green>TASK:' . $task->getTaskUid() . $space . '</> ] Running "' . $taskDetails['title'] . $additionalInformation . '"');
|
||||
$this->scheduler->executeTask($task);
|
||||
} catch (\Throwable $exception) {
|
||||
$this->io->writeln($exception->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getTaskUidsFromSelection(array $list, array $groups): array
|
||||
{
|
||||
$taskUids = [];
|
||||
foreach ($list as $uid) {
|
||||
[$keyword, $group] = [...explode(':', (string)$uid), null];
|
||||
if ($keyword === 'g') {
|
||||
if (!array_key_exists($group, $groups)) {
|
||||
throw new \InvalidArgumentException('Group with id "' . $group . '" does not exist.', 1679683415);
|
||||
}
|
||||
$taskUidsInGroup = array_column($groups[$group]['tasks'], 'uid');
|
||||
$taskUids += $taskUidsInGroup;
|
||||
} else {
|
||||
$taskUids[] = $uid;
|
||||
}
|
||||
}
|
||||
return $taskUids;
|
||||
}
|
||||
|
||||
private function getLanguageService(): LanguageService
|
||||
{
|
||||
return GeneralUtility::makeInstance(LanguageServiceFactory::class)->create('en');
|
||||
}
|
||||
|
||||
private function getTasksToRun(array $taskGroups, array $taskList): array
|
||||
{
|
||||
$taskUids = array_unique($this->getTaskUidsFromSelection($taskList, $taskGroups));
|
||||
foreach ($taskUids as $taskUid) {
|
||||
// This will throw an exception if the task uid was not found and print it to the console.
|
||||
$this->taskRepository->findByUid((int)$taskUid);
|
||||
}
|
||||
return $taskUids;
|
||||
}
|
||||
|
||||
protected function getSelectableTasks(mixed $taskGroups): array
|
||||
{
|
||||
$selectableTasks = [];
|
||||
foreach ($taskGroups as $uid => $group) {
|
||||
$groupLabel = ($group['groupName'] ?? $this->getLanguageService()->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:label.noGroup'));
|
||||
$selectableTasks['g:' . $uid] = '<fg=yellow>' . $groupLabel . '</>';
|
||||
|
||||
foreach ($group['tasks'] as $task) {
|
||||
$additionalInformation = $task['additionalInformation'] === '' ? '' : ' (' . $task['additionalInformation'] . ')';
|
||||
$selectableTasks[$task['uid']] = $task['fullTitle'] . $additionalInformation;
|
||||
}
|
||||
}
|
||||
return $selectableTasks;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Scheduler\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Helper\TableCell;
|
||||
use Symfony\Component\Console\Helper\TableSeparator;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\BufferedOutput;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\ConsoleSectionOutput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use TYPO3\CMS\Core\Attribute\AsNonSchedulableCommand;
|
||||
use TYPO3\CMS\Core\Core\Bootstrap;
|
||||
use TYPO3\CMS\Core\Localization\LanguageService;
|
||||
use TYPO3\CMS\Core\Localization\LanguageServiceFactory;
|
||||
use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Scheduler\Domain\Repository\SchedulerTaskRepository;
|
||||
use TYPO3\CMS\Scheduler\Task\TaskStatus;
|
||||
|
||||
/**
|
||||
* CLI command for EXT:scheduler to list tasks
|
||||
*/
|
||||
#[AsCommand('scheduler:list', 'List all TYPO3 Scheduler tasks.')]
|
||||
#[AsNonSchedulableCommand]
|
||||
class SchedulerListCommand extends Command
|
||||
{
|
||||
protected SymfonyStyle $io;
|
||||
|
||||
public function __construct(
|
||||
protected readonly SchedulerTaskRepository $taskRepository,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addOption(
|
||||
'group',
|
||||
'g',
|
||||
InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
|
||||
'Show only groups with given uid',
|
||||
)
|
||||
->addOption(
|
||||
'watch',
|
||||
'w',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'Start watcher mode (polling)',
|
||||
);
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
if (!$output instanceof ConsoleOutputInterface) {
|
||||
throw new \InvalidArgumentException('This command accepts only an instance of "ConsoleOutputInterface".', 1678645754);
|
||||
}
|
||||
|
||||
// Make sure the _cli_ user is loaded
|
||||
Bootstrap::initializeBackendAuthentication();
|
||||
$this->io = new SymfonyStyle($input, $output);
|
||||
$languageService = $this->getLanguageService();
|
||||
|
||||
$tableHeader = [
|
||||
$languageService->sL('scheduler.messages:label.id'),
|
||||
$languageService->sL('scheduler.messages:task'),
|
||||
$languageService->sL('scheduler.messages:label.description'),
|
||||
$languageService->sL('scheduler.messages:label.frequency'),
|
||||
$languageService->sL('scheduler.messages:status'),
|
||||
];
|
||||
|
||||
$tableSection = $output->section();
|
||||
$tableBuffer = new BufferedOutput(OutputInterface::VERBOSITY_NORMAL, true);
|
||||
$table = new Table($tableBuffer);
|
||||
$table->setHeaders($tableHeader);
|
||||
$showGroups = $input->getOption('group');
|
||||
$rows = $this->getTableRows($showGroups);
|
||||
$table->setRows($rows);
|
||||
$table->setColumnMaxWidth(1, 50);
|
||||
$table->setColumnMaxWidth(2, 50);
|
||||
$table->setColumnMaxWidth(4, 50);
|
||||
$table->render();
|
||||
|
||||
$bufferedData = $tableBuffer->fetch();
|
||||
$tableSection->overwrite($bufferedData);
|
||||
|
||||
$doWatch = $input->hasParameterOption('--watch') || $input->hasParameterOption('-w');
|
||||
if ($doWatch) {
|
||||
$infoSection = $output->section();
|
||||
$interval = (int)($input->getOption('watch') ?: 1);
|
||||
$infoSection->write('Watching tasks every ' . $interval . ' seconds, press CTRL+C to stop watching');
|
||||
|
||||
while (true) { // @phpstan-ignore while.alwaysTrue (intentional infinite loop for CLI watch mode, terminated by CTRL+C signal)
|
||||
sleep($interval);
|
||||
$this->updateTable($input, $table, $tableBuffer, $tableSection);
|
||||
}
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
private function getTableRows(array $groups = []): array
|
||||
{
|
||||
$tasks = $this->taskRepository->getGroupedTasks();
|
||||
$languageService = $this->getLanguageService();
|
||||
|
||||
$rows = [];
|
||||
foreach ($tasks['taskGroupsWithTasks'] as $uid => $group) {
|
||||
if (!in_array($uid, $groups) && count($groups) > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Flag as disabled group
|
||||
$groupDisabledLabel = $group['hidden'] ? '<fg=yellow>' . $this->getLanguageService()->sL('scheduler.messages:status.disabled') . '</>' : '';
|
||||
$groupLabel = ($group['groupName'] ?? $languageService->sL('scheduler.messages:label.noGroup')) . ' (id:' . $uid . ') ' . $groupDisabledLabel;
|
||||
|
||||
$rows[] = [new TableSeparator(['colspan' => 5])];
|
||||
$rows[] = [new TableCell('<options=bold>' . $groupLabel . '</>', ['colspan' => 5])];
|
||||
$rows[] = [new TableSeparator(['colspan' => 5])];
|
||||
|
||||
foreach ($group['tasks'] as $task) {
|
||||
$progress = $task['progress'] ?? false;
|
||||
$taskStatus = [];
|
||||
|
||||
/** @var TaskStatus $status */
|
||||
foreach ($task['statuses'] as $status) {
|
||||
$color = match ($status->severity) {
|
||||
ContextualFeedbackSeverity::OK => 'green',
|
||||
ContextualFeedbackSeverity::INFO => 'blue',
|
||||
ContextualFeedbackSeverity::WARNING => 'yellow',
|
||||
ContextualFeedbackSeverity::ERROR => 'red',
|
||||
ContextualFeedbackSeverity::NOTICE => 'gray',
|
||||
};
|
||||
$label = $languageService->sL($status->label);
|
||||
if ($status->type === 'running' && $progress) {
|
||||
$label .= ' (' . $progress . ')';
|
||||
}
|
||||
// The console has no tooltip, so the more detailed message
|
||||
// (e.g. the failure reason) is shown inline instead.
|
||||
if ($status->message !== '') {
|
||||
$label .= ' (' . vsprintf($languageService->sL($status->message), $status->messageArguments) . ')';
|
||||
}
|
||||
$taskStatus[] = '<fg=' . $color . '>' . $label . '</>';
|
||||
}
|
||||
|
||||
$taskTitle = $task['fullTitle'] . (empty($task['additionalInformation']) ? '' : ' (' . $task['additionalInformation'] . ')');
|
||||
$rows[] = [
|
||||
$task['uid'],
|
||||
$taskTitle,
|
||||
$task['description'],
|
||||
$task['frequency'],
|
||||
implode(', ', $taskStatus),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
private function getLanguageService(): LanguageService
|
||||
{
|
||||
return GeneralUtility::makeInstance(LanguageServiceFactory::class)->create('en');
|
||||
}
|
||||
|
||||
protected function updateTable(InputInterface $input, Table $table, BufferedOutput $buffer, ConsoleSectionOutput $tableSection): void
|
||||
{
|
||||
$tableSection->overwrite('');
|
||||
$rows = $this->getTableRows($input->getOption('group'));
|
||||
$table->setRows($rows)->render();
|
||||
$bufferedData = $buffer->fetch();
|
||||
$tableSection->overwrite($bufferedData);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user