[!!!][FEATURE] Migrate Scheduler Cli Controller to Symfony Command
[Packages/TYPO3.CMS.git] / typo3 / sysext / scheduler / Classes / Command / SchedulerCommand.php
1 <?php
2 namespace TYPO3\CMS\Scheduler\Command;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use Symfony\Component\Console\Command\Command;
18 use Symfony\Component\Console\Input\InputInterface;
19 use Symfony\Component\Console\Input\InputOption;
20 use Symfony\Component\Console\Output\OutputInterface;
21 use TYPO3\CMS\Core\Core\Bootstrap;
22 use TYPO3\CMS\Core\Utility\GeneralUtility;
23 use TYPO3\CMS\Scheduler\Scheduler;
24 use TYPO3\CMS\Scheduler\Task\AbstractTask;
25
26 /**
27 * CLI command for the 'scheduler' extension which executes
28 */
29 class SchedulerCommand extends Command
30 {
31 /**
32 * @var bool
33 */
34 protected $hasTask = true;
35
36 /**
37 * @var Scheduler
38 */
39 protected $scheduler;
40
41 /**
42 * Configure the command by defining the name, options and arguments
43 */
44 public function configure()
45 {
46 $this
47 ->setDescription('Start the TYPO3 Scheduler from the command line.')
48 ->setHelp('If no parameter is given, the scheduler executes any tasks that are overdue to run.
49 Call it like this: typo3/cli_dispatch.phpsh scheduler --task=13 -f')
50 ->addOption(
51 'task',
52 'i',
53 InputOption::VALUE_REQUIRED,
54 'UID of a specific task'
55 )
56 ->addOption(
57 'force',
58 'f',
59 InputOption::VALUE_NONE,
60 'Force execution of the task which is passed with -i option'
61 )
62 ->addOption(
63 'stop',
64 's',
65 InputOption::VALUE_NONE,
66 'Stop the task which is passed with -i option'
67 );
68 }
69
70 /**
71 * Execute scheduler tasks
72 *
73 * @param InputInterface $input
74 * @param OutputInterface $output
75 * @return void
76 */
77 public function execute(InputInterface $input, OutputInterface $output)
78 {
79 // Make sure the _cli_ user is loaded
80 Bootstrap::getInstance()->initializeBackendAuthentication();
81
82 $this->scheduler = GeneralUtility::makeInstance(Scheduler::class);
83
84 if ((int)$input->getOption('task') > 0) {
85 $taskUid = (int)$input->getOption('task');
86 $stopTask = (bool)($input->hasOption('stop') && $input->getOption('stop'));
87 $force = (bool)($input->hasOption('force') && $input->getOption('force'));
88 $task = $this->getTask($taskUid, $stopTask || $force);
89
90 if ($this->scheduler->isValidTaskObject($task)) {
91 if ($stopTask) {
92 $this->stopTask($task);
93 } else {
94 $this->scheduler->executeTask($task);
95 }
96 }
97 // Record the run in the system registry
98 $this->scheduler->recordLastRun('cli-by-id');
99 } else {
100 $this->loopTasks();
101 }
102 }
103
104 /**
105 * Stop task
106 *
107 * @param AbstractTask $task
108 */
109 protected function stopTask($task)
110 {
111 if ($this->scheduler->isValidTaskObject($task)) {
112 $task->unmarkAllExecutions();
113 }
114 }
115
116 /**
117 * Return task a task for a given UID
118 *
119 * @param int $taskUid
120 * @param bool $force fetch the task regardless if it is queued for execution
121 * @return AbstractTask
122 */
123 protected function getTask(int $taskUid, bool $force)
124 {
125 if ($force) {
126 $task = $this->scheduler->fetchTask($taskUid);
127 } else {
128 $whereClause = 'uid = ' . (int)$taskUid . ' AND nextexecution != 0 AND nextexecution <= ' . $GLOBALS['EXEC_TIME'];
129 list($task) = $this->scheduler->fetchTasksWithCondition($whereClause);
130 }
131
132 return $task;
133 }
134
135 /**
136 * Execute tasks in loop that are ready to execute
137 */
138 protected function loopTasks()
139 {
140 do {
141 // Try getting the next task and execute it
142 // If there are no more tasks to execute, an exception is thrown by \TYPO3\CMS\Scheduler\Scheduler::fetchTask()
143 try {
144 $task = $this->scheduler->fetchTask();
145 try {
146 $this->scheduler->executeTask($task);
147 } catch (\Exception $e) {
148 // We ignore any exception that may have been thrown during execution,
149 // as this is a background process.
150 // The exception message has been recorded to the database anyway
151 continue;
152 }
153 } catch (\OutOfBoundsException $e) {
154 $this->hasTask = false;
155 } catch (\UnexpectedValueException $e) {
156 continue;
157 }
158 } while ($this->hasTask);
159 // Record the run in the system registry
160 $this->scheduler->recordLastRun();
161 }
162 }