‪TYPO3CMS  9.5
SchedulerModuleController.php
Go to the documentation of this file.
1 <?php
2 declare(strict_types = 1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
18 use Psr\Http\Message\ResponseInterface;
19 use Psr\Http\Message\ServerRequestInterface;
47 
53 {
56 
60  private ‪$deprecatedPublicMethods = [
61  'addMessage' => 'Using SchedulerModuleController::addMessage() is deprecated and will not be possible anymore in TYPO3 v10.0.',
62  ];
63 
68  'CMD' => 'Using SchedulerModuleController::$CMD is deprecated and will not be possible anymore in TYPO3 v10.0. Use SchedulerModuleController::getCurrentAction() instead.',
69  ];
70 
76  protected ‪$submittedData = [];
77 
84  protected ‪$messages = [];
85 
89  protected ‪$cshKey = '_MOD_system_txschedulerM1';
90 
94  protected ‪$scheduler;
95 
99  protected ‪$backendTemplatePath = '';
100 
104  protected ‪$view;
105 
109  protected ‪$moduleUri;
110 
116  protected ‪$moduleTemplate;
117 
121  protected ‪$iconFactory;
122 
128  protected ‪$CMD;
129 
133  protected ‪$action;
134 
140  protected ‪$MOD_MENU = [
141  'function' => []
142  ];
143 
150  protected ‪$MOD_SETTINGS = [];
151 
155  public function ‪__construct()
156  {
157  $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
158  $this->‪getLanguageService()->‪includeLLFile('EXT:scheduler/Resources/Private/Language/locallang.xlf');
159  $this->backendTemplatePath = ‪ExtensionManagementUtility::extPath('scheduler') . 'Resources/Private/Templates/Backend/SchedulerModule/';
160  $this->view = GeneralUtility::makeInstance(StandaloneView::class);
161  $this->view->getRequest()->setControllerExtensionName('scheduler');
162  $this->view->setPartialRootPaths([‪ExtensionManagementUtility::extPath('scheduler') . 'Resources/Private/Partials/Backend/SchedulerModule/']);
163  $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
164  $this->moduleUri = (string)$uriBuilder->buildUriFromRoute('system_txschedulerM1');
165  $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
166  $this->scheduler = GeneralUtility::makeInstance(Scheduler::class);
167 
168  $this->‪getPageRenderer()->‪loadRequireJsModule('TYPO3/CMS/Backend/Modal');
169  $this->‪getPageRenderer()->‪loadRequireJsModule('TYPO3/CMS/Backend/SplitButtons');
170  }
171 
178  public function ‪mainAction(ServerRequestInterface $request): ResponseInterface
179  {
180  $parsedBody = $request->getParsedBody();
181  $queryParams = $request->getQueryParams();
182 
183  $this->‪setCurrentAction(‪Action::cast($parsedBody['CMD'] ?? $queryParams['CMD'] ?? null));
184  $this->MOD_MENU = [
185  'function' => [
186  'scheduler' => $this->‪getLanguageService()->‪getLL('function.scheduler'),
187  'check' => $this->‪getLanguageService()->‪getLL('function.check'),
188  'info' => $this->‪getLanguageService()->‪getLL('function.info')
189  ]
190  ];
191  $settings = $parsedBody['SET'] ?? $queryParams['SET'] ?? null;
192  $this->MOD_SETTINGS = ‪BackendUtility::getModuleData($this->MOD_MENU, $settings, 'system_txschedulerM1', '', '', '');
193 
194  // Set the form
195  $content = '<form name="tx_scheduler_form" id="tx_scheduler_form" method="post" action="">';
196 
197  // Prepare main content
198  $content .= '<h1>' . $this->‪getLanguageService()->‪getLL('function.' . $this->MOD_SETTINGS['function']) . '</h1>';
199  $previousCMD = ‪Action::cast($parsedBody['previousCMD'] ?? $queryParams['previousCMD'] ?? null);
200  $content .= $this->‪getModuleContent($previousCMD);
201  $content .= '<div id="extraFieldsSection"></div></form><div id="extraFieldsHidden"></div>';
202 
203  $this->‪getButtons($request);
204  $this->‪getModuleMenu();
205 
206  $this->moduleTemplate->setContent($content);
207  return new ‪HtmlResponse($this->moduleTemplate->renderContent());
208  }
209 
215  public function ‪getCurrentAction(): ‪Action
216  {
217  return ‪$this->action;
218  }
219 
223  protected function ‪getModuleMenu(): void
224  {
225  $menu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
226  $menu->setIdentifier('SchedulerJumpMenu');
228  $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
229  foreach ($this->MOD_MENU['function'] as $controller => $title) {
230  $item = $menu
231  ->makeMenuItem()
232  ->setHref(
233  (string)$uriBuilder->buildUriFromRoute(
234  'system_txschedulerM1',
235  [
236  'id' => 0,
237  'SET' => [
238  'function' => $controller
239  ]
240  ]
241  )
242  )
243  ->setTitle($title);
244  if ($controller === $this->MOD_SETTINGS['function']) {
245  $item->setActive(true);
246  }
247  $menu->addMenuItem($item);
248  }
249  $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
250  }
251 
258  protected function ‪getModuleContent(Action $previousAction): string
259  {
260  $content = '';
261  $sectionTitle = '';
262  // Get submitted data
263  $this->submittedData = GeneralUtility::_GPmerged('tx_scheduler');
264  $this->submittedData['uid'] = (int)$this->submittedData['uid'];
265  // If a save command was submitted, handle saving now
266  if (in_array((string)$this->‪getCurrentAction(), [‪Action::SAVE, ‪Action::SAVE_CLOSE, ‪Action::SAVE_NEW], true)) {
267  // First check the submitted data
268  $result = $this->‪preprocessData();
269 
270  // If result is ok, proceed with saving
271  if ($result) {
272  $this->‪saveTask();
273 
274  if ($this->action->equals(‪Action::SAVE_CLOSE)) {
275  // Display default screen
277  } elseif ($this->action->equals(‪Action::SAVE)) {
278  // After saving a "add form", return to edit
280  } elseif ($this->action->equals(‪Action::SAVE_NEW)) {
281  // Unset submitted data, so that empty form gets displayed
282  unset($this->submittedData);
283  // After saving a "add/edit form", return to add
285  } else {
286  // Return to edit form
287  $this->‪setCurrentAction($previousAction);
288  }
289  } else {
290  $this->‪setCurrentAction($previousAction);
291  }
292  }
293 
294  // Handle chosen action
295  switch ((string)$this->MOD_SETTINGS['function']) {
296  case 'scheduler':
297  $this->‪executeTasks();
298 
299  switch ((string)$this->‪getCurrentAction()) {
300  case ‪Action::ADD:
301  case ‪Action::EDIT:
302  try {
303  // Try adding or editing
304  $content .= $this->‪editTaskAction();
305  $sectionTitle = $this->‪getLanguageService()->‪getLL('action.' . $this->‪getCurrentAction());
306  } catch (\LogicException|\UnexpectedValueException|\OutOfBoundsException $e) {
307  // Catching all types of exceptions that were previously handled and
308  // converted to messages
309  $content .= $this->‪listTasksAction();
310  } catch (\Exception $e) {
311  // Catching all "unexpected" exceptions not previously handled
312  $this->‪addMessage($e->getMessage(), ‪FlashMessage::ERROR);
313  $content .= $this->‪listTasksAction();
314  }
315  break;
316  case ‪Action::DELETE:
317  $this->‪deleteTask();
318  $content .= $this->‪listTasksAction();
319  break;
320  case ‪Action::STOP:
321  $this->‪stopTask();
322  $content .= $this->‪listTasksAction();
323  break;
325  $this->‪toggleDisableAction();
326  $content .= $this->‪listTasksAction();
327  break;
330  $content .= $this->‪listTasksAction();
331  break;
332  case ‪Action::LIST:
333  $content .= $this->‪listTasksAction();
334  }
335  break;
336 
337  // Setup check screen
338  case 'check':
339  // @todo move check to the report module
340  $content .= $this->‪checkScreenAction();
341  break;
342 
343  // Information screen
344  case 'info':
345  $content .= $this->‪infoScreenAction();
346  break;
347  }
348  // Wrap the content
349  return '<h2>' . $sectionTitle . '</h2><div class="tx_scheduler_mod1">' . $content . '</div>';
350  }
351 
358  protected function ‪checkScreenAction(): string
359  {
360  $this->view->setTemplatePathAndFilename($this->backendTemplatePath . 'CheckScreen.html');
361 
362  // Display information about last automated run, as stored in the system registry
363  $registry = GeneralUtility::makeInstance(Registry::class);
364  $lastRun = $registry->get('tx_scheduler', 'lastRun');
365  if (!is_array($lastRun)) {
366  $message = $this->‪getLanguageService()->‪getLL('msg.noLastRun');
368  } else {
369  if (empty($lastRun['end']) || empty($lastRun['start']) || empty($lastRun['type'])) {
370  $message = $this->‪getLanguageService()->‪getLL('msg.incompleteLastRun');
372  } else {
373  $startDate = date(‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $lastRun['start']);
374  $startTime = date(‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], $lastRun['start']);
375  $endDate = date(‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $lastRun['end']);
376  $endTime = date(‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], $lastRun['end']);
377  $label = 'automatically';
378  if ($lastRun['type'] === 'manual') {
379  $label = 'manually';
380  }
381  $type = $this->‪getLanguageService()->‪getLL('label.' . $label);
382  $message = sprintf($this->‪getLanguageService()->getLL('msg.lastRun'), $type, $startDate, $startTime, $endDate, $endTime);
384  }
385  }
386  $this->view->assign('lastRunMessage', $message);
387  $this->view->assign('lastRunSeverity', $severity);
388 
390  $this->view->assign('composerMode', true);
391  } else {
392  // Check if CLI script is executable or not
393  $script = GeneralUtility::getFileAbsFileName('EXT:core/bin/typo3');
394  $this->view->assign('script', $script);
395  // Skip this check if running Windows, as rights do not work the same way on this platform
396  // (i.e. the script will always appear as *not* executable)
398  $isExecutable = true;
399  } else {
400  $isExecutable = is_executable($script);
401  }
402  if ($isExecutable) {
403  $message = $this->‪getLanguageService()->‪getLL('msg.cliScriptExecutable');
404  $severity = ‪InfoboxViewHelper::STATE_OK;
405  } else {
406  $message = $this->‪getLanguageService()->‪getLL('msg.cliScriptNotExecutable');
408  }
409  $this->view->assign('isExecutableMessage', $message);
410  $this->view->assign('isExecutableSeverity', $severity);
411  }
412 
413  $this->view->assign('now', $this->‪getServerTime());
414 
415  return $this->view->render();
416  }
417 
423  protected function ‪infoScreenAction(): string
424  {
425  $registeredClasses = $this->‪getRegisteredClasses();
426  // No classes available, display information message
427  if (empty($registeredClasses)) {
428  $this->view->setTemplatePathAndFilename($this->backendTemplatePath . 'InfoScreenNoClasses.html');
429  return $this->view->render();
430  }
431 
432  $this->view->setTemplatePathAndFilename($this->backendTemplatePath . 'InfoScreen.html');
433  $this->view->assign('registeredClasses', $registeredClasses);
434 
435  return $this->view->render();
436  }
437 
441  protected function ‪deleteTask(): void
442  {
443  try {
444  // Try to fetch the task and delete it
445  $task = $this->scheduler->fetchTask($this->submittedData['uid']);
446  // If the task is currently running, it may not be deleted
447  if ($task->isExecutionRunning()) {
448  $this->‪addMessage($this->‪getLanguageService()->getLL('msg.maynotDeleteRunningTask'), ‪FlashMessage::ERROR);
449  } else {
450  if ($this->scheduler->removeTask($task)) {
451  $this->‪getBackendUser()->‪writelog(4, 0, 0, 0, 'Scheduler task "%s" (UID: %s, Class: "%s") was deleted', [$task->getTaskTitle(), $task->getTaskUid(), $task->getTaskClassName()]);
452  $this->‪addMessage($this->‪getLanguageService()->getLL('msg.deleteSuccess'));
453  } else {
454  $this->‪addMessage($this->‪getLanguageService()->getLL('msg.deleteError'), ‪FlashMessage::ERROR);
455  }
456  }
457  } catch (\UnexpectedValueException $e) {
458  // The task could not be unserialized properly, simply update the database record
459  $taskUid = (int)$this->submittedData['uid'];
460  $result = GeneralUtility::makeInstance(ConnectionPool::class)
461  ->getConnectionForTable('tx_scheduler_task')
462  ->update('tx_scheduler_task', ['deleted' => 1], ['uid' => $taskUid]);
463  if ($result) {
464  $this->‪addMessage($this->‪getLanguageService()->getLL('msg.deleteSuccess'));
465  } else {
466  $this->‪addMessage($this->‪getLanguageService()->getLL('msg.deleteError'), ‪FlashMessage::ERROR);
467  }
468  } catch (\OutOfBoundsException $e) {
469  // The task was not found, for some reason
470  $this->‪addMessage(sprintf($this->‪getLanguageService()->getLL('msg.taskNotFound'), $this->submittedData['uid']), ‪FlashMessage::ERROR);
471  }
472  }
473 
480  protected function ‪stopTask(): void
481  {
482  try {
483  // Try to fetch the task and stop it
484  $task = $this->scheduler->fetchTask($this->submittedData['uid']);
485  if ($task->isExecutionRunning()) {
486  // If the task is indeed currently running, clear marked executions
487  $result = $task->unmarkAllExecutions();
488  if ($result) {
489  $this->‪addMessage($this->‪getLanguageService()->getLL('msg.stopSuccess'));
490  } else {
491  $this->‪addMessage($this->‪getLanguageService()->getLL('msg.stopError'), ‪FlashMessage::ERROR);
492  }
493  } else {
494  // The task is not running, nothing to unmark
495  $this->‪addMessage($this->‪getLanguageService()->getLL('msg.maynotStopNonRunningTask'), ‪FlashMessage::WARNING);
496  }
497  } catch (\Exception $e) {
498  // The task was not found, for some reason
499  $this->‪addMessage(sprintf($this->‪getLanguageService()->getLL('msg.taskNotFound'), $this->submittedData['uid']), ‪FlashMessage::ERROR);
500  }
501  }
502 
506  protected function ‪toggleDisableAction(): void
507  {
508  $task = $this->scheduler->fetchTask($this->submittedData['uid']);
509  $task->setDisabled(!$task->isDisabled());
510  // If a disabled single task is enabled again, we register it for a
511  // single execution at next scheduler run.
512  if ($task->getType() === ‪AbstractTask::TYPE_SINGLE) {
513  $task->registerSingleExecution(time());
514  }
515  $task->save();
516  }
517 
521  protected function ‪setNextExecutionTimeAction(): void
522  {
523  $task = $this->scheduler->fetchTask($this->submittedData['uid']);
524  $task->setRunOnNextCronJob(true);
525  $task->save();
526  }
527 
533  protected function ‪editTaskAction(): string
534  {
535  $this->view->setTemplatePathAndFilename($this->backendTemplatePath . 'EditTask.html');
536 
537  $registeredClasses = $this->‪getRegisteredClasses();
538  $registeredTaskGroups = $this->‪getRegisteredTaskGroups();
539 
540  $taskInfo = [];
541  $task = null;
542  $process = 'edit';
543 
544  if ($this->submittedData['uid'] > 0) {
545  // If editing, retrieve data for existing task
546  try {
547  $taskRecord = $this->scheduler->fetchTaskRecord($this->submittedData['uid']);
548  // If there's a registered execution, the task should not be edited
549  if (!empty($taskRecord['serialized_executions'])) {
550  $this->‪addMessage($this->‪getLanguageService()->getLL('msg.maynotEditRunningTask'), ‪FlashMessage::ERROR);
551  throw new \LogicException('Runnings tasks cannot not be edited', 1251232849);
552  }
553 
554  // Get the task object
556  $task = unserialize($taskRecord['serialized_task_object']);
557 
558  // Set some task information
559  $taskInfo['disable'] = $taskRecord['disable'];
560  $taskInfo['description'] = $taskRecord['description'];
561  $taskInfo['task_group'] = $taskRecord['task_group'];
562 
563  // Check that the task object is valid
564  if (isset($registeredClasses[get_class($task)]) && $this->scheduler->isValidTaskObject($task)) {
565  // The task object is valid, process with fetching current data
566  $taskInfo['class'] = get_class($task);
567  // Get execution information
568  $taskInfo['start'] = (int)$task->getExecution()->getStart();
569  $taskInfo['end'] = (int)$task->getExecution()->getEnd();
570  $taskInfo['interval'] = $task->getExecution()->getInterval();
571  $taskInfo['croncmd'] = $task->getExecution()->getCronCmd();
572  $taskInfo['multiple'] = $task->getExecution()->getMultiple();
573  if (!empty($taskInfo['interval']) || !empty($taskInfo['croncmd'])) {
574  // Guess task type from the existing information
575  // If an interval or a cron command is defined, it's a recurring task
576  $taskInfo['type'] = ‪AbstractTask::TYPE_RECURRING;
577  $taskInfo['frequency'] = $taskInfo['interval'] ?: $taskInfo['croncmd'];
578  } else {
579  // It's not a recurring task
580  // Make sure interval and cron command are both empty
581  $taskInfo['type'] = ‪AbstractTask::TYPE_SINGLE;
582  $taskInfo['frequency'] = '';
583  $taskInfo['end'] = 0;
584  }
585  } else {
586  // The task object is not valid
587  // Issue error message
588  $this->‪addMessage(sprintf($this->‪getLanguageService()->getLL('msg.invalidTaskClassEdit'), get_class($task)), ‪FlashMessage::ERROR);
589  // Initialize empty values
590  $taskInfo['start'] = 0;
591  $taskInfo['end'] = 0;
592  $taskInfo['frequency'] = '';
593  $taskInfo['multiple'] = false;
594  $taskInfo['type'] = ‪AbstractTask::TYPE_SINGLE;
595  }
596  } catch (\OutOfBoundsException $e) {
597  // Add a message and continue throwing the exception
598  $this->‪addMessage(sprintf($this->‪getLanguageService()->getLL('msg.taskNotFound'), $this->submittedData['uid']), ‪FlashMessage::ERROR);
599  throw $e;
600  }
601  } else {
602  // If adding a new object, set some default values
603  $taskInfo['class'] = key($registeredClasses);
604  $taskInfo['type'] = ‪AbstractTask::TYPE_RECURRING;
605  $taskInfo['start'] = ‪$GLOBALS['EXEC_TIME'];
606  $taskInfo['end'] = '';
607  $taskInfo['frequency'] = '';
608  $taskInfo['multiple'] = 0;
609  $process = 'add';
610  }
611 
612  // If some data was already submitted, use it to override
613  // existing data
614  if (!empty($this->submittedData)) {
615  ‪ArrayUtility::mergeRecursiveWithOverrule($taskInfo, $this->submittedData);
616  }
617 
618  // Get the extra fields to display for each task that needs some
619  $allAdditionalFields = [];
620  if ($process === 'add') {
621  foreach ($registeredClasses as $class => $registrationInfo) {
622  if (!empty($registrationInfo['provider'])) {
624  $providerObject = GeneralUtility::makeInstance($registrationInfo['provider']);
625  if ($providerObject instanceof AdditionalFieldProviderInterface) {
626  $additionalFields = $providerObject->getAdditionalFields($taskInfo, null, $this);
627  $allAdditionalFields = array_merge($allAdditionalFields, [$class => $additionalFields]);
628  }
629  }
630  }
631  } elseif ($task !== null && !empty($registeredClasses[$taskInfo['class']]['provider'])) {
632  // only try to fetch additionalFields if the task is valid
633  $providerObject = GeneralUtility::makeInstance($registeredClasses[$taskInfo['class']]['provider']);
634  if ($providerObject instanceof AdditionalFieldProviderInterface) {
635  $allAdditionalFields[$taskInfo['class']] = $providerObject->getAdditionalFields($taskInfo, $task, $this);
636  }
637  }
638 
639  // Load necessary JavaScript
640  $this->‪getPageRenderer()->‪loadRequireJsModule('TYPO3/CMS/Scheduler/Scheduler');
641  $this->‪getPageRenderer()->‪loadRequireJsModule('TYPO3/CMS/Backend/DateTimePicker');
642  $this->‪getPageRenderer()->‪loadRequireJsModule('TYPO3/CMS/Scheduler/PageBrowser');
643  $this->‪getPageRenderer()->‪addJsInlineCode('browse-button', '
644  function setFormValueFromBrowseWin(fieldReference, elValue, elName) {
645  var res = elValue.split("_");
646  var element = document.getElementById(fieldReference);
647  element.value = res[1];
648  }
649  ');
650 
651  // Start rendering the add/edit form
652  $this->view->assign('uid', htmlspecialchars((string)$this->submittedData['uid']));
653  $this->view->assign('cmd', htmlspecialchars((string)$this->‪getCurrentAction()));
654  $this->view->assign('csh', $this->cshKey);
655  $this->view->assign('lang', 'LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:');
656 
657  $table = [];
658 
659  // Disable checkbox
660  $this->view->assign('task_disable', ($taskInfo['disable'] ? ' checked="checked"' : ''));
661  $this->view->assign('task_disable_label', 'LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:disable');
662 
663  // Task class selector
664  // On editing, don't allow changing of the task class, unless it was not valid
665  if ($this->submittedData['uid'] > 0 && !empty($taskInfo['class'])) {
666  $this->view->assign('task_class', $taskInfo['class']);
667  $this->view->assign('task_class_title', $registeredClasses[$taskInfo['class']]['title']);
668  $this->view->assign('task_class_extension', $registeredClasses[$taskInfo['class']]['extension']);
669  } else {
670  // Group registered classes by classname
671  $groupedClasses = [];
672  foreach ($registeredClasses as $class => $classInfo) {
673  $groupedClasses[$classInfo['extension']][$class] = $classInfo;
674  }
675  ksort($groupedClasses);
676  foreach ($groupedClasses as $extension => $class) {
677  foreach ($groupedClasses[$extension] as $class => $classInfo) {
678  $selected = $class == $taskInfo['class'] ? ' selected="selected"' : '';
679  $groupedClasses[$extension][$class]['selected'] = $selected;
680  }
681  }
682  $this->view->assign('groupedClasses', $groupedClasses);
683  }
684 
685  // Task type selector
686  $this->view->assign('task_type_selected_1', ((int)$taskInfo['type'] === ‪AbstractTask::TYPE_SINGLE ? ' selected="selected"' : ''));
687  $this->view->assign('task_type_selected_2', ((int)$taskInfo['type'] === ‪AbstractTask::TYPE_RECURRING ? ' selected="selected"' : ''));
688 
689  // Task group selector
690  foreach ($registeredTaskGroups as $key => $taskGroup) {
691  $selected = $taskGroup['uid'] == $taskInfo['task_group'] ? ' selected="selected"' : '';
692  $registeredTaskGroups[$key]['selected'] = $selected;
693  }
694  $this->view->assign('registeredTaskGroups', $registeredTaskGroups);
695 
696  // Start date/time field
697  $dateFormat = ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ? '%H:%M %m-%d-%Y' : '%H:%M %d-%m-%Y';
698  $this->view->assign('start_value_hr', ($taskInfo['start'] > 0 ? strftime($dateFormat, $taskInfo['start']) : ''));
699  $this->view->assign('start_value', $taskInfo['start']);
700 
701  // End date/time field
702  // NOTE: datetime fields need a special id naming scheme
703  $this->view->assign('end_value_hr', ($taskInfo['end'] > 0 ? strftime($dateFormat, $taskInfo['end']) : ''));
704  $this->view->assign('end_value', $taskInfo['end']);
705 
706  // Frequency input field
707  $this->view->assign('frequency', $taskInfo['frequency']);
708 
709  // Multiple execution selector
710  $this->view->assign('multiple', ($taskInfo['multiple'] ? 'checked="checked"' : ''));
711 
712  // Description
713  $this->view->assign('description', $taskInfo['description']);
714 
715  // Display additional fields
716  $additionalFieldList = [];
717  foreach ($allAdditionalFields as $class => ‪$fields) {
718  if ($class == $taskInfo['class']) {
719  $additionalFieldsStyle = '';
720  } else {
721  $additionalFieldsStyle = ' style="display: none"';
722  }
723  // Add each field to the display, if there are indeed any
724  if (isset(‪$fields) && is_array(‪$fields)) {
725  foreach (‪$fields as $fieldID => $fieldInfo) {
726  $htmlClassName = strtolower(str_replace('\\', '-', $class));
727  $field = [];
728  $field['htmlClassName'] = $htmlClassName;
729  $field['code'] = $fieldInfo['code'];
730  $field['cshKey'] = $fieldInfo['cshKey'];
731  $field['cshLabel'] = $fieldInfo['cshLabel'];
732  $field['langLabel'] = $fieldInfo['label'];
733  $field['fieldID'] = $fieldID;
734  $field['additionalFieldsStyle'] = $additionalFieldsStyle;
735  $field['browseButton'] = $this->‪getBrowseButton($fieldID, $fieldInfo);
736  $additionalFieldList[] = $field;
737  }
738  }
739  }
740  $this->view->assign('additionalFields', $additionalFieldList);
741 
742  $this->view->assign('returnUrl', (string)GeneralUtility::getIndpEnv('REQUEST_URI'));
743  $this->view->assign('table', implode(LF, $table));
744  $this->view->assign('now', $this->‪getServerTime());
745  $this->view->assign('frequencyOptions', (array)‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['frequencyOptions']);
746 
747  return $this->view->render();
748  }
749 
755  protected function ‪getBrowseButton($fieldID, array $fieldInfo): string
756  {
757  if (isset($fieldInfo['browser']) && ($fieldInfo['browser'] === 'page')) {
758  $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
759  $url = (string)$uriBuilder->buildUriFromRoute(
760  'wizard_element_browser',
761  ['mode' => 'db', 'bparams' => $fieldID . '|||pages|']
762  );
763  $title = htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.browse_db'));
764  return '
765  <div><a href="#" data-url=' . htmlspecialchars($url) . ' class="btn btn-default t3js-pageBrowser" title="' . $title . '">
766  <span class="t3js-icon icon icon-size-small icon-state-default icon-actions-insert-record" data-identifier="actions-insert-record">
767  <span class="icon-markup">' . $this->iconFactory->getIcon(
768  'actions-insert-record',
770  )->render() . '</span>
771  </span>
772  </a><span id="page_' . $fieldID . '">&nbsp;' . htmlspecialchars($fieldInfo['pageTitle']) . '</span></div>';
773  }
774  return '';
775  }
776 
780  protected function ‪executeTasks(): void
781  {
782  // Continue if some elements have been chosen for execution
783  if (isset($this->submittedData['execute']) && !empty($this->submittedData['execute'])) {
784  // Get list of registered classes
785  $registeredClasses = $this->‪getRegisteredClasses();
786  // Loop on all selected tasks
787  foreach ($this->submittedData['execute'] as $uid) {
788  try {
789  // Try fetching the task
790  $task = $this->scheduler->fetchTask($uid);
791  $class = get_class($task);
792  $name = $registeredClasses[$class]['title'] . ' (' . $registeredClasses[$class]['extension'] . ')';
793  if (GeneralUtility::_POST('go_cron') !== null) {
794  $task->setRunOnNextCronJob(true);
795  $task->save();
796  } else {
797  // Now try to execute it and report on outcome
798  try {
799  $result = $this->scheduler->executeTask($task);
800  if ($result) {
801  $this->‪addMessage(sprintf($this->‪getLanguageService()->getLL('msg.executed'), $name));
802  } else {
803  $this->‪addMessage(sprintf($this->‪getLanguageService()->getLL('msg.notExecuted'), $name), ‪FlashMessage::ERROR);
804  }
805  } catch (\Exception $e) {
806  // An exception was thrown, display its message as an error
807  $this->‪addMessage(sprintf($this->‪getLanguageService()->getLL('msg.executionFailed'), $name, $e->getMessage()), ‪FlashMessage::ERROR);
808  }
809  }
810  } catch (\OutOfBoundsException $e) {
811  $this->‪addMessage(sprintf($this->‪getLanguageService()->getLL('msg.taskNotFound'), $uid), ‪FlashMessage::ERROR);
812  } catch (\UnexpectedValueException $e) {
813  $this->‪addMessage(sprintf($this->‪getLanguageService()->getLL('msg.executionFailed'), $uid, $e->getMessage()), ‪FlashMessage::ERROR);
814  }
815  }
816  // Record the run in the system registry
817  $this->scheduler->recordLastRun('manual');
818  // Make sure to switch to list view after execution
820  }
821  }
822 
828  protected function ‪listTasksAction(): string
829  {
830  $this->view->setTemplatePathAndFilename($this->backendTemplatePath . 'ListTasks.html');
831 
832  // Define display format for dates
833  $dateFormat = ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] . ' ' . ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'];
834 
835  // Get list of registered task groups
836  $registeredTaskGroups = $this->‪getRegisteredTaskGroups();
837 
838  // add an empty entry for non-grouped tasks
839  // add in front of list
840  array_unshift($registeredTaskGroups, ['uid' => 0, 'groupName' => '']);
841 
842  // Get all registered tasks
843  // Just to get the number of entries
844  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
845  ->getQueryBuilderForTable('tx_scheduler_task');
846  $queryBuilder->getRestrictions()->removeAll();
847 
848  $result = $queryBuilder->select('t.*')
849  ->addSelect(
850  'g.groupName AS taskGroupName',
851  'g.description AS taskGroupDescription',
852  'g.deleted AS isTaskGroupDeleted'
853  )
854  ->from('tx_scheduler_task', 't')
855  ->leftJoin(
856  't',
857  'tx_scheduler_task_group',
858  'g',
859  $queryBuilder->expr()->eq('t.task_group', $queryBuilder->quoteIdentifier('g.uid'))
860  )
861  ->where(
862  $queryBuilder->expr()->eq('t.deleted', 0)
863  )
864  ->orderBy('g.sorting')
865  ->execute();
866 
867  // Loop on all tasks
868  $temporaryResult = [];
869  while ($row = $result->fetch()) {
870  if ($row['taskGroupName'] === null || $row['isTaskGroupDeleted'] === '1') {
871  $row['taskGroupName'] = '';
872  $row['taskGroupDescription'] = '';
873  $row['task_group'] = 0;
874  }
875  $temporaryResult[$row['task_group']]['groupName'] = $row['taskGroupName'];
876  $temporaryResult[$row['task_group']]['groupDescription'] = $row['taskGroupDescription'];
877  $temporaryResult[$row['task_group']]['tasks'][] = $row;
878  }
879 
880  // No tasks defined, display information message
881  if (empty($temporaryResult)) {
882  $this->view->setTemplatePathAndFilename($this->backendTemplatePath . 'ListTasksNoTasks.html');
883  return $this->view->render();
884  }
885 
886  $this->‪getPageRenderer()->‪loadRequireJsModule('TYPO3/CMS/Scheduler/Scheduler');
887  $this->‪getPageRenderer()->‪loadRequireJsModule('TYPO3/CMS/Backend/Tooltip');
888 
889  $tasks = $temporaryResult;
890 
891  $registeredClasses = $this->‪getRegisteredClasses();
892  $missingClasses = [];
893  foreach ($temporaryResult as $taskIndex => $taskGroup) {
894  foreach ($taskGroup['tasks'] as $recordIndex => $schedulerRecord) {
895  if ((int)$schedulerRecord['disable'] === 1) {
896  $translationKey = 'enable';
897  } else {
898  $translationKey = 'disable';
899  }
900  $tasks[$taskIndex]['tasks'][$recordIndex]['translationKey'] = $translationKey;
901 
902  // Define some default values
903  $lastExecution = '-';
904  $isRunning = false;
905  $showAsDisabled = false;
906  // Restore the serialized task and pass it a reference to the scheduler object
908  $task = unserialize($schedulerRecord['serialized_task_object']);
909  $class = get_class($task);
910  if ($class === '__PHP_Incomplete_Class' && preg_match('/^O:[0-9]+:"(?P<classname>.+?)"/', $schedulerRecord['serialized_task_object'], $matches) === 1) {
911  $class = $matches['classname'];
912  }
913  $tasks[$taskIndex]['tasks'][$recordIndex]['class'] = $class;
914  // Assemble information about last execution
915  if (!empty($schedulerRecord['lastexecution_time'])) {
916  $lastExecution = date($dateFormat, (int)$schedulerRecord['lastexecution_time']);
917  if ($schedulerRecord['lastexecution_context'] === 'CLI') {
918  $context = $this->‪getLanguageService()->‪getLL('label.cron');
919  } else {
920  $context = $this->‪getLanguageService()->‪getLL('label.manual');
921  }
922  $lastExecution .= ' (' . $context . ')';
923  }
924  $tasks[$taskIndex]['tasks'][$recordIndex]['lastExecution'] = $lastExecution;
925 
926  if (isset($registeredClasses[get_class($task)]) && $this->scheduler->isValidTaskObject($task)) {
927  $tasks[$taskIndex]['tasks'][$recordIndex]['validClass'] = true;
928  // The task object is valid
929  $labels = [];
930  $additionalInformation = $task->getAdditionalInformation();
931  if ($task instanceof ProgressProviderInterface) {
932  $progress = round((float)$task->getProgress(), 2);
933  $tasks[$taskIndex]['tasks'][$recordIndex]['progress'] = $progress;
934  }
935  $tasks[$taskIndex]['tasks'][$recordIndex]['classTitle'] = $registeredClasses[$class]['title'];
936  $tasks[$taskIndex]['tasks'][$recordIndex]['classExtension'] = $registeredClasses[$class]['extension'];
937  $tasks[$taskIndex]['tasks'][$recordIndex]['additionalInformation'] = $additionalInformation;
938  // Check if task currently has a running execution
939  if (!empty($schedulerRecord['serialized_executions'])) {
940  $labels[] = [
941  'class' => 'success',
942  'text' => $this->‪getLanguageService()->‪getLL('status.running')
943  ];
944  $isRunning = true;
945  }
946  $tasks[$taskIndex]['tasks'][$recordIndex]['isRunning'] = $isRunning;
947 
948  // Prepare display of next execution date
949  // If task is currently running, date is not displayed (as next hasn't been calculated yet)
950  // Also hide the date if task is disabled (the information doesn't make sense, as it will not run anyway)
951  if ($isRunning || $schedulerRecord['disable']) {
952  $nextDate = '-';
953  } else {
954  $nextDate = date($dateFormat, (int)$schedulerRecord['nextexecution']);
955  if (empty($schedulerRecord['nextexecution'])) {
956  $nextDate = $this->‪getLanguageService()->‪getLL('none');
957  } elseif ($schedulerRecord['nextexecution'] < ‪$GLOBALS['EXEC_TIME']) {
958  $labels[] = [
959  'class' => 'warning',
960  'text' => $this->‪getLanguageService()->‪getLL('status.late'),
961  'description' => $this->‪getLanguageService()->‪getLL('status.legend.scheduled')
962  ];
963  }
964  }
965  $tasks[$taskIndex]['tasks'][$recordIndex]['nextDate'] = $nextDate;
966  // Get execution type
967  if ($task->getType() === ‪AbstractTask::TYPE_SINGLE) {
968  $execType = $this->‪getLanguageService()->‪getLL('label.type.single');
969  $frequency = '-';
970  } else {
971  $execType = $this->‪getLanguageService()->‪getLL('label.type.recurring');
972  if ($task->getExecution()->getCronCmd() == '') {
973  $frequency = $task->getExecution()->getInterval();
974  } else {
975  $frequency = $task->getExecution()->getCronCmd();
976  }
977  }
978  // Check the disable status
979  // Row is shown dimmed if task is disabled, unless it is still running
980  if ($schedulerRecord['disable'] && !$isRunning) {
981  $labels[] = [
982  'class' => 'default',
983  'text' => $this->‪getLanguageService()->‪getLL('status.disabled')
984  ];
985  $showAsDisabled = true;
986  }
987  $tasks[$taskIndex]['tasks'][$recordIndex]['execType'] = $execType;
988  $tasks[$taskIndex]['tasks'][$recordIndex]['frequency'] = $frequency;
989  // Get multiple executions setting
990  if ($task->getExecution()->getMultiple()) {
991  $multiple = $this->‪getLanguageService()->‪sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:yes');
992  } else {
993  $multiple = $this->‪getLanguageService()->‪sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:no');
994  }
995  $tasks[$taskIndex]['tasks'][$recordIndex]['multiple'] = $multiple;
996 
997  // Check if the last run failed
998  if (!empty($schedulerRecord['lastexecution_failure'])) {
999  // Try to get the stored exception array
1001  $exceptionArray = @unserialize($schedulerRecord['lastexecution_failure']);
1002  // If the exception could not be unserialized, issue a default error message
1003  if (!is_array($exceptionArray) || empty($exceptionArray)) {
1004  $labelDescription = $this->‪getLanguageService()->‪getLL('msg.executionFailureDefault');
1005  } else {
1006  $labelDescription = sprintf($this->‪getLanguageService()->getLL('msg.executionFailureReport'), $exceptionArray['code'], $exceptionArray['message']);
1007  }
1008  $labels[] = [
1009  'class' => 'danger',
1010  'text' => $this->‪getLanguageService()->‪getLL('status.failure'),
1011  'description' => $labelDescription
1012  ];
1013  }
1014  $tasks[$taskIndex]['tasks'][$recordIndex]['labels'] = $labels;
1015  if ($showAsDisabled) {
1016  $tasks[$taskIndex]['tasks'][$recordIndex]['showAsDisabled'] = 'disabled';
1017  }
1018  } else {
1019  $missingClasses[] = $tasks[$taskIndex]['tasks'][$recordIndex];
1020  unset($tasks[$taskIndex]['tasks'][$recordIndex]);
1021  }
1022  }
1023  }
1024 
1025  $this->view->assign('tasks', $tasks);
1026  $this->view->assign('missingClasses', $missingClasses);
1027  $this->view->assign('moduleUri', $this->moduleUri);
1028  $this->view->assign('now', $this->‪getServerTime());
1029 
1030  return $this->view->render();
1031  }
1032 
1039  protected function ‪makeStatusLabel(array $labels): string
1040  {
1041  $htmlLabels = [];
1042  foreach ($labels as $label) {
1043  if (empty($label['text'])) {
1044  continue;
1045  }
1046  $htmlLabels[] = '<span class="label label-' . htmlspecialchars($label['class']) . ' pull-right" title="' . htmlspecialchars($label['description']) . '">' . htmlspecialchars($label['text']) . '</span>';
1047  }
1048 
1049  return implode('&nbsp;', $htmlLabels);
1050  }
1051 
1055  protected function ‪saveTask(): void
1056  {
1057  // If a task is being edited fetch old task data
1058  if (!empty($this->submittedData['uid'])) {
1059  try {
1060  $taskRecord = $this->scheduler->fetchTaskRecord($this->submittedData['uid']);
1062  $task = unserialize($taskRecord['serialized_task_object']);
1063  } catch (\OutOfBoundsException $e) {
1064  // If the task could not be fetched, issue an error message
1065  // and exit early
1066  $this->‪addMessage(sprintf($this->‪getLanguageService()->getLL('msg.taskNotFound'), $this->submittedData['uid']), ‪FlashMessage::ERROR);
1067  return;
1068  }
1069  // Register single execution
1070  if ((int)$this->submittedData['type'] === ‪AbstractTask::TYPE_SINGLE) {
1071  $task->registerSingleExecution($this->submittedData['start']);
1072  } else {
1073  if (!empty($this->submittedData['croncmd'])) {
1074  // Definition by cron-like syntax
1075  $interval = 0;
1076  $cronCmd = $this->submittedData['croncmd'];
1077  } else {
1078  // Definition by interval
1079  $interval = $this->submittedData['interval'];
1080  $cronCmd = '';
1081  }
1082  // Register recurring execution
1083  $task->registerRecurringExecution($this->submittedData['start'], $interval, $this->submittedData['end'], $this->submittedData['multiple'], $cronCmd);
1084  }
1085  // Set disable flag
1086  $task->setDisabled($this->submittedData['disable']);
1087  // Set description
1088  $task->setDescription($this->submittedData['description']);
1089  // Set task group
1090  $task->setTaskGroup($this->submittedData['task_group']);
1091  // Save additional input values
1092  if (!empty(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields'])) {
1094  $providerObject = GeneralUtility::makeInstance(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields']);
1095  if ($providerObject instanceof AdditionalFieldProviderInterface) {
1096  $providerObject->saveAdditionalFields($this->submittedData, $task);
1097  }
1098  }
1099  // Save to database
1100  $result = $this->scheduler->saveTask($task);
1101  if ($result) {
1102  $this->‪getBackendUser()->‪writelog(4, 0, 0, 0, 'Scheduler task "%s" (UID: %s, Class: "%s") was updated', [$task->getTaskTitle(), $task->getTaskUid(), $task->getTaskClassName()]);
1103  $this->‪addMessage($this->‪getLanguageService()->getLL('msg.updateSuccess'));
1104  } else {
1105  $this->‪addMessage($this->‪getLanguageService()->getLL('msg.updateError'), ‪FlashMessage::ERROR);
1106  }
1107  } else {
1108  // A new task is being created
1109  // Create an instance of chosen class
1111  $task = GeneralUtility::makeInstance($this->submittedData['class']);
1112  if ((int)$this->submittedData['type'] === ‪AbstractTask::TYPE_SINGLE) {
1113  // Set up single execution
1114  $task->registerSingleExecution($this->submittedData['start']);
1115  } else {
1116  // Set up recurring execution
1117  $task->registerRecurringExecution($this->submittedData['start'], $this->submittedData['interval'], $this->submittedData['end'], $this->submittedData['multiple'], $this->submittedData['croncmd']);
1118  }
1119  // Save additional input values
1120  if (!empty(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields'])) {
1122  $providerObject = GeneralUtility::makeInstance(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields']);
1123  if ($providerObject instanceof AdditionalFieldProviderInterface) {
1124  $providerObject->saveAdditionalFields($this->submittedData, $task);
1125  }
1126  }
1127  // Set disable flag
1128  $task->setDisabled($this->submittedData['disable']);
1129  // Set description
1130  $task->setDescription($this->submittedData['description']);
1131  // Set description
1132  $task->setTaskGroup($this->submittedData['task_group']);
1133  // Add to database
1134  $result = $this->scheduler->addTask($task);
1135  if ($result) {
1136  $this->‪getBackendUser()->‪writelog(4, 0, 0, 0, 'Scheduler task "%s" (UID: %s, Class: "%s") was added', [$task->getTaskTitle(), $task->getTaskUid(), $task->getTaskClassName()]);
1137  $this->‪addMessage($this->‪getLanguageService()->getLL('msg.addSuccess'));
1138 
1139  // set the uid of the just created task so that we
1140  // can continue editing after initial saving
1141  $this->submittedData['uid'] = $task->getTaskUid();
1142  } else {
1143  $this->‪addMessage($this->‪getLanguageService()->getLL('msg.addError'), ‪FlashMessage::ERROR);
1144  }
1145  }
1146  }
1147 
1148  /*************************
1149  *
1150  * INPUT PROCESSING UTILITIES
1151  *
1152  *************************/
1158  protected function ‪preprocessData()
1159  {
1160  $result = true;
1161  // Validate id
1162  $this->submittedData['uid'] = empty($this->submittedData['uid']) ? 0 : (int)$this->submittedData['uid'];
1163  // Validate selected task class
1164  if (!class_exists($this->submittedData['class'])) {
1165  $this->‪addMessage($this->‪getLanguageService()->getLL('msg.noTaskClassFound'), ‪FlashMessage::ERROR);
1166  }
1167  // Check start date
1168  if (empty($this->submittedData['start'])) {
1169  $this->‪addMessage($this->‪getLanguageService()->getLL('msg.noStartDate'), ‪FlashMessage::ERROR);
1170  $result = false;
1171  } elseif (is_string($this->submittedData['start']) && (!is_numeric($this->submittedData['start']))) {
1172  try {
1173  $this->submittedData['start'] = $this->‪convertToTimestamp($this->submittedData['start']);
1174  } catch (\Exception $e) {
1175  $this->‪addMessage($this->‪getLanguageService()->getLL('msg.invalidStartDate'), ‪FlashMessage::ERROR);
1176  $result = false;
1177  }
1178  } else {
1179  $this->submittedData['start'] = (int)$this->submittedData['start'];
1180  }
1181  // Check end date, if recurring task
1182  if ((int)$this->submittedData['type'] === ‪AbstractTask::TYPE_RECURRING && !empty($this->submittedData['end'])) {
1183  if (is_string($this->submittedData['end']) && (!is_numeric($this->submittedData['end']))) {
1184  try {
1185  $this->submittedData['end'] = $this->‪convertToTimestamp($this->submittedData['end']);
1186  } catch (\Exception $e) {
1187  $this->‪addMessage($this->‪getLanguageService()->getLL('msg.invalidStartDate'), ‪FlashMessage::ERROR);
1188  $result = false;
1189  }
1190  } else {
1191  $this->submittedData['end'] = (int)$this->submittedData['end'];
1192  }
1193  if ($this->submittedData['end'] < $this->submittedData['start']) {
1194  $this->‪addMessage(
1195  $this->‪getLanguageService()->getLL('msg.endDateSmallerThanStartDate'),
1197  );
1198  $result = false;
1199  }
1200  }
1201  // Set default values for interval and cron command
1202  $this->submittedData['interval'] = 0;
1203  $this->submittedData['croncmd'] = '';
1204  // Check type and validity of frequency, if recurring
1205  if ((int)$this->submittedData['type'] === ‪AbstractTask::TYPE_RECURRING) {
1206  $frequency = trim($this->submittedData['frequency']);
1207  if (empty($frequency)) {
1208  // Empty frequency, not valid
1209  $this->‪addMessage($this->‪getLanguageService()->getLL('msg.noFrequency'), ‪FlashMessage::ERROR);
1210  $result = false;
1211  } else {
1212  $cronErrorCode = 0;
1213  $cronErrorMessage = '';
1214  // Try interpreting the cron command
1215  try {
1216  ‪NormalizeCommand::normalize($frequency);
1217  $this->submittedData['croncmd'] = $frequency;
1218  } catch (\Exception $e) {
1219  // Store the exception's result
1220  $cronErrorMessage = $e->getMessage();
1221  $cronErrorCode = $e->getCode();
1222  // Check if the frequency is a valid number
1223  // If yes, assume it is a frequency in seconds, and unset cron error code
1224  if (is_numeric($frequency)) {
1225  $this->submittedData['interval'] = (int)$frequency;
1226  unset($cronErrorCode);
1227  }
1228  }
1229  // If there's a cron error code, issue validation error message
1230  if (!empty($cronErrorCode)) {
1231  $this->‪addMessage(sprintf($this->‪getLanguageService()->getLL('msg.frequencyError'), $cronErrorMessage, $cronErrorCode), ‪FlashMessage::ERROR);
1232  $result = false;
1233  }
1234  }
1235  }
1236  // Validate additional input fields
1237  if (!empty(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields'])) {
1239  $providerObject = GeneralUtility::makeInstance(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields']);
1240  if ($providerObject instanceof AdditionalFieldProviderInterface) {
1241  // The validate method will return true if all went well, but that must not
1242  // override previous false values => AND the returned value with the existing one
1243  $result &= $providerObject->validateAdditionalFields($this->submittedData, $this);
1244  }
1245  }
1246  return $result;
1247  }
1248 
1255  protected function ‪convertToTimestamp(string $input): int
1256  {
1257  // Convert to ISO 8601 dates
1258  $dateTime = new \DateTime($input);
1259  $value = $dateTime->getTimestamp();
1260  if ($value !== 0) {
1261  $value -= date('Z', $value);
1262  }
1263  return $value;
1264  }
1265 
1272  protected function ‪addMessage($message, $severity = ‪FlashMessage::OK)
1273  {
1274  $this->moduleTemplate->addFlashMessage($message, '', $severity);
1275  }
1276 
1290  protected function ‪getRegisteredClasses(): array
1291  {
1292  $list = [];
1293  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'] ?? [] as $class => $registrationInformation) {
1294  $title = isset($registrationInformation['title']) ? $this->‪getLanguageService()->‪sL($registrationInformation['title']) : '';
1295  $description = isset($registrationInformation['description']) ? $this->‪getLanguageService()->‪sL($registrationInformation['description']) : '';
1296  $list[$class] = [
1297  'extension' => $registrationInformation['extension'],
1298  'title' => $title,
1299  'description' => $description,
1300  'provider' => $registrationInformation['additionalFields'] ?? ''
1301  ];
1302  }
1303  return $list;
1304  }
1305 
1311  protected function ‪getRegisteredTaskGroups(): array
1312  {
1313  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
1314  ->getQueryBuilderForTable('tx_scheduler_task_group');
1315 
1316  return $queryBuilder
1317  ->select('*')
1318  ->from('tx_scheduler_task_group')
1319  ->orderBy('sorting')
1320  ->execute()
1321  ->fetchAll();
1322  }
1323 
1329  protected function ‪getButtons(ServerRequestInterface $request): void
1330  {
1331  $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
1332  // CSH
1333  $helpButton = $buttonBar->makeHelpButton()
1334  ->setModuleName('_MOD_system_txschedulerM1')
1335  ->setFieldName('');
1336  $buttonBar->addButton($helpButton);
1337 
1338  // Add and Reload
1340  $reloadButton = $buttonBar->makeLinkButton()
1341  ->setTitle($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.reload'))
1342  ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-refresh', ‪Icon::SIZE_SMALL))
1343  ->setHref($this->moduleUri);
1344  $buttonBar->addButton($reloadButton, ‪ButtonBar::BUTTON_POSITION_RIGHT, 1);
1345  if ($this->MOD_SETTINGS['function'] === 'scheduler' && !empty($this->‪getRegisteredClasses())) {
1346  $addButton = $buttonBar->makeLinkButton()
1347  ->setTitle($this->‪getLanguageService()->getLL('action.add'))
1348  ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-add', ‪Icon::SIZE_SMALL))
1349  ->setHref($this->moduleUri . '&CMD=' . ‪Action::ADD);
1350  $buttonBar->addButton($addButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 2);
1351  }
1352  }
1353 
1354  // Close and Save
1355  if (in_array((string)$this->‪getCurrentAction(), [‪Action::ADD, ‪Action::EDIT], true)) {
1356  // Close
1357  $closeButton = $buttonBar->makeLinkButton()
1358  ->setTitle($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:cancel'))
1359  ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-close', ‪Icon::SIZE_SMALL))
1360  ->setOnClick('document.location=' . GeneralUtility::quoteJSvalue($this->moduleUri))
1361  ->setHref('#');
1362  $buttonBar->addButton($closeButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 2);
1363  // Save, SaveAndClose, SaveAndNew
1364  $saveButtonDropdown = $buttonBar->makeSplitButton();
1365  $saveButton = $buttonBar->makeInputButton()
1366  ->setName('CMD')
1367  ->setValue(‪Action::SAVE)
1368  ->setForm('tx_scheduler_form')
1369  ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-save', ‪Icon::SIZE_SMALL))
1370  ->setTitle($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:save'));
1371  $saveButtonDropdown->addItem($saveButton);
1372  $saveAndNewButton = $buttonBar->makeInputButton()
1373  ->setName('CMD')
1374  ->setValue(‪Action::SAVE_NEW)
1375  ->setForm('tx_scheduler_form')
1376  ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-save-new', ‪Icon::SIZE_SMALL))
1377  ->setTitle($this->‪getLanguageService()->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:label.saveAndCreateNewTask'));
1378  $saveButtonDropdown->addItem($saveAndNewButton);
1379  $saveAndCloseButton = $buttonBar->makeInputButton()
1380  ->setName('CMD')
1381  ->setValue(‪Action::SAVE_CLOSE)
1382  ->setForm('tx_scheduler_form')
1383  ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-save-close', ‪Icon::SIZE_SMALL))
1384  ->setTitle($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:saveAndClose'));
1385  $saveButtonDropdown->addItem($saveAndCloseButton);
1386  $buttonBar->addButton($saveButtonDropdown, ‪ButtonBar::BUTTON_POSITION_LEFT, 3);
1387  }
1388 
1389  // Delete
1390  if ($this->‪getCurrentAction()->equals(‪Action::EDIT)) {
1391  $deleteButton = $buttonBar->makeLinkButton()
1392  ->setHref($this->moduleUri . '&CMD=' . ‪Action::DELETE . '&tx_scheduler[uid]=' . $request->getQueryParams()['tx_scheduler']['uid'])
1393  ->setClasses('t3js-modal-trigger')
1394  ->setDataAttributes([
1395  'severity' => 'warning',
1396  'title' => $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:delete'),
1397  'button-close-text' => $this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:cancel'),
1398  'content' => $this->‪getLanguageService()->getLL('msg.delete'),
1399  ])
1400  ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-edit-delete', ‪Icon::SIZE_SMALL))
1401  ->setTitle($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:delete'));
1402  $buttonBar->addButton($deleteButton, ‪ButtonBar::BUTTON_POSITION_LEFT, 4);
1403  }
1404 
1405  // Shortcut
1406  $shortcutButton = $buttonBar->makeShortcutButton()
1407  ->setModuleName('system_txschedulerM1')
1408  ->setDisplayName($this->MOD_MENU['function'][$this->MOD_SETTINGS['function']])
1409  ->setSetVariables(['function']);
1410  $buttonBar->addButton($shortcutButton);
1411  }
1412 
1418  protected function ‪setCurrentAction(‪Action ‪$action): void
1419  {
1420  $this->action = ‪$action;
1421  // @deprecated since TYPO3 v9, will be removed with TYPO3 v10.0
1422  $this->CMD = (string)‪$action;
1423  }
1424 
1428  protected function ‪getServerTime(): string
1429  {
1430  $dateFormat = ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] . ' ' . ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'] . ' T (e';
1431  return date($dateFormat) . ', GMT ' . date('P') . ')';
1432  }
1433 
1438  protected function ‪getLanguageService(): ‪LanguageService
1439  {
1440  return ‪$GLOBALS['LANG'];
1441  }
1442 
1448  protected function ‪getBackendUser(): ‪BackendUserAuthentication
1449  {
1450  return ‪$GLOBALS['BE_USER'];
1451  }
1452 
1456  protected function ‪getPageRenderer(): PageRenderer
1457  {
1458  return GeneralUtility::makeInstance(PageRenderer::class);
1459  }
1460 }
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\$MOD_SETTINGS
‪array $MOD_SETTINGS
Definition: SchedulerModuleController.php:133
‪TYPO3\CMS\Scheduler\CronCommand\NormalizeCommand\normalize
‪static string normalize($cronCommand)
Definition: NormalizeCommand.php:39
‪TYPO3\CMS\Scheduler\Task\Enumeration\Action\SAVE
‪const SAVE
Definition: Action.php:30
‪TYPO3\CMS\Core\Imaging\Icon\SIZE_SMALL
‪const SIZE_SMALL
Definition: Icon.php:29
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\$scheduler
‪Scheduler $scheduler
Definition: SchedulerModuleController.php:86
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\$moduleUri
‪string $moduleUri
Definition: SchedulerModuleController.php:98
‪TYPO3\CMS\Core\Localization\LanguageService\includeLLFile
‪mixed includeLLFile($fileRef, $setGlobal=true, $mergeLocalOntoDefault=false)
Definition: LanguageService.php:260
‪TYPO3\CMS\Scheduler\Task\Enumeration\Action\ADD
‪const ADD
Definition: Action.php:26
‪TYPO3\CMS\Backend\Template\Components\ButtonBar\BUTTON_POSITION_LEFT
‪const BUTTON_POSITION_LEFT
Definition: ButtonBar.php:35
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\getBrowseButton
‪string getBrowseButton($fieldID, array $fieldInfo)
Definition: SchedulerModuleController.php:738
‪TYPO3\CMS\Backend\Template\Components\ButtonBar
Definition: ButtonBar.php:31
‪TYPO3\CMS\Core\Imaging\Icon
Definition: Icon.php:25
‪TYPO3\CMS\Scheduler\CronCommand\NormalizeCommand
Definition: NormalizeCommand.php:27
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\getModuleContent
‪string getModuleContent(Action $previousAction)
Definition: SchedulerModuleController.php:241
‪TYPO3\CMS\Fluid\ViewHelpers\Be\InfoboxViewHelper\STATE_INFO
‪const STATE_INFO
Definition: InfoboxViewHelper.php:61
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\$deprecatedPublicProperties
‪array $deprecatedPublicProperties
Definition: SchedulerModuleController.php:63
‪TYPO3\CMS\Scheduler\Controller
Definition: SchedulerModuleController.php:3
‪TYPO3\CMS\Core\Registry
Definition: Registry.php:32
‪TYPO3\CMS\Scheduler\Task\Enumeration\Action\LIST
‪const LIST
Definition: Action.php:29
‪TYPO3\CMS\Scheduler\Task\Enumeration\Action\SET_NEXT_EXECUTION_TIME
‪const SET_NEXT_EXECUTION_TIME
Definition: Action.php:33
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\getModuleMenu
‪getModuleMenu()
Definition: SchedulerModuleController.php:206
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\executeTasks
‪executeTasks()
Definition: SchedulerModuleController.php:763
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\deleteTask
‪deleteTask()
Definition: SchedulerModuleController.php:424
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\$moduleTemplate
‪ModuleTemplate $moduleTemplate
Definition: SchedulerModuleController.php:104
‪TYPO3\CMS\Core\Core\Environment\isWindows
‪static bool isWindows()
Definition: Environment.php:266
‪TYPO3\CMS\Fluid\ViewHelpers\Be\InfoboxViewHelper\STATE_ERROR
‪const STATE_ERROR
Definition: InfoboxViewHelper.php:64
‪TYPO3\CMS\Core\Imaging\IconFactory
Definition: IconFactory.php:31
‪TYPO3\CMS\Fluid\ViewHelpers\Be\InfoboxViewHelper\STATE_WARNING
‪const STATE_WARNING
Definition: InfoboxViewHelper.php:63
‪TYPO3\CMS\Core\Utility\ArrayUtility\mergeRecursiveWithOverrule
‪static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
Definition: ArrayUtility.php:614
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\getRegisteredTaskGroups
‪array getRegisteredTaskGroups()
Definition: SchedulerModuleController.php:1294
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\preprocessData
‪bool preprocessData()
Definition: SchedulerModuleController.php:1141
‪TYPO3\CMS\Core\Localization\LanguageService\sL
‪string sL($input)
Definition: LanguageService.php:158
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\__construct
‪__construct()
Definition: SchedulerModuleController.php:138
‪$fields
‪$fields
Definition: pages.php:4
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\$cshKey
‪string $cshKey
Definition: SchedulerModuleController.php:82
‪TYPO3\CMS\Backend\Template\ModuleTemplate
Definition: ModuleTemplate.php:40
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\$backendTemplatePath
‪string $backendTemplatePath
Definition: SchedulerModuleController.php:90
‪TYPO3\CMS\Core\Page\PageRenderer\loadRequireJsModule
‪loadRequireJsModule($mainModuleName, $callBackFunction=null)
Definition: PageRenderer.php:1593
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\convertToTimestamp
‪int convertToTimestamp(string $input)
Definition: SchedulerModuleController.php:1238
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility
Definition: ExtensionManagementUtility.php:36
‪TYPO3\CMS\Core\Type\Enumeration\cast
‪static static cast($value)
Definition: Enumeration.php:182
‪TYPO3\CMS\Core\Page\PageRenderer
Definition: PageRenderer.php:35
‪TYPO3\CMS\Core\Messaging\AbstractMessage\WARNING
‪const WARNING
Definition: AbstractMessage.php:28
‪TYPO3\CMS\Scheduler\Task\Enumeration\Action\TOGGLE_HIDDEN
‪const TOGGLE_HIDDEN
Definition: Action.php:35
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\infoScreenAction
‪string infoScreenAction()
Definition: SchedulerModuleController.php:406
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\$action
‪Action $action
Definition: SchedulerModuleController.php:118
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\$iconFactory
‪IconFactory $iconFactory
Definition: SchedulerModuleController.php:108
‪TYPO3\CMS\Scheduler\Task\AbstractTask
Definition: AbstractTask.php:32
‪TYPO3\CMS\Scheduler\Task\Enumeration\Action\STOP
‪const STOP
Definition: Action.php:34
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\toggleDisableAction
‪toggleDisableAction()
Definition: SchedulerModuleController.php:489
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\getLanguageService
‪LanguageService getLanguageService()
Definition: SchedulerModuleController.php:1421
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController
Definition: SchedulerModuleController.php:53
‪TYPO3\CMS\Backend\Routing\UriBuilder
Definition: UriBuilder.php:35
‪TYPO3\CMS\Backend\Utility\BackendUtility\getModuleData
‪static array getModuleData( $MOD_MENU, $CHANGED_SETTINGS, $modName, $type='', $dontValidateList='', $setDefaultList='')
Definition: BackendUtility.php:3259
‪TYPO3\CMS\Scheduler\ProgressProviderInterface
Definition: ProgressProviderInterface.php:21
‪TYPO3\CMS\Scheduler\Scheduler
Definition: Scheduler.php:33
‪TYPO3\CMS\Scheduler\Task\Enumeration\Action\EDIT
‪const EDIT
Definition: Action.php:28
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\stopTask
‪stopTask()
Definition: SchedulerModuleController.php:463
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\addMessage
‪addMessage($message, $severity=FlashMessage::OK)
Definition: SchedulerModuleController.php:1255
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:45
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\getCurrentAction
‪Action getCurrentAction()
Definition: SchedulerModuleController.php:198
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\setCurrentAction
‪setCurrentAction(Action $action)
Definition: SchedulerModuleController.php:1401
‪TYPO3\CMS\Fluid\ViewHelpers\Be\InfoboxViewHelper\STATE_OK
‪const STATE_OK
Definition: InfoboxViewHelper.php:62
‪TYPO3\CMS\Scheduler\Task\Enumeration\Action\DELETE
‪const DELETE
Definition: Action.php:27
‪TYPO3\CMS\Core\Compatibility\PublicMethodDeprecationTrait
Definition: PublicMethodDeprecationTrait.php:68
‪TYPO3\CMS\Backend\Utility\BackendUtility
Definition: BackendUtility.php:72
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\setNextExecutionTimeAction
‪setNextExecutionTimeAction()
Definition: SchedulerModuleController.php:504
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\$MOD_MENU
‪array $MOD_MENU
Definition: SchedulerModuleController.php:124
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\checkScreenAction
‪string checkScreenAction()
Definition: SchedulerModuleController.php:341
‪TYPO3\CMS\Core\Messaging\AbstractMessage\OK
‪const OK
Definition: AbstractMessage.php:27
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\$CMD
‪mixed $CMD
Definition: SchedulerModuleController.php:114
‪TYPO3\CMS\Scheduler\Task\AbstractTask\TYPE_RECURRING
‪const TYPE_RECURRING
Definition: AbstractTask.php:36
‪TYPO3\CMS\Core\Core\Environment\isComposerMode
‪static bool isComposerMode()
Definition: Environment.php:117
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\$messages
‪array $messages
Definition: SchedulerModuleController.php:78
‪TYPO3\CMS\Core\Messaging\FlashMessage
Definition: FlashMessage.php:22
‪TYPO3\CMS\Fluid\View\StandaloneView
Definition: StandaloneView.php:32
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication\writelog
‪int writelog($type, $action, $error, $details_nr, $details, $data, $tablename='', $recuid='', $recpid='', $event_pid=-1, $NEWid='', $userId=0)
Definition: BackendUserAuthentication.php:2351
‪TYPO3\CMS\Scheduler\Task\Enumeration\Action
Definition: Action.php:24
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:23
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\getServerTime
‪string getServerTime()
Definition: SchedulerModuleController.php:1411
‪TYPO3\CMS\Scheduler\Task\Enumeration\Action\SAVE_CLOSE
‪const SAVE_CLOSE
Definition: Action.php:31
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Scheduler\Task\AbstractTask\TYPE_SINGLE
‪const TYPE_SINGLE
Definition: AbstractTask.php:35
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:39
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\$deprecatedPublicMethods
‪array $deprecatedPublicMethods
Definition: SchedulerModuleController.php:57
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\extPath
‪static string extPath($key, $script='')
Definition: ExtensionManagementUtility.php:149
‪TYPO3\CMS\Fluid\ViewHelpers\Be\InfoboxViewHelper
Definition: InfoboxViewHelper.php:58
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\$view
‪StandaloneView $view
Definition: SchedulerModuleController.php:94
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\getButtons
‪getButtons(ServerRequestInterface $request)
Definition: SchedulerModuleController.php:1312
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\saveTask
‪saveTask()
Definition: SchedulerModuleController.php:1038
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:29
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\getRegisteredClasses
‪array getRegisteredClasses()
Definition: SchedulerModuleController.php:1273
‪TYPO3\CMS\Core\Compatibility\PublicPropertyDeprecationTrait
Definition: PublicPropertyDeprecationTrait.php:66
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:44
‪TYPO3\CMS\Core\Localization\LanguageService\getLL
‪string getLL($index)
Definition: LanguageService.php:118
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\mainAction
‪ResponseInterface mainAction(ServerRequestInterface $request)
Definition: SchedulerModuleController.php:161
‪TYPO3\CMS\Backend\Template\Components\ButtonBar\BUTTON_POSITION_RIGHT
‪const BUTTON_POSITION_RIGHT
Definition: ButtonBar.php:40
‪TYPO3\CMS\Core\Page\PageRenderer\addJsInlineCode
‪addJsInlineCode($name, $block, $compress=true, $forceOnTop=false)
Definition: PageRenderer.php:1226
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\editTaskAction
‪string editTaskAction()
Definition: SchedulerModuleController.php:516
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\makeStatusLabel
‪string makeStatusLabel(array $labels)
Definition: SchedulerModuleController.php:1022
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\getPageRenderer
‪PageRenderer getPageRenderer()
Definition: SchedulerModuleController.php:1439
‪TYPO3\CMS\Core\Messaging\AbstractMessage\ERROR
‪const ERROR
Definition: AbstractMessage.php:29
‪TYPO3\CMS\Scheduler\AdditionalFieldProviderInterface
Definition: AdditionalFieldProviderInterface.php:21
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\getBackendUser
‪TYPO3 CMS Core Authentication BackendUserAuthentication getBackendUser()
Definition: SchedulerModuleController.php:1431
‪TYPO3\CMS\Core\Http\HtmlResponse
Definition: HtmlResponse.php:25
‪TYPO3\CMS\Scheduler\Task\Enumeration\Action\SAVE_NEW
‪const SAVE_NEW
Definition: Action.php:32
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\$submittedData
‪array $submittedData
Definition: SchedulerModuleController.php:71
‪TYPO3\CMS\Scheduler\Controller\SchedulerModuleController\listTasksAction
‪string listTasksAction()
Definition: SchedulerModuleController.php:811