Skip to content

Commit 6cc6461

Browse files
bmacksbuerk
authored andcommitted
[TASK] Introduce TCA for tx_scheduler_task
TCA is now added to tx_scheduler_task allowing to use DataHandler to persist changes within the scheduler module. In addition, DatabaseRestrictions can be used for tx_scheduler_task now, making it best practice for EXT:scheduler as well. We also now have history support for scheduler tasks! Custom logging while persisting is now removed as DataHandler is taking care of this in sys_log. FormEngine / Editing is currently unavailable due to "hideTable => true". Custom persistence validation is currently still handled in SchedulerTaskRepository, before it is migrated to DataHandler hooks in the next patch. Resolves: #106657 Releases: main Change-Id: I676dddc14430a36f884e64452b5073f7ef59c886 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/89324 Reviewed-by: Stefan Bürk <stefan@buerk.tech> Reviewed-by: Stefan Froemken <froemken@gmail.com> Tested-by: Stefan Froemken <froemken@gmail.com> Tested-by: core-ci <typo3@b13.com> Tested-by: Stefan Bürk <stefan@buerk.tech>
1 parent 36013d5 commit 6cc6461

File tree

8 files changed

+388
-189
lines changed

8 files changed

+388
-189
lines changed

typo3/sysext/scheduler/Classes/Controller/SchedulerModuleController.php

Lines changed: 20 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,13 @@
2626
use TYPO3\CMS\Backend\Template\Components\Buttons\GenericButton;
2727
use TYPO3\CMS\Backend\Template\ModuleTemplate;
2828
use TYPO3\CMS\Backend\Template\ModuleTemplateFactory;
29-
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
3029
use TYPO3\CMS\Core\Context\Context;
3130
use TYPO3\CMS\Core\Database\ConnectionPool;
3231
use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;
3332
use TYPO3\CMS\Core\Domain\DateTimeFormat;
3433
use TYPO3\CMS\Core\Imaging\IconFactory;
3534
use TYPO3\CMS\Core\Imaging\IconSize;
3635
use TYPO3\CMS\Core\Localization\LanguageService;
37-
use TYPO3\CMS\Core\SysLog\Action\Database as SystemLogDatabaseAction;
38-
use TYPO3\CMS\Core\SysLog\Error as SystemLogErrorClassification;
39-
use TYPO3\CMS\Core\SysLog\Type as SystemLogType;
4036
use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity;
4137
use TYPO3\CMS\Core\Utility\GeneralUtility;
4238
use TYPO3\CMS\Core\Utility\MathUtility;
@@ -141,7 +137,7 @@ public function handleRequest(ServerRequestInterface $request): ResponseInterfac
141137
&& in_array($parsedBody['CMD'] ?? '', ['save', 'saveclose', 'close'], true)
142138
) {
143139
// Received data for adding a new task - validate, persist, render requested 'next' action.
144-
$isTaskDataValid = $this->isSubmittedTaskDataValid($view, $request, true);
140+
$isTaskDataValid = $this->isSubmittedTaskDataValid($view, $request->getParsedBody()['tx_scheduler'] ?? [], true);
145141
if (!$isTaskDataValid) {
146142
return $this->renderAddTaskFormView($view, $request);
147143
}
@@ -161,7 +157,7 @@ public function handleRequest(ServerRequestInterface $request): ResponseInterfac
161157
&& in_array($parsedBody['CMD'] ?? '', ['save', 'close', 'saveclose', 'new'], true)
162158
) {
163159
// Received data for updating existing task - validate, persist, render requested 'next' action.
164-
$isTaskDataValid = $this->isSubmittedTaskDataValid($view, $request, false);
160+
$isTaskDataValid = $this->isSubmittedTaskDataValid($view, $request->getParsedBody()['tx_scheduler'] ?? [], false);
165161
if (!$isTaskDataValid) {
166162
return $this->renderEditTaskFormView($view, $request);
167163
}
@@ -202,12 +198,11 @@ public function getCurrentAction(): SchedulerManagementAction
202198
}
203199

204200
/**
205-
* Set a task to deleted.
201+
* Mark a task as deleted.
206202
*/
207203
protected function deleteTask(ModuleTemplate $view, int $taskUid): void
208204
{
209205
$languageService = $this->getLanguageService();
210-
$backendUser = $this->getBackendUser();
211206
if ($taskUid <= 0) {
212207
throw new \RuntimeException('Expecting a valid task uid', 1641670374);
213208
}
@@ -219,14 +214,6 @@ protected function deleteTask(ModuleTemplate $view, int $taskUid): void
219214
$this->addMessage($view, $languageService->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:msg.canNotDeleteRunningTask'), ContextualFeedbackSeverity::ERROR);
220215
} else {
221216
if ($this->taskRepository->remove($task)) {
222-
$backendUser->writelog(
223-
SystemLogType::EXTENSION,
224-
SystemLogDatabaseAction::DELETE,
225-
SystemLogErrorClassification::MESSAGE,
226-
null,
227-
'Scheduler task "%s" (UID: %s, Type: "%s") was deleted',
228-
[$task->getTaskTitle(), $task->getTaskUid(), $task->getTaskType()]
229-
);
230217
$this->addMessage($view, $languageService->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:msg.deleteSuccess'));
231218
} else {
232219
$this->addMessage($view, $languageService->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:msg.deleteError'));
@@ -290,13 +277,11 @@ protected function toggleDisabledFlag(ModuleTemplate $view, int $taskUid): void
290277
}
291278
try {
292279
$task = $this->taskRepository->findByUid($taskUid);
293-
// If a disabled single task is enabled again, register it for a single execution at next scheduler run.
294-
$isTaskQueuedForExecution = $task->getType() === AbstractTask::TYPE_SINGLE;
295-
296-
// Toggle task state and add a flash message
297-
$taskName = $this->getHumanReadableTaskName($task);
280+
// Toggle the task state and add a flash message
281+
$taskName = $this->taskService->getHumanReadableTaskName($task);
298282
$isTaskDisabled = $task->isDisabled();
299-
if ($isTaskDisabled && $isTaskQueuedForExecution) {
283+
// If a disabled single task is enabled again, register it for a single execution at next scheduler run.
284+
if ($isTaskDisabled && $task->getExecution()->isSingleRun()) {
300285
$task->setDisabled(false);
301286
$execution = Execution::createSingleExecution($this->context->getAspect('date')->get('timestamp'));
302287
$task->setExecution($execution);
@@ -368,7 +353,7 @@ protected function renderAddTaskFormView(ModuleTemplate $view, ServerRequestInte
368353
$parseBodyForProvider['taskType'] = $taskType;
369354
}
370355
$fields = $providerObject->getAdditionalFields($parseBodyForProvider, null, $this);
371-
$additionalFields = array_merge($additionalFields, $this->preparedAdditionalFields($fields, $taskType));
356+
$additionalFields = $this->taskService->prepareAdditionalFields($taskType, $fields, $additionalFields);
372357
}
373358

374359
$view->assignMultiple([
@@ -442,9 +427,9 @@ protected function renderEditTaskFormView(ModuleTemplate $view, ServerRequestInt
442427
}
443428

444429
$taskExecution = $task->getExecution();
445-
$taskName = $this->getHumanReadableTaskName($task);
430+
$taskName = $this->taskService->getHumanReadableTaskName($task);
446431
// If an interval or a cron command is defined, it's a recurring task
447-
$taskRunningType = (int)($parsedBody['runningType'] ?? ((empty($taskExecution->getCronCmd()) && empty($taskExecution->getInterval())) ? AbstractTask::TYPE_SINGLE : AbstractTask::TYPE_RECURRING));
432+
$taskRunningType = (int)($parsedBody['runningType'] ?? ($taskExecution->isSingleRun() ? AbstractTask::TYPE_SINGLE : AbstractTask::TYPE_RECURRING));
448433

449434
$currentData = [
450435
'taskType' => $taskType,
@@ -469,7 +454,7 @@ protected function renderEditTaskFormView(ModuleTemplate $view, ServerRequestInt
469454
// Additional field providers receive form data by reference. But they shouldn't pollute our array here.
470455
$parseBodyForProvider = $request->getParsedBody()['tx_scheduler'] ?? [];
471456
$fields = $providerObject->getAdditionalFields($parseBodyForProvider, $task, $this);
472-
$additionalFields = $this->preparedAdditionalFields($fields, (string)$taskType);
457+
$additionalFields = $this->taskService->prepareAdditionalFields((string)$taskType, $fields);
473458
}
474459

475460
$view->assignMultiple([
@@ -512,7 +497,7 @@ protected function executeTasks(ModuleTemplate $view, string $taskUids): void
512497
foreach ($taskUids as $uid) {
513498
try {
514499
$task = $this->taskRepository->findByUid($uid);
515-
$name = $this->getHumanReadableTaskName($task);
500+
$name = $this->taskService->getHumanReadableTaskName($task);
516501
// Try to execute it and report result
517502
$result = $this->scheduler->executeTask($task);
518503
if ($result) {
@@ -543,7 +528,7 @@ protected function scheduleCrons(ModuleTemplate $view, string $taskUids): void
543528
foreach ($taskUids as $uid) {
544529
try {
545530
$task = $this->taskRepository->findByUid($uid);
546-
$name = $this->getHumanReadableTaskName($task);
531+
$name = $this->taskService->getHumanReadableTaskName($task);
547532
$task->setRunOnNextCronJob(true);
548533
if ($task->isDisabled()) {
549534
$task->setDisabled(false);
@@ -597,11 +582,13 @@ protected function renderListTasksView(ModuleTemplate $view, ModuleData $moduleD
597582
return $view->renderResponse('ListTasks');
598583
}
599584

600-
protected function isSubmittedTaskDataValid(ModuleTemplate $view, ServerRequestInterface $request, bool $isNewTask): bool
585+
protected function isSubmittedTaskDataValid(ModuleTemplate $view, array $parsedBody, bool $isNewTask): bool
601586
{
587+
if ($parsedBody === []) {
588+
return false;
589+
}
602590
$languageService = $this->getLanguageService();
603-
$parsedBody = $request->getParsedBody()['tx_scheduler'] ?? [];
604-
$taskType = $parsedBody['taskType'];
591+
$taskType = (string)($parsedBody['taskType'] ?? '');
605592
$runningType = (int)($parsedBody['runningType'] ?? 0);
606593
$startTime = $parsedBody['start'] ?? 0;
607594
$endTime = $parsedBody['end'] ?? 0;
@@ -677,18 +664,10 @@ protected function createTask(ModuleTemplate $view, ServerRequestInterface $requ
677664
{
678665
$taskType = $request->getParsedBody()['tx_scheduler']['taskType'];
679666
$task = $this->taskService->createNewTask($taskType);
680-
$task = $this->setTaskDataFromRequest($task, $request);
667+
$task = $this->taskService->setTaskDataFromRequest($task, $request->getParsedBody()['tx_scheduler'] ?? []);
681668
if (!$this->taskRepository->add($task)) {
682669
throw new \RuntimeException('Unable to add task. Possible database error', 1641720169);
683670
}
684-
$this->getBackendUser()->writelog(
685-
SystemLogType::EXTENSION,
686-
SystemLogDatabaseAction::INSERT,
687-
SystemLogErrorClassification::MESSAGE,
688-
null,
689-
'Scheduler task "%s" (UID: %s, Type: "%s") was added',
690-
[$task->getTaskTitle(), $task->getTaskUid(), $task->getTaskType()]
691-
);
692671
$this->addMessage($view, $this->getLanguageService()->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:msg.addSuccess'));
693672
return $task->getTaskUid();
694673
}
@@ -699,42 +678,11 @@ protected function createTask(ModuleTemplate $view, ServerRequestInterface $requ
699678
protected function updateTask(ModuleTemplate $view, ServerRequestInterface $request): void
700679
{
701680
$task = $this->taskRepository->findByUid((int)$request->getParsedBody()['tx_scheduler']['uid']);
702-
$task = $this->setTaskDataFromRequest($task, $request);
681+
$task = $this->taskService->setTaskDataFromRequest($task, $request->getParsedBody()['tx_scheduler'] ?? []);
703682
$this->taskRepository->update($task);
704-
$this->getBackendUser()->writelog(
705-
SystemLogType::EXTENSION,
706-
SystemLogDatabaseAction::UPDATE,
707-
SystemLogErrorClassification::MESSAGE,
708-
null,
709-
'Scheduler task "%s" (UID: %s, Type: "%s") was updated',
710-
[$task->getTaskTitle(), $task->getTaskUid(), $task->getTaskType()]
711-
);
712683
$this->addMessage($view, $this->getLanguageService()->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:msg.updateSuccess'));
713684
}
714685

715-
protected function setTaskDataFromRequest(AbstractTask $task, ServerRequestInterface $request): AbstractTask
716-
{
717-
$parsedBody = $request->getParsedBody()['tx_scheduler'];
718-
if ((int)$parsedBody['runningType'] === AbstractTask::TYPE_SINGLE) {
719-
$execution = Execution::createSingleExecution($this->getTimestampFromDateString($parsedBody['start']));
720-
} else {
721-
$execution = Execution::createRecurringExecution(
722-
$this->getTimestampFromDateString($parsedBody['start']),
723-
is_numeric($parsedBody['frequency']) ? (int)$parsedBody['frequency'] : 0,
724-
!empty($parsedBody['end'] ?? '') ? $this->getTimestampFromDateString($parsedBody['end']) : 0,
725-
(bool)($parsedBody['multiple'] ?? false),
726-
!is_numeric($parsedBody['frequency']) ? $parsedBody['frequency'] : '',
727-
);
728-
}
729-
$task->setExecution($execution);
730-
$task->setDisabled($parsedBody['disable'] ?? false);
731-
$task->setDescription($parsedBody['description'] ?? '');
732-
$task->setTaskGroup((int)($parsedBody['task_group'] ?? 0));
733-
$provider = $this->taskService->getAdditionalFieldProviderForTask($task->getTaskType());
734-
$provider?->saveAdditionalFields($parsedBody, $task);
735-
return $task;
736-
}
737-
738686
/**
739687
* Convert input to DateTime and retrieve timestamp.
740688
*
@@ -781,31 +729,6 @@ protected function getRegisteredTaskGroups(): array
781729
->fetchAllAssociative();
782730
}
783731

784-
/**
785-
* Prepared additional fields from field providers for rendering.
786-
*/
787-
protected function preparedAdditionalFields(array $additionalFields, string $taskType): array
788-
{
789-
$result = [];
790-
foreach ($additionalFields as $fieldID => $fieldInfo) {
791-
$result[] = [
792-
'taskType' => $taskType,
793-
'fieldID' => $fieldID,
794-
'htmlClassName' => strtolower(str_replace('\\', '-', $taskType)),
795-
'code' => $fieldInfo['code'] ?? '',
796-
'cshKey' => $fieldInfo['cshKey'] ?? '',
797-
'cshLabel' => $fieldInfo['cshLabel'] ?? '',
798-
'langLabel' => $this->getLanguageService()->sL($fieldInfo['label'] ?? ''),
799-
'browser' => $fieldInfo['browser'] ?? '',
800-
'pageTitle' => $fieldInfo['pageTitle'] ?? '',
801-
'pageUid' => $fieldInfo['pageUid'] ?? '',
802-
'renderType' => $fieldInfo['type'] ?? '',
803-
'description' => $fieldInfo['description'] ?? '',
804-
];
805-
}
806-
return $result;
807-
}
808-
809732
protected function addDocHeaderReloadButton(ModuleTemplate $moduleTemplate): void
810733
{
811734
$languageService = $this->getLanguageService();
@@ -902,15 +825,6 @@ protected function addDocHeaderShortcutButton(ModuleTemplate $moduleTemplate, st
902825
$buttonBar->addButton($shortcutButton);
903826
}
904827

905-
protected function getHumanReadableTaskName(AbstractTask $task): string
906-
{
907-
$taskInformation = $this->taskService->getAllTaskTypes()[$task->getTaskType()];
908-
if (!isset($taskInformation)) {
909-
throw new \RuntimeException('Task Type ' . $task->getTaskType() . ' not found in list of registered tasks', 1641658569);
910-
}
911-
return $taskInformation['fullTitle'];
912-
}
913-
914828
/**
915829
* Add a flash message to the flash message queue of this module.
916830
*/
@@ -958,9 +872,4 @@ protected function getLanguageService(): LanguageService
958872
{
959873
return $GLOBALS['LANG'];
960874
}
961-
962-
protected function getBackendUser(): BackendUserAuthentication
963-
{
964-
return $GLOBALS['BE_USER'];
965-
}
966875
}

0 commit comments

Comments
 (0)