TYPO3 CMS  TYPO3_8-7
AbstractTask.php
Go to the documentation of this file.
1 <?php
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 
21 
27 abstract class AbstractTask
28 {
29  const TYPE_SINGLE = 1;
30  const TYPE_RECURRING = 2;
31 
37  protected $scheduler;
38 
44  protected $taskUid;
45 
51  protected $disabled = false;
52 
58  protected $runOnNextCronJob = false;
59 
65  protected $execution;
66 
72  protected $executionTime = 0;
73 
79  protected $description = '';
80 
86  protected $taskGroup;
87 
91  public function __construct()
92  {
93  $this->setScheduler();
94  $this->execution = GeneralUtility::makeInstance(\TYPO3\CMS\Scheduler\Execution::class);
95  }
96 
106  abstract public function execute();
107 
116  public function getAdditionalInformation()
117  {
118  return '';
119  }
120 
126  public function setTaskUid($id)
127  {
128  $this->taskUid = (int)$id;
129  }
130 
136  public function getTaskUid()
137  {
138  return $this->taskUid;
139  }
140 
146  public function getTaskTitle()
147  {
148  return $GLOBALS['LANG']->sL($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][get_class($this)]['title']);
149  }
150 
156  public function getTaskDescription()
157  {
158  return $GLOBALS['LANG']->sL($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][get_class($this)]['description']);
159  }
160 
166  public function getTaskClassName()
167  {
168  return get_class($this);
169  }
170 
176  public function isDisabled()
177  {
178  return $this->disabled;
179  }
180 
186  public function setDisabled($flag)
187  {
188  if ($flag) {
189  $this->disabled = true;
190  } else {
191  $this->disabled = false;
192  }
193  }
194 
200  public function setRunOnNextCronJob($flag)
201  {
202  $this->runOnNextCronJob = $flag;
203  }
204 
210  public function getRunOnNextCronJob()
211  {
213  }
214 
220  public function setExecutionTime($timestamp)
221  {
222  $this->executionTime = (int)$timestamp;
223  }
224 
230  public function getTaskGroup()
231  {
232  return $this->taskGroup;
233  }
234 
240  public function setTaskGroup($taskGroup)
241  {
242  $this->taskGroup = (int)$taskGroup;
243  }
244 
250  public function getExecutionTime()
251  {
252  return $this->executionTime;
253  }
254 
260  public function setDescription($description)
261  {
262  $this->description = $description;
263  }
264 
270  public function getDescription()
271  {
272  return $this->description;
273  }
274 
278  public function setScheduler()
279  {
280  $this->scheduler = GeneralUtility::makeInstance(\TYPO3\CMS\Scheduler\Scheduler::class);
281  }
282 
288  public function unsetScheduler()
289  {
290  unset($this->scheduler);
291  }
292 
298  public function registerSingleExecution($timestamp)
299  {
301  $execution = GeneralUtility::makeInstance(\TYPO3\CMS\Scheduler\Execution::class);
302  $execution->setStart($timestamp);
303  $execution->setInterval(0);
304  $execution->setEnd($timestamp);
305  $execution->setCronCmd('');
306  $execution->setMultiple(0);
307  $execution->setIsNewSingleExecution(true);
308  // Replace existing execution object
309  $this->execution = $execution;
310  }
311 
321  public function registerRecurringExecution($start, $interval, $end = 0, $multiple = false, $cron_cmd = '')
322  {
324  $execution = GeneralUtility::makeInstance(\TYPO3\CMS\Scheduler\Execution::class);
325  // Set general values
326  $execution->setStart($start);
327  $execution->setEnd($end);
328  $execution->setMultiple($multiple);
329  if (empty($cron_cmd)) {
330  // Use interval
331  $execution->setInterval($interval);
332  $execution->setCronCmd('');
333  } else {
334  // Use cron syntax
335  $execution->setInterval(0);
336  $execution->setCronCmd($cron_cmd);
337  }
338  // Replace existing execution object
339  $this->execution = $execution;
340  }
341 
348  {
349  $this->execution = $execution;
350  }
351 
357  public function getExecution()
358  {
359  return $this->execution;
360  }
361 
367  public function getNextDueExecution()
368  {
369  // NOTE: this call may throw an exception, but we let it bubble up
370  return $this->execution->getNextExecution();
371  }
372 
379  {
380  return $this->execution->getMultiple();
381  }
382 
388  public function isExecutionRunning()
389  {
390  $isRunning = false;
391  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
392  ->getQueryBuilderForTable('tx_scheduler_task');
393  $row = $queryBuilder
394  ->select('serialized_executions')
395  ->from('tx_scheduler_task')
396  ->where(
397  $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($this->taskUid, \PDO::PARAM_INT))
398  )
399  ->execute()
400  ->fetch();
401 
402  if ($row && !empty($row['serialized_executions'])) {
403  $isRunning = true;
404  }
405  return $isRunning;
406  }
407 
414  public function markExecution()
415  {
416  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
417  ->getQueryBuilderForTable('tx_scheduler_task');
418 
419  $row = $queryBuilder
420  ->select('serialized_executions')
421  ->from('tx_scheduler_task')
422  ->where(
423  $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($this->taskUid, \PDO::PARAM_INT))
424  )
425  ->execute()
426  ->fetch();
427 
428  $runningExecutions = [];
429  if ($row && !empty($row['serialized_executions'])) {
430  $runningExecutions = unserialize($row['serialized_executions']);
431  }
432  // Count the number of existing executions and use that number as a key
433  // (we need to know that number, because it is returned at the end of the method)
434  $numExecutions = count($runningExecutions);
435  $runningExecutions[$numExecutions] = time();
436  // Define the context in which the script is running
437  $context = 'BE';
438  if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_CLI) {
439  $context = 'CLI';
440  }
441  GeneralUtility::makeInstance(ConnectionPool::class)
442  ->getConnectionForTable('tx_scheduler_task')
443  ->update(
444  'tx_scheduler_task',
445  [
446  'serialized_executions' => serialize($runningExecutions),
447  'lastexecution_time' => time(),
448  'lastexecution_context' => $context
449  ],
450  [
451  'uid' => $this->taskUid
452  ],
453  [
454  'serialized_executions' => Connection::PARAM_LOB,
455  ]
456  );
457  return $numExecutions;
458  }
459 
466  public function unmarkExecution($executionID, \Throwable $failure = null)
467  {
468  // Get the executions for the task
469  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
470  ->getQueryBuilderForTable('tx_scheduler_task');
471 
472  $row = $queryBuilder
473  ->select('serialized_executions')
474  ->from('tx_scheduler_task')
475  ->where(
476  $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($this->taskUid, \PDO::PARAM_INT))
477  )
478  ->execute()
479  ->fetch();
480 
481  if ($row && $row['serialized_executions'] !== '') {
482  $runningExecutions = unserialize($row['serialized_executions']);
483  // Remove the selected execution
484  unset($runningExecutions[$executionID]);
485  if (!empty($runningExecutions)) {
486  // Re-serialize the updated executions list (if necessary)
487  $runningExecutionsSerialized = serialize($runningExecutions);
488  } else {
489  $runningExecutionsSerialized = '';
490  }
491  if ($failure instanceof \Throwable) {
492  // Log failed execution
493  $logMessage = 'Task failed to execute successfully. Class: ' . get_class($this)
494  . ', UID: ' . $this->taskUid . ', Code: ' . $failure->getCode() . ', ' . $failure->getMessage();
495  $this->scheduler->log($logMessage, 1);
496  // Do not serialize the complete exception or the trace, this can lead to huge strings > 50MB
497  $failureString = serialize([
498  'code' => $failure->getCode(),
499  'message' => $failure->getMessage(),
500  'file' => $failure->getFile(),
501  'line' => $failure->getLine(),
502  'traceString' => $failure->getTraceAsString(),
503  ]);
504  } else {
505  $failureString = '';
506  }
507  // Save the updated executions list
508  GeneralUtility::makeInstance(ConnectionPool::class)
509  ->getConnectionForTable('tx_scheduler_task')
510  ->update(
511  'tx_scheduler_task',
512  [
513  'serialized_executions' => $runningExecutionsSerialized,
514  'lastexecution_failure' => $failureString
515  ],
516  [
517  'uid' => $this->taskUid
518  ],
519  [
520  'serialized_executions' => Connection::PARAM_LOB,
521  ]
522  );
523  }
524  }
525 
531  public function unmarkAllExecutions()
532  {
533  // Set the serialized executions field to empty
534  $result = GeneralUtility::makeInstance(ConnectionPool::class)
535  ->getConnectionForTable('tx_scheduler_task')
536  ->update(
537  'tx_scheduler_task',
538  [
539  'serialized_executions' => ''
540  ],
541  [
542  'uid' => $this->taskUid
543  ],
544  [
545  'serialized_executions' => Connection::PARAM_LOB,
546  ]
547  );
548  return (bool)$result;
549  }
550 
556  public function save()
557  {
558  return $this->scheduler->saveTask($this);
559  }
560 
565  public function stop()
566  {
567  $this->execution = GeneralUtility::makeInstance(\TYPO3\CMS\Scheduler\Execution::class);
568  }
569 
573  public function remove()
574  {
575  $this->scheduler->removeTask($this);
576  }
577 
584  public function getType()
585  {
586  if (!empty($this->getExecution()->getInterval()) || !empty($this->getExecution()->getCronCmd())) {
587  return self::TYPE_RECURRING;
588  }
589  return self::TYPE_SINGLE;
590  }
591 
597  protected function logException(\Exception $e)
598  {
599  GeneralUtility::sysLog($e->getMessage(), 'scheduler', GeneralUtility::SYSLOG_SEVERITY_ERROR);
600  $this->getLogger()->error('A Task Exception was captured: ' . $e->getMessage() . ' (' . $e->getCode() . ')', ['exception' => $e]);
601  }
602 
608  protected function getLogger()
609  {
610  $logManager = GeneralUtility::makeInstance(LogManager::class);
611  return $logManager->getLogger(get_class($this));
612  }
613 }
static makeInstance($className,... $constructorArguments)
unmarkExecution($executionID, \Throwable $failure=null)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
setExecution(\TYPO3\CMS\Scheduler\Execution $execution)