f4088cd4b0f05eabfb08a0075e39f87aa256956c
[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 * Constructor
73 */
74 public function __construct() {
75 $this->setScheduler();
76 $this->execution = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Scheduler\\Execution');
77 }
78
79 /**
80 * This is the main method that is called when a task is executed
81 * It MUST be implemented by all classes inheriting from this one
82 * Note that there is no error handling, errors and failures are expected
83 * to be handled and logged by the client implementations.
84 * Should return TRUE on successful execution, FALSE on error.
85 *
86 * @return boolean Returns TRUE on successful execution, FALSE on error
87 */
88 abstract public function execute();
89
90 /**
91 * This method is designed to return some additional information about the task,
92 * that may help to set it apart from other tasks from the same class
93 * This additional information is used - for example - in the Scheduler's BE module
94 * This method should be implemented in most task classes
95 *
96 * @return string Information to display
97 */
98 public function getAdditionalInformation() {
99 return '';
100 }
101
102 /**
103 * This method is used to set the unique id of the task
104 *
105 * @param integer $id Primary key (from the database record) of the scheduled task
106 * @return void
107 */
108 public function setTaskUid($id) {
109 $this->taskUid = intval($id);
110 }
111
112 /**
113 * This method returns the unique id of the task
114 *
115 * @return integer The id of the task
116 */
117 public function getTaskUid() {
118 return $this->taskUid;
119 }
120
121 /**
122 * This method returns the title of the scheduler task
123 *
124 * @return string
125 */
126 public function getTaskTitle() {
127 return $GLOBALS['LANG']->sL($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][get_class($this)]['title']);
128 }
129
130 /**
131 * This method returns the description of the scheduler task
132 *
133 * @return string
134 */
135 public function getTaskDescription() {
136 return $GLOBALS['LANG']->sL($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][get_class($this)]['description']);
137 }
138
139 /**
140 * This method returns the class name of the scheduler task
141 *
142 * @return string
143 */
144 public function getTaskClassName() {
145 return get_class($this);
146 }
147
148 /**
149 * This method returns the disable status of the task
150 *
151 * @return boolean TRUE if task is disabled, FALSE otherwise
152 */
153 public function isDisabled() {
154 return $this->disabled;
155 }
156
157 /**
158 * This method is used to set the disable status of the task
159 *
160 * @param boolean $flag TRUE if task should be disabled, FALSE otherwise
161 * @return void
162 */
163 public function setDisabled($flag) {
164 if ($flag) {
165 $this->disabled = TRUE;
166 } else {
167 $this->disabled = FALSE;
168 }
169 }
170
171 /**
172 * This method is used to set the timestamp corresponding to the next execution time of the task
173 *
174 * @param integer $timestamp Timestamp of next execution
175 * @return void
176 */
177 public function setExecutionTime($timestamp) {
178 $this->executionTime = intval($timestamp);
179 }
180
181 /**
182 * This method returns the timestamp corresponding to the next execution time of the task
183 *
184 * @return integer Timestamp of next execution
185 */
186 public function getExecutionTime() {
187 return $this->executionTime;
188 }
189
190 /**
191 * Sets the internal reference to the singleton instance of the Scheduler
192 *
193 * @return void
194 */
195 public function setScheduler() {
196 $this->scheduler = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Scheduler\\Scheduler');
197 }
198
199 /**
200 * Unsets the internal reference to the singleton instance of the Scheduler
201 * This is done before a task is serialized, so that the scheduler instance
202 * is not saved to the database too
203 *
204 * @return void
205 */
206 public function unsetScheduler() {
207 unset($this->scheduler);
208 }
209
210 /**
211 * Registers a single execution of the task
212 *
213 * @param integer $timestamp Timestamp of the next execution
214 */
215 public function registerSingleExecution($timestamp) {
216 /** @var $execution \TYPO3\CMS\Scheduler\Execution */
217 $execution = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Scheduler\\Execution');
218 $execution->setStart($timestamp);
219 $execution->setInterval(0);
220 $execution->setEnd($timestamp);
221 $execution->setCronCmd('');
222 $execution->setMultiple(0);
223 $execution->setIsNewSingleExecution(TRUE);
224 // Replace existing execution object
225 $this->execution = $execution;
226 }
227
228 /**
229 * Registers a recurring execution of the task
230 *
231 * @param integer $start The first date/time where this execution should occur (timestamp)
232 * @param string $interval Execution interval in seconds
233 * @param integer $end The last date/time where this execution should occur (timestamp)
234 * @param boolean $multiple Set to FALSE if multiple executions of this task are not permitted in parallel
235 * @param string $cron_cmd Used like in crontab (minute hour day month weekday)
236 * @return void
237 */
238 public function registerRecurringExecution($start, $interval, $end = 0, $multiple = FALSE, $cron_cmd = '') {
239 /** @var $execution \TYPO3\CMS\Scheduler\Execution */
240 $execution = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Scheduler\\Execution');
241 // Set general values
242 $execution->setStart($start);
243 $execution->setEnd($end);
244 $execution->setMultiple($multiple);
245 if (empty($cron_cmd)) {
246 // Use interval
247 $execution->setInterval($interval);
248 $execution->setCronCmd('');
249 } else {
250 // Use cron syntax
251 $execution->setInterval(0);
252 $execution->setCronCmd($cron_cmd);
253 }
254 // Replace existing execution object
255 $this->execution = $execution;
256 }
257
258 /**
259 * Sets the internal execution object
260 *
261 * @param \TYPO3\CMS\Scheduler\Execution $execution The execution to add
262 */
263 public function setExecution(\TYPO3\CMS\Scheduler\Execution $execution) {
264 $this->execution = $execution;
265 }
266
267 /**
268 * Returns the execution object
269 *
270 * @return \TYPO3\CMS\Scheduler\Execution The internal execution object
271 */
272 public function getExecution() {
273 return $this->execution;
274 }
275
276 /**
277 * Returns the timestamp for next due execution of the task
278 *
279 * @return integer Date and time of the next execution as a timestamp
280 */
281 public function getNextDueExecution() {
282 // NOTE: this call may throw an exception, but we let it bubble up
283 return $this->execution->getNextExecution();
284 }
285
286 /**
287 * Returns TRUE if several runs of the task are allowed concurrently
288 *
289 * @return boolean TRUE if concurrent executions are allowed, FALSE otherwise
290 */
291 public function areMultipleExecutionsAllowed() {
292 return $this->execution->getMultiple();
293 }
294
295 /**
296 * Returns TRUE if an instance of the task is already running
297 *
298 * @return boolean TRUE if an instance is already running, FALSE otherwise
299 */
300 public function isExecutionRunning() {
301 $isRunning = FALSE;
302 $queryArr = array(
303 'SELECT' => 'serialized_executions',
304 'FROM' => 'tx_scheduler_task',
305 'WHERE' => 'uid = ' . intval($this->taskUid),
306 'LIMIT' => 1
307 );
308 $res = $GLOBALS['TYPO3_DB']->exec_SELECT_queryArray($queryArr);
309 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
310 if (strlen($row['serialized_executions']) > 0) {
311 $isRunning = TRUE;
312 }
313 }
314 $GLOBALS['TYPO3_DB']->sql_free_result($res);
315 return $isRunning;
316 }
317
318 /**
319 * This method adds current execution to the execution list
320 * It also logs the execution time and mode
321 *
322 * @return integer Execution id
323 */
324 public function markExecution() {
325 $queryArr = array(
326 'SELECT' => 'serialized_executions',
327 'FROM' => 'tx_scheduler_task',
328 'WHERE' => 'uid = ' . intval($this->taskUid),
329 'LIMIT' => 1
330 );
331 $res = $GLOBALS['TYPO3_DB']->exec_SELECT_queryArray($queryArr);
332 $runningExecutions = array();
333 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
334 if (strlen($row['serialized_executions']) > 0) {
335 $runningExecutions = unserialize($row['serialized_executions']);
336 }
337 }
338 $GLOBALS['TYPO3_DB']->sql_free_result($res);
339 // Count the number of existing executions and use that number as a key
340 // (we need to know that number, because it is returned at the end of the method)
341 $numExecutions = count($runningExecutions);
342 $runningExecutions[$numExecutions] = time();
343 // Define the context in which the script is running
344 $context = 'BE';
345 if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_CLI) {
346 $context = 'CLI';
347 }
348 $GLOBALS['TYPO3_DB']->exec_UPDATEquery('tx_scheduler_task', 'uid = ' . intval($this->taskUid), array(
349 'serialized_executions' => serialize($runningExecutions),
350 'lastexecution_time' => time(),
351 'lastexecution_context' => $context
352 ));
353 return $numExecutions;
354 }
355
356 /**
357 * Removes given execution from list
358 *
359 * @param integer $executionID Id of the execution to remove.
360 * @param \Exception $failure An exception to signal a failed execution
361 * @return void
362 */
363 public function unmarkExecution($executionID, \Exception $failure = NULL) {
364 // Get the executions for the task
365 $queryArr = array(
366 'SELECT' => 'serialized_executions',
367 'FROM' => 'tx_scheduler_task',
368 'WHERE' => 'uid = ' . intval($this->taskUid),
369 'LIMIT' => 1
370 );
371 $res = $GLOBALS['TYPO3_DB']->exec_SELECT_queryArray($queryArr);
372 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
373 if (strlen($row['serialized_executions']) > 0) {
374 $runningExecutions = unserialize($row['serialized_executions']);
375 // Remove the selected execution
376 unset($runningExecutions[$executionID]);
377 if (count($runningExecutions) > 0) {
378 // Re-serialize the updated executions list (if necessary)
379 $runningExecutionsSerialized = serialize($runningExecutions);
380 } else {
381 $runningExecutionsSerialized = '';
382 }
383 if ($failure instanceof \Exception) {
384 // Log failed execution
385 $logMessage = 'Task failed to execute successfully. Class: ' . get_class($this) . ', UID: ' . $this->taskUid . '. ' . $failure->getMessage();
386 $this->scheduler->log($logMessage, 1, $failure->getCode());
387 $failure = serialize($failure);
388 } else {
389 $failure = '';
390 }
391 // Save the updated executions list
392 $GLOBALS['TYPO3_DB']->exec_UPDATEquery('tx_scheduler_task', 'uid = ' . intval($this->taskUid), array(
393 'serialized_executions' => $runningExecutionsSerialized,
394 'lastexecution_failure' => $failure
395 ));
396 }
397 }
398 $GLOBALS['TYPO3_DB']->sql_free_result($res);
399 }
400
401 /**
402 * Clears all marked executions
403 *
404 * @return boolean TRUE if the clearing succeeded, FALSE otherwise
405 */
406 public function unmarkAllExecutions() {
407 // Set the serialized executions field to empty
408 $result = $GLOBALS['TYPO3_DB']->exec_UPDATEquery('tx_scheduler_task', 'uid = ' . intval($this->taskUid), array(
409 'serialized_executions' => ''
410 ));
411 return $result;
412 }
413
414 /**
415 * Saves the details of the task to the database.
416 *
417 * @return bool
418 */
419 public function save() {
420 return $this->scheduler->saveTask($this);
421 }
422
423 /**
424 * Stops the task, by replacing the execution object by an empty one
425 * NOTE: the task still needs to be saved after that
426 *
427 * @return void
428 */
429 public function stop() {
430 $this->execution = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Scheduler\\Execution');
431 }
432
433 /**
434 * Removes the task totally from the system.
435 *
436 * @return void
437 */
438 public function remove() {
439 $this->scheduler->removeTask($this);
440 }
441
442 }
443
444
445 ?>