[FEATURE] Description-field for scheduler-jobs
[Packages/TYPO3.CMS.git] / typo3 / sysext / scheduler / Classes / Task / AbstractTask.php
1 <?php
2 namespace TYPO3\CMS\Scheduler\Task;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2005-2013 Christian Jul Jensen (julle@typo3.org)
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 *
19 * This script is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * This copyright notice MUST APPEAR in all copies of the script!
25 ***************************************************************/
26 /**
27 * This is the base class for all Scheduler tasks
28 * It's an abstract class, not designed to be instantiated directly
29 * All Scheduler tasks should inherit from this class
30 *
31 * @author Fran├žois Suter <francois@typo3.org>
32 * @author Christian Jul Jensen <julle@typo3.org>
33 */
34 abstract class AbstractTask {
35
36 /**
37 * Reference to a scheduler object
38 *
39 * @var \TYPO3\CMS\Scheduler\Scheduler
40 */
41 protected $scheduler;
42
43 /**
44 * The unique id of the task used to identify it in the database
45 *
46 * @var int
47 */
48 protected $taskUid;
49
50 /**
51 * Disable flag, TRUE if task is disabled, FALSE otherwise
52 *
53 * @var boolean
54 */
55 protected $disabled = FALSE;
56
57 /**
58 * The execution object related to the task
59 *
60 * @var \TYPO3\CMS\Scheduler\Execution
61 */
62 protected $execution;
63
64 /**
65 * This variable contains the time of next execution of the task
66 *
67 * @var integer
68 */
69 protected $executionTime = 0;
70
71 /**
72 * Description for the task
73 *
74 * @var string
75 */
76 protected $description = '';
77
78 /**
79 * Constructor
80 */
81 public function __construct() {
82 $this->setScheduler();
83 $this->execution = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Scheduler\\Execution');
84 }
85
86 /**
87 * This is the main method that is called when a task is executed
88 * It MUST be implemented by all classes inheriting from this one
89 * Note that there is no error handling, errors and failures are expected
90 * to be handled and logged by the client implementations.
91 * Should return TRUE on successful execution, FALSE on error.
92 *
93 * @return boolean Returns TRUE on successful execution, FALSE on error
94 */
95 abstract public function execute();
96
97 /**
98 * This method is designed to return some additional information about the task,
99 * that may help to set it apart from other tasks from the same class
100 * This additional information is used - for example - in the Scheduler's BE module
101 * This method should be implemented in most task classes
102 *
103 * @return string Information to display
104 */
105 public function getAdditionalInformation() {
106 return '';
107 }
108
109 /**
110 * This method is used to set the unique id of the task
111 *
112 * @param integer $id Primary key (from the database record) of the scheduled task
113 * @return void
114 */
115 public function setTaskUid($id) {
116 $this->taskUid = intval($id);
117 }
118
119 /**
120 * This method returns the unique id of the task
121 *
122 * @return integer The id of the task
123 */
124 public function getTaskUid() {
125 return $this->taskUid;
126 }
127
128 /**
129 * This method returns the title of the scheduler task
130 *
131 * @return string
132 */
133 public function getTaskTitle() {
134 return $GLOBALS['LANG']->sL($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][get_class($this)]['title']);
135 }
136
137 /**
138 * This method returns the description of the scheduler task
139 *
140 * @return string
141 */
142 public function getTaskDescription() {
143 return $GLOBALS['LANG']->sL($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][get_class($this)]['description']);
144 }
145
146 /**
147 * This method returns the class name of the scheduler task
148 *
149 * @return string
150 */
151 public function getTaskClassName() {
152 return get_class($this);
153 }
154
155 /**
156 * This method returns the disable status of the task
157 *
158 * @return boolean TRUE if task is disabled, FALSE otherwise
159 */
160 public function isDisabled() {
161 return $this->disabled;
162 }
163
164 /**
165 * This method is used to set the disable status of the task
166 *
167 * @param boolean $flag TRUE if task should be disabled, FALSE otherwise
168 * @return void
169 */
170 public function setDisabled($flag) {
171 if ($flag) {
172 $this->disabled = TRUE;
173 } else {
174 $this->disabled = FALSE;
175 }
176 }
177
178 /**
179 * This method is used to set the timestamp corresponding to the next execution time of the task
180 *
181 * @param integer $timestamp Timestamp of next execution
182 * @return void
183 */
184 public function setExecutionTime($timestamp) {
185 $this->executionTime = intval($timestamp);
186 }
187
188 /**
189 * This method returns the timestamp corresponding to the next execution time of the task
190 *
191 * @return integer Timestamp of next execution
192 */
193 public function getExecutionTime() {
194 return $this->executionTime;
195 }
196
197 /**
198 * This method is used to set the description of the task
199 *
200 * @param string $description Description
201 * @return void
202 */
203 public function setDescription($description) {
204 $this->description = $description;
205 }
206
207 /**
208 * This method returns the description of the task
209 *
210 * @return string Description
211 */
212 public function getDescription() {
213 return $this->description;
214 }
215
216 /**
217 * Sets the internal reference to the singleton instance of the Scheduler
218 *
219 * @return void
220 */
221 public function setScheduler() {
222 $this->scheduler = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Scheduler\\Scheduler');
223 }
224
225 /**
226 * Unsets the internal reference to the singleton instance of the Scheduler
227 * This is done before a task is serialized, so that the scheduler instance
228 * is not saved to the database too
229 *
230 * @return void
231 */
232 public function unsetScheduler() {
233 unset($this->scheduler);
234 }
235
236 /**
237 * Registers a single execution of the task
238 *
239 * @param integer $timestamp Timestamp of the next execution
240 */
241 public function registerSingleExecution($timestamp) {
242 /** @var $execution \TYPO3\CMS\Scheduler\Execution */
243 $execution = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Scheduler\\Execution');
244 $execution->setStart($timestamp);
245 $execution->setInterval(0);
246 $execution->setEnd($timestamp);
247 $execution->setCronCmd('');
248 $execution->setMultiple(0);
249 $execution->setIsNewSingleExecution(TRUE);
250 // Replace existing execution object
251 $this->execution = $execution;
252 }
253
254 /**
255 * Registers a recurring execution of the task
256 *
257 * @param integer $start The first date/time where this execution should occur (timestamp)
258 * @param string $interval Execution interval in seconds
259 * @param integer $end The last date/time where this execution should occur (timestamp)
260 * @param boolean $multiple Set to FALSE if multiple executions of this task are not permitted in parallel
261 * @param string $cron_cmd Used like in crontab (minute hour day month weekday)
262 * @return void
263 */
264 public function registerRecurringExecution($start, $interval, $end = 0, $multiple = FALSE, $cron_cmd = '') {
265 /** @var $execution \TYPO3\CMS\Scheduler\Execution */
266 $execution = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Scheduler\\Execution');
267 // Set general values
268 $execution->setStart($start);
269 $execution->setEnd($end);
270 $execution->setMultiple($multiple);
271 if (empty($cron_cmd)) {
272 // Use interval
273 $execution->setInterval($interval);
274 $execution->setCronCmd('');
275 } else {
276 // Use cron syntax
277 $execution->setInterval(0);
278 $execution->setCronCmd($cron_cmd);
279 }
280 // Replace existing execution object
281 $this->execution = $execution;
282 }
283
284 /**
285 * Sets the internal execution object
286 *
287 * @param \TYPO3\CMS\Scheduler\Execution $execution The execution to add
288 */
289 public function setExecution(\TYPO3\CMS\Scheduler\Execution $execution) {
290 $this->execution = $execution;
291 }
292
293 /**
294 * Returns the execution object
295 *
296 * @return \TYPO3\CMS\Scheduler\Execution The internal execution object
297 */
298 public function getExecution() {
299 return $this->execution;
300 }
301
302 /**
303 * Returns the timestamp for next due execution of the task
304 *
305 * @return integer Date and time of the next execution as a timestamp
306 */
307 public function getNextDueExecution() {
308 // NOTE: this call may throw an exception, but we let it bubble up
309 return $this->execution->getNextExecution();
310 }
311
312 /**
313 * Returns TRUE if several runs of the task are allowed concurrently
314 *
315 * @return boolean TRUE if concurrent executions are allowed, FALSE otherwise
316 */
317 public function areMultipleExecutionsAllowed() {
318 return $this->execution->getMultiple();
319 }
320
321 /**
322 * Returns TRUE if an instance of the task is already running
323 *
324 * @return boolean TRUE if an instance is already running, FALSE otherwise
325 */
326 public function isExecutionRunning() {
327 $isRunning = FALSE;
328 $queryArr = array(
329 'SELECT' => 'serialized_executions',
330 'FROM' => 'tx_scheduler_task',
331 'WHERE' => 'uid = ' . intval($this->taskUid),
332 'LIMIT' => 1
333 );
334 $res = $GLOBALS['TYPO3_DB']->exec_SELECT_queryArray($queryArr);
335 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
336 if (strlen($row['serialized_executions']) > 0) {
337 $isRunning = TRUE;
338 }
339 }
340 $GLOBALS['TYPO3_DB']->sql_free_result($res);
341 return $isRunning;
342 }
343
344 /**
345 * This method adds current execution to the execution list
346 * It also logs the execution time and mode
347 *
348 * @return integer Execution id
349 */
350 public function markExecution() {
351 $queryArr = array(
352 'SELECT' => 'serialized_executions',
353 'FROM' => 'tx_scheduler_task',
354 'WHERE' => 'uid = ' . intval($this->taskUid),
355 'LIMIT' => 1
356 );
357 $res = $GLOBALS['TYPO3_DB']->exec_SELECT_queryArray($queryArr);
358 $runningExecutions = array();
359 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
360 if (strlen($row['serialized_executions']) > 0) {
361 $runningExecutions = unserialize($row['serialized_executions']);
362 }
363 }
364 $GLOBALS['TYPO3_DB']->sql_free_result($res);
365 // Count the number of existing executions and use that number as a key
366 // (we need to know that number, because it is returned at the end of the method)
367 $numExecutions = count($runningExecutions);
368 $runningExecutions[$numExecutions] = time();
369 // Define the context in which the script is running
370 $context = 'BE';
371 if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_CLI) {
372 $context = 'CLI';
373 }
374 $GLOBALS['TYPO3_DB']->exec_UPDATEquery('tx_scheduler_task', 'uid = ' . intval($this->taskUid), array(
375 'serialized_executions' => serialize($runningExecutions),
376 'lastexecution_time' => time(),
377 'lastexecution_context' => $context
378 ));
379 return $numExecutions;
380 }
381
382 /**
383 * Removes given execution from list
384 *
385 * @param integer $executionID Id of the execution to remove.
386 * @param \Exception $failure An exception to signal a failed execution
387 * @return void
388 */
389 public function unmarkExecution($executionID, \Exception $failure = NULL) {
390 // Get the executions for the task
391 $queryArr = array(
392 'SELECT' => 'serialized_executions',
393 'FROM' => 'tx_scheduler_task',
394 'WHERE' => 'uid = ' . intval($this->taskUid),
395 'LIMIT' => 1
396 );
397 $res = $GLOBALS['TYPO3_DB']->exec_SELECT_queryArray($queryArr);
398 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
399 if (strlen($row['serialized_executions']) > 0) {
400 $runningExecutions = unserialize($row['serialized_executions']);
401 // Remove the selected execution
402 unset($runningExecutions[$executionID]);
403 if (count($runningExecutions) > 0) {
404 // Re-serialize the updated executions list (if necessary)
405 $runningExecutionsSerialized = serialize($runningExecutions);
406 } else {
407 $runningExecutionsSerialized = '';
408 }
409 if ($failure instanceof \Exception) {
410 // Log failed execution
411 $logMessage = 'Task failed to execute successfully. Class: ' . get_class($this) . ', UID: ' . $this->taskUid . '. ' . $failure->getMessage();
412 $this->scheduler->log($logMessage, 1, $failure->getCode());
413 $failure = serialize($failure);
414 } else {
415 $failure = '';
416 }
417 // Save the updated executions list
418 $GLOBALS['TYPO3_DB']->exec_UPDATEquery('tx_scheduler_task', 'uid = ' . intval($this->taskUid), array(
419 'serialized_executions' => $runningExecutionsSerialized,
420 'lastexecution_failure' => $failure
421 ));
422 }
423 }
424 $GLOBALS['TYPO3_DB']->sql_free_result($res);
425 }
426
427 /**
428 * Clears all marked executions
429 *
430 * @return boolean TRUE if the clearing succeeded, FALSE otherwise
431 */
432 public function unmarkAllExecutions() {
433 // Set the serialized executions field to empty
434 $result = $GLOBALS['TYPO3_DB']->exec_UPDATEquery('tx_scheduler_task', 'uid = ' . intval($this->taskUid), array(
435 'serialized_executions' => ''
436 ));
437 return $result;
438 }
439
440 /**
441 * Saves the details of the task to the database.
442 *
443 * @return boolean
444 */
445 public function save() {
446 return $this->scheduler->saveTask($this);
447 }
448
449 /**
450 * Stops the task, by replacing the execution object by an empty one
451 * NOTE: the task still needs to be saved after that
452 *
453 * @return void
454 */
455 public function stop() {
456 $this->execution = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Scheduler\\Execution');
457 }
458
459 /**
460 * Removes the task totally from the system.
461 *
462 * @return void
463 */
464 public function remove() {
465 $this->scheduler->removeTask($this);
466 }
467
468 }