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