0byt3m1n1
Path:
/
data
/
applications
/
aps
/
typo3
/
4.5.5-0
/
standard
/
htdocs
/
typo3
/
sysext
/
scheduler
/
mod1
/
[
Home
]
File: index.php
<?php /*************************************************************** * Copyright notice * * (c) 2009-2011 François Suter <francois@typo3.org> * (c) 2005 Christian Jul Jensen <julle@typo3.org> * All rights reserved * * This script is part of the TYPO3 project. The TYPO3 project is * free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * The GNU General Public License can be found at * http://www.gnu.org/copyleft/gpl.html. * * This script is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * This copyright notice MUST APPEAR in all copies of the script! ***************************************************************/ require_once (t3lib_extMgm::extPath('scheduler') . 'interfaces/interface.tx_scheduler_additionalfieldprovider.php'); $LANG->includeLLFile('EXT:scheduler/mod1/locallang.xml'); $BE_USER->modAccess($MCONF, 1); // This checks permissions and exits if the users has no permission for entry. /** * Module 'TYPO3 Scheduler administration module' for the 'scheduler' extension. * * @author François Suter <francois@typo3.org> * @author Christian Jul Jensen <julle@typo3.org> * @author Ingo Renner <ingo@typo3.org> * @package TYPO3 * @subpackage tx_scheduler * @version $Id$ */ class tx_scheduler_Module extends t3lib_SCbase { /** * Back path to typo3 main dir * * @var string $backPath */ public $backPath; /** * Array containing submitted data when editing or adding a task * * @var array $submittedData */ protected $submittedData = array(); /** * Array containing all messages issued by the application logic * Contains the error's severity and the message itself * * @var array $messages */ protected $messages = array(); /** * @var string Key of the CSH file */ protected $cshKey; /** * * @var tx_scheduler Local scheduler instance */ protected $scheduler; /** * Constructor * * @return void */ public function __construct() { $this->backPath = $GLOBALS['BACK_PATH']; // Set key for CSH $this->cshKey = '_MOD_' . $GLOBALS['MCONF']['name']; } /** * Initializes the backend module * * @return void */ public function init() { parent::init(); // Initialize document $this->doc = t3lib_div::makeInstance('template'); $this->doc->setModuleTemplate(t3lib_extMgm::extPath('scheduler') . 'mod1/mod_template.html'); $this->doc->getPageRenderer()->addCssFile(t3lib_extMgm::extRelPath('scheduler') . 'res/tx_scheduler_be.css'); $this->doc->backPath = $this->backPath; $this->doc->bodyTagId = 'typo3-mod-php'; $this->doc->bodyTagAdditions = 'class="tx_scheduler_mod1"'; // Create scheduler instance $this->scheduler = t3lib_div::makeInstance('tx_scheduler'); } /** * Adds items to the ->MOD_MENU array. Used for the function menu selector. * * @return void */ public function menuConfig() { $this->MOD_MENU = array( 'function' => array( 'scheduler' => $GLOBALS['LANG']->getLL('function.scheduler'), 'check' => $GLOBALS['LANG']->getLL('function.check'), 'info' => $GLOBALS['LANG']->getLL('function.info'), ) ); parent::menuConfig(); } /** * Main function of the module. Write the content to $this->content * * @return void */ public function main() { // Access check! // The page will show only if user has admin rights if ($GLOBALS['BE_USER']->user['admin']) { // Set the form $this->doc->form = '<form name="tx_scheduler_form" id="tx_scheduler_form" method="post" action="">'; // JavaScript for main function menu $this->doc->JScode = ' <script language="javascript" type="text/javascript"> script_ended = 0; function jumpToUrl(URL) { document.location = URL; } </script> '; $this->doc->getPageRenderer()->addInlineSetting('scheduler', 'runningIcon', t3lib_extMgm::extRelPath('scheduler') . 'res/gfx/status_running.png'); // Prepare main content $this->content = $this->doc->header( $GLOBALS['LANG']->getLL('function.' . $this->MOD_SETTINGS['function']) ); $this->content .= $this->doc->spacer(5); $this->content .= $this->getModuleContent(); } else { // If no access, only display the module's title $this->content = $this->doc->header($GLOBALS['LANG']->getLL('title')); $this->content .= $this->doc->spacer(5); } // Place content inside template $content = $this->doc->moduleBody( array(), $this->getDocHeaderButtons(), $this->getTemplateMarkers() ); // Renders the module page $this->content = $this->doc->render( $GLOBALS['LANG']->getLL('title'), $content ); } /** * Generate the module's content * * @return string HTML of the module's main content */ protected function getModuleContent() { $content = ''; $sectionTitle = ''; // Get submitted data $this->submittedData = t3lib_div::_GPmerged('tx_scheduler'); // If a save command was submitted, handle saving now if ($this->CMD == 'save') { $previousCMD = t3lib_div::_GP('previousCMD'); // First check the submitted data $result = $this->preprocessData(); // If result is ok, proceed with saving if ($result) { $this->saveTask(); // Unset command, so that default screen gets displayed unset($this->CMD); // Errors occurred // Go back to previous step } else { $this->CMD = $previousCMD; } } // Handle chosen action switch((string)$this->MOD_SETTINGS['function']) { case 'scheduler': // Scheduler's main screen $content .= $this->executeTasks(); // Execute chosen action switch ($this->CMD) { case 'add': case 'edit': try { // Try adding or editing $content .= $this->editTask(); $sectionTitle = $GLOBALS['LANG']->getLL('action.' . $this->CMD); } catch (Exception $e) { // An exception may happen when the task to // edit could not be found. In this case revert // to displaying the list of tasks // It can also happend when attempting to edit a running task $content .= $this->listTasks(); } break; case 'delete': $this->deleteTask(); $content .= $this->listTasks(); break; case 'stop': $this->stopTask(); $content .= $this->listTasks(); break; case 'list': default: $content .= $this->listTasks(); break; } break; case 'check': // Setup check screen // TODO: move check to the report module $content .= $this->displayCheckScreen(); break; case 'info': // Information screen $content .= $this->displayInfoScreen(); break; } // Wrap the content in a section return $this->doc->section($sectionTitle, '<div class="tx_scheduler_mod1">' . $content . '</div>', 0, 1); } /** * This method actually prints out the module's HTML content * * @return void */ public function render() { echo $this->content; } /** * This method checks the status of the '_cli_scheduler' user * It will differentiate between a non-existing user and an existing, * but disabled user (as per enable fields) * * @return integer -1 if user doesn't exist * 0 if user exists, but is disabled * 1 if user exists and is not disabled */ protected function checkSchedulerUser() { $schedulerUserStatus = -1; // Assemble base WHERE clause $where = 'username = \'_cli_scheduler\' AND admin = 0' . t3lib_BEfunc::deleteClause('be_users'); // Check if user exists at all $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery( '1', 'be_users', $where ); if ($GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { $schedulerUserStatus = 0; // Check if user exists and is enabled $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery( '1', 'be_users', $where . t3lib_BEfunc::BEenableFields('be_users') ); if ($GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { $schedulerUserStatus = 1; } } $GLOBALS['TYPO3_DB']->sql_free_result($res); return $schedulerUserStatus; } /** * This method creates the "cli_scheduler" BE user if it doesn't exist * * @return void */ protected function createSchedulerUser() { // Check _cli_scheduler user status $checkUser = $this->checkSchedulerUser(); // Prepare default message $message = $GLOBALS['LANG']->getLL('msg.userExists'); $severity = t3lib_FlashMessage::WARNING; // If the user does not exist, try creating it if ($checkUser == -1) { // Prepare necessary data for _cli_scheduler user creation $password = md5(uniqid('scheduler', true)); $data = array('be_users' => array('NEW' => array('username' => '_cli_scheduler', 'password' => $password, 'pid' => 0))); /** * Create an instance of TCEmain and execute user creation * * @var t3lib_TCEmain */ $tcemain = t3lib_div::makeInstance('t3lib_TCEmain'); $tcemain->stripslashes_values = 0; $tcemain->start($data, array()); $tcemain->process_datamap(); // Check if a new uid was indeed generated (i.e. a new record was created) // (counting TCEmain errors doesn't work as some failures don't report errors) $numberOfNewIDs = count($tcemain->substNEWwithIDs); if ($numberOfNewIDs == 1) { $message = $GLOBALS['LANG']->getLL('msg.userCreated'); $severity = t3lib_FlashMessage::OK; } else { $message = $GLOBALS['LANG']->getLL('msg.userNotCreated'); $severity = t3lib_FlashMessage::ERROR; } } $this->addMessage($message, $severity); } /** * This method displays the result of a number of checks * on whether the Scheduler is ready to run or running properly * * @return string further information */ protected function displayCheckScreen() { $message = ''; $severity = t3lib_FlashMessage::OK; // First, check if cli_sceduler user creation was requested if ($this->CMD == 'user') { $this->createSchedulerUser(); } // Start generating the content $content = $GLOBALS['LANG']->getLL('msg.schedulerSetupCheck'); // Display information about last automated run, as stored in the system registry /** * @var t3lib_Registry */ $registry = t3lib_div::makeInstance('t3lib_Registry'); $lastRun = $registry->get('tx_scheduler', 'lastRun'); if (!is_array($lastRun)) { $message = $GLOBALS['LANG']->getLL('msg.noLastRun'); $severity = t3lib_FlashMessage::WARNING; } else { if (empty($lastRun['end']) || empty($lastRun['start']) || empty($lastRun['type'])) { $message = $GLOBALS['LANG']->getLL('msg.incompleteLastRun'); $severity = t3lib_FlashMessage::WARNING; } else { $startDate = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $lastRun['start']); $startTime = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], $lastRun['start']); $endDate = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $lastRun['end']); $endTime = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], $lastRun['end']); $label = 'automatically'; if ($lastRun['type'] == 'manual') { $label = 'manually'; } $type = $GLOBALS['LANG']->getLL('label.' . $label); $message = sprintf($GLOBALS['LANG']->getLL('msg.lastRun'), $type, $startDate, $startTime, $endDate, $endTime); $severity = t3lib_FlashMessage::INFO; } } $flashMessage = t3lib_div::makeInstance( 't3lib_FlashMessage', $message, '', $severity ); $content .= '<div class="info-block">'; $content .= '<h3>' . $GLOBALS['LANG']->getLL('hdg.lastRun') . '</h3>'; $content .= $flashMessage->render(); $content .= '</div>'; // Check CLI user $content .= '<div class="info-block">'; $content .= '<h3>' . $GLOBALS['LANG']->getLL('hdg.schedulerUser') . '</h3>'; $content .= '<p>' . $GLOBALS['LANG']->getLL('msg.schedulerUser') . '</p>'; $checkUser = $this->checkSchedulerUser(); if ($checkUser == -1) { $link = $GLOBALS['MCONF']['_'] . '&SET[function]=check&CMD=user'; $message = sprintf($GLOBALS['LANG']->getLL('msg.schedulerUserMissing'), htmlspecialchars($link)); $severity = t3lib_FlashMessage::ERROR; } elseif ($checkUser == 0) { $message = $GLOBALS['LANG']->getLL('msg.schedulerUserFoundButDisabled'); $severity = t3lib_FlashMessage::WARNING; } else { $message = $GLOBALS['LANG']->getLL('msg.schedulerUserFound'); $severity = t3lib_FlashMessage::OK; } $flashMessage = t3lib_div::makeInstance( 't3lib_FlashMessage', $message, '', $severity ); $content .= $flashMessage->render() . '</div>'; // Check if CLI script is executable or not $script = PATH_typo3 . 'cli_dispatch.phpsh'; $isExecutable = FALSE; // Skip this check if running Windows, as rights do not work the same way on this platform // (i.e. the script will always appear as *not* executable) if (TYPO3_OS === 'WIN') { $isExecutable = TRUE; } else { $isExecutable = is_executable($script); } $content .= '<div class="info-block">'; $content .= '<h3>' . $GLOBALS['LANG']->getLL('hdg.cliScript') . '</h3>'; $content .= '<p>' . sprintf($GLOBALS['LANG']->getLL('msg.cliScript'), $script) . '</p>'; if ($isExecutable) { $message = $GLOBALS['LANG']->getLL('msg.cliScriptExecutable'); $severity = t3lib_FlashMessage::OK; } else { $message = $GLOBALS['LANG']->getLL('msg.cliScriptNotExecutable'); $severity = t3lib_FlashMessage::ERROR; } $flashMessage = t3lib_div::makeInstance( 't3lib_FlashMessage', $message, '', $severity ); $content .= $flashMessage->render() . '</div>'; return $content; } /** * This method gathers information about all available task classes and displays it * * @return string HTML content to display */ protected function displayInfoScreen() { $content = ''; $registeredClasses = self::getRegisteredClasses(); // No classes available, display information message if (count($registeredClasses) == 0) { /** @var t3lib_FlashMessage $flashMessage */ $flashMessage = t3lib_div::makeInstance('t3lib_FlashMessage', $GLOBALS['LANG']->getLL('msg.noTasksDefined'), '', t3lib_FlashMessage::INFO ); $content .= $flashMessage->render(); // Display the list of all available classes } else { // Initialise table layout $tableLayout = array ( 'table' => array ('<table border="0" cellspacing="1" cellpadding="2" class="typo3-dblist">', '</table>'), '0' => array ( 'tr' => array('<tr class="t3-row-header" valign="top">', '</tr>'), 'defCol' => array('<td>', '</td>') ), 'defRow' => array ( 'tr' => array('<tr class="db_list_normal">', '</tr>'), 'defCol' => array('<td>', '</td>') ) ); $table = array(); $tr = 0; // Header row $table[$tr][] = $GLOBALS['LANG']->getLL('label.name'); $table[$tr][] = $GLOBALS['LANG']->getLL('label.extension'); $table[$tr][] = $GLOBALS['LANG']->getLL('label.description'); $table[$tr][] = ''; $tr++; // Display information about each service foreach ($registeredClasses as $class => $classInfo) { $table[$tr][] = $classInfo['title']; $table[$tr][] = $classInfo['extension']; $table[$tr][] = $classInfo['description']; $link = $GLOBALS['MCONF']['_'] . '&SET[function]=list&CMD=add&tx_scheduler[class]=' . $class; $table[$tr][] = '<a href="' . htmlspecialchars($link) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:new', TRUE) . '" class="icon">' . t3lib_iconWorks::getSpriteIcon('actions-document-new') . '</a>'; $tr++; } // Render the table and return it $content = '<div>' . $GLOBALS['LANG']->getLL('msg.infoScreenIntro') . '</div>'; $content .= $this->doc->spacer(5); $content .= $this->doc->table($table, $tableLayout); } return $content; } /** * Display the current server's time along with a help text about server time * usage in the Scheduler * * @return string HTML to display */ protected function displayServerTime() { // Get the current time, formatted $dateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] . ' ' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'] . ' T (e'; $now = date($dateFormat) . ', GMT ' . date('P') . ')'; // Display the help text $serverTime = '<h4>' . $GLOBALS['LANG']->getLL('label.serverTime') . '</h4>'; $serverTime .= '<p>' . $GLOBALS['LANG']->getLL('msg.serverTimeHelp') . '</p>'; $serverTime .= '<p>' . sprintf($GLOBALS['LANG']->getLL('msg.serverTime'), $now) . '</p>'; return $serverTime; } /** * Delete a task from the execution queue * * @return void */ protected function deleteTask() { try { // Try to fetch the task and delete it /** * @var tx_scheduler_Task */ $task = $this->scheduler->fetchTask($this->submittedData['uid']); // If the task is currently running, it may not be deleted if ($task->isExecutionRunning()) { $this->addMessage($GLOBALS['LANG']->getLL('msg.maynotDeleteRunningTask'), t3lib_FlashMessage::ERROR); } else { if ($this->scheduler->removeTask($task)) { $this->addMessage($GLOBALS['LANG']->getLL('msg.deleteSuccess')); } else { $this->addMessage($GLOBALS['LANG']->getLL('msg.deleteError'), t3lib_FlashMessage::ERROR); } } } catch (UnexpectedValueException $e) { // The task could not be unserialized properly, simply delete the database record $result = $GLOBALS['TYPO3_DB']->exec_DELETEquery('tx_scheduler_task', 'uid = ' . intval($this->submittedData['uid'])); if ($result) { $this->addMessage($GLOBALS['LANG']->getLL('msg.deleteSuccess')); } else { $this->addMessage($GLOBALS['LANG']->getLL('msg.deleteError'), t3lib_FlashMessage::ERROR); } } catch (OutOfBoundsException $e) { // The task was not found, for some reason $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.taskNotFound'), $this->submittedData['uid']), t3lib_FlashMessage::ERROR); } } /** * Clears the registered running executions from the task * Note that this doesn't actually stop the running script. It just unmarks * all executions. * TODO: find a way to really kill the running task * * @return void */ protected function stopTask() { try { // Try to fetch the task and stop it /** * @var tx_scheduler_Task */ $task = $this->scheduler->fetchTask($this->submittedData['uid']); if ($task->isExecutionRunning()) { // If the task is indeed currently running, clear marked executions $result = $task->unmarkAllExecutions(); if ($result) { $this->addMessage($GLOBALS['LANG']->getLL('msg.stopSuccess')); } else { $this->addMessage($GLOBALS['LANG']->getLL('msg.stopError'), t3lib_FlashMessage::ERROR); } } else { // The task is not running, nothing to unmark $this->addMessage($GLOBALS['LANG']->getLL('msg.maynotStopNonRunningTask'), t3lib_FlashMessage::WARNING); } } catch (Exception $e) { // The task was not found, for some reason $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.taskNotFound'), $this->submittedData['uid']), t3lib_FlashMessage::ERROR); } } /** * Return a form to add a new task or edit an existing one * * @return string HTML form to add or edit a task */ protected function editTask() { $registeredClasses = self::getRegisteredClasses(); $content = ''; $taskInfo = array(); $task = NULL; $process = 'edit'; if ($this->submittedData['uid'] > 0) { // If editing, retrieve data for existing task try { $taskRecord = $this->scheduler->fetchTaskRecord($this->submittedData['uid']); // If there's a registered execution, the task should not be edited if (!empty($taskRecord['serialized_executions'])) { $this->addMessage($GLOBALS['LANG']->getLL('msg.maynotEditRunningTask'), t3lib_FlashMessage::ERROR); throw new LogicException('Runnings tasks cannot not be edited', 1251232849); } // Get the task object $task = unserialize($taskRecord['serialized_task_object']); // Set some task information $class = $taskRecord['classname']; $taskInfo['disable'] = $taskRecord['disable']; // Check that the task object is valid if ($this->scheduler->isValidTaskObject($task)) { // The task object is valid, process with fetching current data $taskInfo['class'] = $class; // Get execution information $taskInfo['start'] = $task->getExecution()->getStart(); $taskInfo['end'] = $task->getExecution()->getEnd(); $taskInfo['interval'] = $task->getExecution()->getInterval(); $taskInfo['croncmd'] = $task->getExecution()->getCronCmd(); $taskInfo['multiple'] = $task->getExecution()->getMultiple(); if (!empty($taskInfo['interval']) || !empty($taskInfo['croncmd'])) { // Guess task type from the existing information // If an interval or a cron command is defined, it's a recurring task // FIXME remove magic numbers for the type, use class constants instead $taskInfo['type'] = 2; $taskInfo['frequency'] = (empty($taskInfo['interval'])) ? $taskInfo['croncmd'] : $taskInfo['interval']; } else { // It's not a recurring task // Make sure interval and cron command are both empty $taskInfo['type'] = 1; $taskInfo['frequency'] = ''; $taskInfo['end'] = 0; } } else { // The task object is not valid // Issue error message $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.invalidTaskClassEdit'), $class), t3lib_FlashMessage::ERROR); // Initialize empty values $taskInfo['start'] = 0; $taskInfo['end'] = 0; $taskInfo['frequency'] = ''; $taskInfo['multiple'] = false; $taskInfo['type'] = 1; } } catch (OutOfBoundsException $e) { // Add a message and continue throwing the exception $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.taskNotFound'), $this->submittedData['uid']), t3lib_FlashMessage::ERROR); throw $e; } } else { // If adding a new object, set some default values $taskInfo['class'] = key($registeredClasses); $taskInfo['type'] = 2; $taskInfo['start'] = $GLOBALS['EXEC_TIME']; $taskInfo['end'] = ''; $taskInfo['frequency'] = ''; $taskInfo['multiple'] = 0; $process = 'add'; } if (count($this->submittedData) > 0) { // If some data was already submitted, use it to override // existing data $taskInfo = t3lib_div::array_merge_recursive_overrule($taskInfo, $this->submittedData); } // Get the extra fields to display for each task that needs some $allAdditionalFields = array(); if ($process == 'add') { foreach ($registeredClasses as $class => $registrationInfo) { if (!empty($registrationInfo['provider'])) { $providerObject = t3lib_div::getUserObj($registrationInfo['provider']); if ($providerObject instanceof tx_scheduler_AdditionalFieldProvider) { $additionalFields = $providerObject->getAdditionalFields($taskInfo, NULL, $this); $allAdditionalFields = array_merge($allAdditionalFields, array($class => $additionalFields)); } } } // In case of edit, get only the extra fields for the current task class } else { if (!empty($registeredClasses[$taskInfo['class']]['provider'])) { $providerObject = t3lib_div::getUserObj($registeredClasses[$taskInfo['class']]['provider']); if ($providerObject instanceof tx_scheduler_AdditionalFieldProvider) { $allAdditionalFields[$taskInfo['class']] = $providerObject->getAdditionalFields($taskInfo, $task, $this); } } } // Load necessary JavaScript /** @var $pageRenderer t3lib_PageRenderer */ $pageRenderer = $this->doc->getPageRenderer(); $pageRenderer->loadExtJS(); $pageRenderer->addJsFile(t3lib_extMgm::extRelPath('scheduler') . 'res/tx_scheduler_be.js'); $pageRenderer->addJsFile($this->backPath . '../t3lib/js/extjs/tceforms.js'); // Define settings for Date Picker $typo3Settings = array( 'datePickerUSmode' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ? 1 : 0, 'dateFormat' => array('j-n-Y', 'G:i j-n-Y'), 'dateFormatUS' => array('n-j-Y', 'G:i n-j-Y'), ); $pageRenderer->addInlineSettingArray('', $typo3Settings); // Define table layout for add/edit form $tableLayout = array ( 'table' => array ('<table border="0" cellspacing="0" cellpadding="0" id="edit_form" class="typo3-usersettings">', '</table>'), ); // Define a style for hiding // Some fields will be hidden when the task is not recurring $style = ''; if ($taskInfo['type'] == 1) { $style = ' style="display: none"'; } // Start rendering the add/edit form $content .= '<input type="hidden" name="tx_scheduler[uid]" value="' . $this->submittedData['uid'] . '" />'; $content .= '<input type="hidden" name="previousCMD" value="' . $this->CMD . '" />'; $content .= '<input type="hidden" name="CMD" value="save" />'; $table = array(); $tr = 0; $defaultCell = array('<td class="td-input">', '</td>'); // Disable checkbox $label = '<label for="task_disable">' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:disable') . '</label>'; $table[$tr][] = t3lib_BEfunc::wrapInHelp($this->cshKey, 'task_disable', $label); $table[$tr][] = '<input type="hidden" name="tx_scheduler[disable]" value="0" /> <input type="checkbox" name="tx_scheduler[disable]" value="1" id="task_disable"' . ($taskInfo['disable'] == 1 ? ' checked="checked"' : '') . ' />'; $tableLayout[$tr] = array ( 'tr' => array('<tr id="task_disable_row">', '</tr>'), 'defCol' => $defaultCell, '0' => array('<td class="td-label">', '</td>') ); $tr++; // Task class selector $label = '<label for="task_class">' . $GLOBALS['LANG']->getLL('label.class') . '</label>'; $table[$tr][] = t3lib_BEfunc::wrapInHelp($this->cshKey, 'task_class', $label); // On editing, don't allow changing of the task class, unless it was not valid if ($this->submittedData['uid'] > 0 && !empty($taskInfo['class'])) { $cell = $registeredClasses[$taskInfo['class']]['title'] . ' (' . $registeredClasses[$taskInfo['class']]['extension'] . ')'; $cell .= '<input type="hidden" name="tx_scheduler[class]" id="task_class" value="' . $taskInfo['class'] . '" />'; } else { $cell = '<select name="tx_scheduler[class]" id="task_class" class="wide" onchange="actOnChangedTaskClass(this)">'; // Loop on all registered classes to display a selector foreach ($registeredClasses as $class => $classInfo) { $selected = ($class == $taskInfo['class']) ? ' selected="selected"' : ''; $cell .= '<option value="' . $class . '"' . $selected . '>' . $classInfo['title'] . ' (' . $classInfo['extension'] . ')' . '</option>'; } $cell .= '</select>'; } $table[$tr][] = $cell; // Make sure each row has a unique id, for manipulation with JS $tableLayout[$tr] = array ( 'tr' => array('<tr id="task_class_row">', '</tr>'), 'defCol' => $defaultCell, '0' => array('<td class="td-label">', '</td>') ); $tr++; // Task type selector $label = '<label for="task_type">' . $GLOBALS['LANG']->getLL('label.type') . '</label>'; $table[$tr][] = t3lib_BEfunc::wrapInHelp($this->cshKey, 'task_type', $label); $table[$tr][] = '<select name="tx_scheduler[type]" id="task_type" onchange="actOnChangedTaskType(this)">' . '<option value="1"' . ($taskInfo['type'] == 1 ? ' selected="selected"' : '') . '>' . $GLOBALS['LANG']->getLL('label.type.single') . '</option>' . '<option value="2"' . ($taskInfo['type'] == 2 ? ' selected="selected"' : '') . '>' . $GLOBALS['LANG']->getLL('label.type.recurring') . '</option>' . '</select>'; $tableLayout[$tr] = array ( 'tr' => array('<tr id="task_type_row">', '</tr>'), 'defCol' => $defaultCell, '0' => array('<td class="td-label">', '</td>'), ); $tr++; // Start date/time field // NOTE: datetime fields need a special id naming scheme $label = '<label for="tceforms-datetimefield-task_start">' . $GLOBALS['LANG']->getLL('label.start') . '</label>'; $table[$tr][] = t3lib_BEfunc::wrapInHelp($this->cshKey, 'task_start', $label); $table[$tr][] = '<input name="tx_scheduler[start]" type="text" id="tceforms-datetimefield-task_start" value="' . ((empty($taskInfo['start'])) ? '' : strftime('%H:%M %d-%m-%Y', $taskInfo['start'])) . '" />' . t3lib_iconWorks::getSpriteIcon( 'actions-edit-pick-date', array( 'style' => 'cursor:pointer;', 'id' => 'picker-tceforms-datetimefield-task_start' ) ); $tableLayout[$tr] = array ( 'tr' => array('<tr id="task_start_row">', '</tr>'), 'defCol' => $defaultCell, '0' => array('<td class="td-label">', '</td>') ); $tr++; // End date/time field // NOTE: datetime fields need a special id naming scheme $label = '<label for="tceforms-datetimefield-task_end">' . $GLOBALS['LANG']->getLL('label.end') . '</label>'; $table[$tr][] = t3lib_BEfunc::wrapInHelp($this->cshKey, 'task_end', $label); $table[$tr][] = '<input name="tx_scheduler[end]" type="text" id="tceforms-datetimefield-task_end" value="' . ((empty($taskInfo['end'])) ? '' : strftime('%H:%M %d-%m-%Y', $taskInfo['end'])) . '" />' . t3lib_iconWorks::getSpriteIcon( 'actions-edit-pick-date', array( 'style' => 'cursor:pointer;', 'id' => 'picker-tceforms-datetimefield-task_end' ) ); $tableLayout[$tr] = array ( 'tr' => array('<tr id="task_end_row"' . $style . '>', '</tr>'), 'defCol' => $defaultCell, '0' => array('<td class="td-label">', '</td>'), ); $tr++; // Frequency input field $label = '<label for="task_frequency">' . $GLOBALS['LANG']->getLL('label.frequency.long') . '</label>'; $table[$tr][] = t3lib_BEfunc::wrapInHelp($this->cshKey, 'task_frequency', $label); $cell = '<input type="text" name="tx_scheduler[frequency]" id="task_frequency" value="' . $taskInfo['frequency'] . '" />'; $table[$tr][] = $cell; $tableLayout[$tr] = array ( 'tr' => array('<tr id="task_frequency_row"' . $style . '>', '</tr>'), 'defCol' => $defaultCell, '0' => array('<td class="td-label">', '</td>'), ); $tr++; // Multiple execution selector $label = '<label for="task_multiple">' . $GLOBALS['LANG']->getLL('label.parallel.long') . '</label>'; $table[$tr][] = t3lib_BEfunc::wrapInHelp($this->cshKey, 'task_multiple', $label); $table[$tr][] = '<input type="hidden" name="tx_scheduler[multiple]" value="0" /> <input type="checkbox" name="tx_scheduler[multiple]" value="1" id="task_multiple"' . ($taskInfo['multiple'] == 1 ? ' checked="checked"' : '') . ' />'; $tableLayout[$tr] = array ( 'tr' => array('<tr id="task_multiple_row"' . $style . '>', '</tr>'), 'defCol' => $defaultCell, '0' => array('<td class="td-label">', '</td>') ); $tr++; // Display additional fields foreach ($allAdditionalFields as $class => $fields) { if ($class == $taskInfo['class']) { $additionalFieldsStyle = ''; } else { $additionalFieldsStyle = ' style="display: none"'; } // Add each field to the display, if there are indeed any if (isset($fields) && is_array($fields)) { foreach ($fields as $fieldID => $fieldInfo) { $label = '<label for="' . $fieldID . '">' . $GLOBALS['LANG']->sL($fieldInfo['label']) . '</label>'; $table[$tr][] = t3lib_BEfunc::wrapInHelp($fieldInfo['cshKey'], $fieldInfo['cshLabel'], $label); $table[$tr][] = $fieldInfo['code']; $tableLayout[$tr] = array ( 'tr' => array('<tr id="' . $fieldID . '_row"' . $additionalFieldsStyle .' class="extraFields extra_fields_' . $class . '">', '</tr>'), 'defCol' => $defaultCell, '0' => array('<td class="td-label">', '</td>') ); $tr++; } } } // Render the add/edit task form $content .= '<div style="float: left;"><div class="typo3-dyntabmenu-divs">'; $content .= $this->doc->table($table, $tableLayout); $content .= '</div></div>'; $content .= '<div style="padding-top: 20px; clear: both;"></div><div><input type="submit" name="save" class="button" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:save', TRUE) . '" /> ' . '<input type="button" name="cancel" class="button" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:cancel', TRUE) . '" onclick="document.location=\'' . $GLOBALS['MCONF']['_'] . '\'" /></div>'; // Display information about server time usage $content .= $this->displayServerTime(); return $content; } /** * Execute all selected tasks * * @return void */ protected function executeTasks() { // Continue if some elements have been chosen for execution if (isset($this->submittedData['execute']) && count($this->submittedData['execute']) > 0) { // Get list of registered classes $registeredClasses = self::getRegisteredClasses(); // Loop on all selected tasks foreach ($this->submittedData['execute'] as $uid) { try { // Try fetching the task $task = $this->scheduler->fetchTask($uid); $class = get_class($task); $name = $registeredClasses[$class]['title']. ' (' . $registeredClasses[$class]['extension'] . ')'; // Now try to execute it and report on outcome try { $result = $this->scheduler->executeTask($task); if ($result) { $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.executed'), $name)); } else { $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.notExecuted'), $name), t3lib_FlashMessage::ERROR); } } catch (Exception $e) { // An exception was thrown, display its message as an error $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.executionFailed'), $name, $e->getMessage()), t3lib_FlashMessage::ERROR); } } // The task was not found, for some reason catch (OutOfBoundsException $e) { $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.taskNotFound'), $uid), t3lib_FlashMessage::ERROR); } // The task object was not valid catch (UnexpectedValueException $e) { $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.executionFailed'), $name, $e->getMessage()), t3lib_FlashMessage::ERROR); } } // Record the run in the system registry $this->scheduler->recordLastRun('manual'); // Make sure to switch to list view after execution $this->CMD = 'list'; } } /** * Assemble display of list of scheduled tasks * * @return string table of waiting schedulings */ protected function listTasks() { // Define display format for dates $dateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] . ' ' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm']; $content = ''; // Get list of registered classes $registeredClasses = self::getRegisteredClasses(); // Get all registered tasks $query = array( 'SELECT' => '*', 'FROM' => 'tx_scheduler_task', 'WHERE' => '1=1', 'ORDERBY' => 'nextexecution' ); $res = $GLOBALS['TYPO3_DB']->exec_SELECT_queryArray($query); $numRows = $GLOBALS['TYPO3_DB']->sql_num_rows($res); // No tasks defined, display information message if ($numRows == 0) { /** @var t3lib_FlashMessage $flashMessage */ $flashMessage = t3lib_div::makeInstance('t3lib_FlashMessage', $GLOBALS['LANG']->getLL('msg.noTasks'), '', t3lib_FlashMessage::INFO ); $content .= $flashMessage->render(); } else { // Load ExtJS framework and specific JS library /** @var $pageRenderer t3lib_PageRenderer */ $pageRenderer = $this->doc->getPageRenderer(); $pageRenderer->loadExtJS(); $pageRenderer->addJsFile(t3lib_extMgm::extRelPath('scheduler') . 'res/tx_scheduler_be.js'); // Initialise table layout $tableLayout = array( 'table' => array( '<table border="0" cellspacing="1" cellpadding="2" class="typo3-dblist">', '</table>' ), '0' => array( 'tr' => array('<tr class="t3-row-header">', '</tr>'), 'defCol' => array('<td>', '</td>'), '1' => array('<td style="width: 36px;">', '</td>'), '3' => array('<td colspan="2">', '</td>'), ), 'defRow' => array( 'tr' => array('<tr class="db_list_normal">', '</tr>'), 'defCol' => array('<td>', '</td>'), '1' => array('<td class="right">', '</td>'), '2' => array('<td class="right">', '</td>'), ) ); $disabledTaskRow = array ( 'tr' => array('<tr class="db_list_normal disabled">', '</tr>'), 'defCol' => array('<td>', '</td>'), '1' => array('<td class="right">', '</td>'), '2' => array('<td class="right">', '</td>'), ); $rowWithSpan = array ( 'tr' => array('<tr class="db_list_normal">', '</tr>'), 'defCol' => array('<td>', '</td>'), '1' => array('<td class="right">', '</td>'), '2' => array('<td class="right">', '</td>'), '3' => array('<td colspan="6">', '</td>'), ); $table = array(); $tr = 0; // Header row $table[$tr][] = '<a href="#" onclick="toggleCheckboxes();" title="' . $GLOBALS['LANG']->getLL('label.checkAll', TRUE) . '" class="icon">' . t3lib_iconWorks::getSpriteIcon('actions-document-select') . '</a>'; $table[$tr][] = ' '; $table[$tr][] = $GLOBALS['LANG']->getLL('label.id'); $table[$tr][] = $GLOBALS['LANG']->getLL('task'); $table[$tr][] = $GLOBALS['LANG']->getLL('label.type'); $table[$tr][] = $GLOBALS['LANG']->getLL('label.frequency'); $table[$tr][] = $GLOBALS['LANG']->getLL('label.parallel'); $table[$tr][] = $GLOBALS['LANG']->getLL('label.lastExecution'); $table[$tr][] = $GLOBALS['LANG']->getLL('label.nextExecution'); $tr++; // Loop on all tasks while (($schedulerRecord = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))) { // Define action icons $editAction = '<a href="' . $GLOBALS['MCONF']['_'] . '&CMD=edit&tx_scheduler[uid]=' . $schedulerRecord['uid'] . '" title="'.$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:edit', TRUE) . '" class="icon">' . t3lib_iconWorks::getSpriteIcon('actions-document-open') . '</a>'; $deleteAction = '<a href="' . $GLOBALS['MCONF']['_'] . '&CMD=delete&tx_scheduler[uid]=' . $schedulerRecord['uid'] . '" onclick="return confirm(\'' . $GLOBALS['LANG']->getLL('msg.delete') . '\');" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:delete', TRUE) . '" class="icon">' . t3lib_iconWorks::getSpriteIcon('actions-edit-delete') . '</a>'; $stopAction = '<a href="' . $GLOBALS['MCONF']['_'] . '&CMD=stop&tx_scheduler[uid]=' . $schedulerRecord['uid'] . '" onclick="return confirm(\'' . $GLOBALS['LANG']->getLL('msg.stop') . '\');" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:stop', TRUE) . '" class="icon"><img ' . t3lib_iconWorks::skinImg($this->backPath, t3lib_extMgm::extRelPath('scheduler') . '/res/gfx/stop.png') . ' alt="'.$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:stop') . '" /></a>'; // Define some default values $lastExecution = '-'; $isRunning = false; $executionStatus = 'scheduled'; $executionStatusOutput = ''; $name = ''; $nextDate = '-'; $execType = '-'; $frequency = '-'; $multiple = '-'; $startExecutionElement = ' '; // Restore the serialized task and pass it a reference to the scheduler object $task = unserialize($schedulerRecord['serialized_task_object']); // Assemble information about last execution $context = ''; if (!empty($schedulerRecord['lastexecution_time'])) { $lastExecution = date($dateFormat, $schedulerRecord['lastexecution_time']); if ($schedulerRecord['lastexecution_context'] == 'CLI') { $context = $GLOBALS['LANG']->getLL('label.cron'); } else { $context = $GLOBALS['LANG']->getLL('label.manual'); } $lastExecution .= ' (' . $context . ')'; } if ($this->scheduler->isValidTaskObject($task)) { // The task object is valid $name = htmlspecialchars($registeredClasses[$schedulerRecord['classname']]['title']. ' (' . $registeredClasses[$schedulerRecord['classname']]['extension'] . ')'); $additionalInformation = $task->getAdditionalInformation(); if (!empty($additionalInformation)) { $name .= '<br />[' . htmlspecialchars($additionalInformation) . ']'; } // Check if task currently has a running execution if (!empty($schedulerRecord['serialized_executions'])) { $isRunning = true; $executionStatus = 'running'; } // Prepare display of next execution date // If task is currently running, date is not displayed (as next hasn't been calculated yet) // Also hide the date if task is disabled (the information doesn't make sense, as it will not run anyway) if ($isRunning || $schedulerRecord['disable'] == 1) { $nextDate = '-'; } else { $nextDate = date($dateFormat, $schedulerRecord['nextexecution']); if (empty($schedulerRecord['nextexecution'])) { $nextDate = $GLOBALS['LANG']->getLL('none'); } elseif ($schedulerRecord['nextexecution'] < $GLOBALS['EXEC_TIME']) { // Next execution is overdue, highlight date $nextDate = '<span class="late" title="' . $GLOBALS['LANG']->getLL('status.legend.scheduled') . '">' . $nextDate . '</span>'; $executionStatus = 'late'; } } // Get execution type if ($task->getExecution()->getInterval() == 0 && $task->getExecution()->getCronCmd() == '') { $execType = $GLOBALS['LANG']->getLL('label.type.single'); $frequency = '-'; } else { $execType = $GLOBALS['LANG']->getLL('label.type.recurring'); if ($task->getExecution()->getCronCmd() == '') { $frequency = $task->getExecution()->getInterval(); } else { $frequency = $task->getExecution()->getCronCmd(); } } // Get multiple executions setting if ($task->getExecution()->getMultiple()) { $multiple = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:yes'); } else { $multiple = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:no'); } // Define checkbox $startExecutionElement = '<input type="checkbox" name="tx_scheduler[execute][]" value="' . $schedulerRecord['uid'] . '" id="task_' . $schedulerRecord['uid'] . '" class="checkboxes" />'; // Show no action links (edit, delete) if task is running $actions = $editAction . $deleteAction; if ($isRunning) { $actions = $stopAction; } // Check the disable status // Row is shown dimmed if task is disabled, unless it is still running if ($schedulerRecord['disable'] == 1 && !$isRunning) { $tableLayout[$tr] = $disabledTaskRow; $executionStatus = 'disabled'; } // Check if the last run failed $failureOutput = ''; if (!empty($schedulerRecord['lastexecution_failure'])) { // Try to get the stored exception object $exception = unserialize($schedulerRecord['lastexecution_failure']); // If the exception could not be unserialized, issue a default error message if ($exception === FALSE) { $failureDetail = $GLOBALS['LANG']->getLL('msg.executionFailureDefault'); } else { $failureDetail = sprintf($GLOBALS['LANG']->getLL('msg.executionFailureReport'), $exception->getCode(), $exception->getMessage()); } $failureOutput = ' <img ' . t3lib_iconWorks::skinImg(t3lib_extMgm::extRelPath('scheduler'), 'res/gfx/status_failure.png') . ' alt="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.failure')) . '" title="' . htmlspecialchars($failureDetail) . '" />'; } // Format the execution status, // including failure feedback, if any $executionStatusOutput = '<img ' . t3lib_iconWorks::skinImg(t3lib_extMgm::extRelPath('scheduler'), 'res/gfx/status_' . $executionStatus . '.png') . ' id="executionstatus_' . $schedulerRecord['uid'] . '" alt="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.' . $executionStatus)) . '" title="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.legend.' . $executionStatus)) . '" />' . $failureOutput; $table[$tr][] = $startExecutionElement; $table[$tr][] = $actions; $table[$tr][] = $schedulerRecord['uid']; $table[$tr][] = $executionStatusOutput; $table[$tr][] = $name; $table[$tr][] = $execType; $table[$tr][] = $frequency; $table[$tr][] = $multiple; $table[$tr][] = $lastExecution; $table[$tr][] = $nextDate; } else { // The task object is not valid // Prepare to issue an error /** @var t3lib_FlashMessage $flashMessage */ $flashMessage = t3lib_div::makeInstance('t3lib_FlashMessage', sprintf($GLOBALS['LANG']->getLL('msg.invalidTaskClass'), $schedulerRecord['classname']), '', t3lib_FlashMessage::ERROR ); $executionStatusOutput = $flashMessage->render(); $tableLayout[$tr] = $rowWithSpan; $table[$tr][] = $startExecutionElement; $table[$tr][] = $deleteAction; $table[$tr][] = $schedulerRecord['uid']; $table[$tr][] = $executionStatusOutput; } $tr++; } // Render table $content .= $this->doc->table($table, $tableLayout); $content .= '<input type="submit" class="button" name="go" id="scheduler_executeselected" value="' . $GLOBALS['LANG']->getLL('label.executeSelected') . '" />'; } if (count($registeredClasses) > 0) { // Display add new task link $link = $GLOBALS['MCONF']['_'] . '&CMD=add'; $content .= '<p><a href="' . htmlspecialchars($link) .'"><img ' . t3lib_iconWorks::skinImg($this->backPath, 'gfx/new_el.gif') . ' alt="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:new', TRUE) . '" /> ' . $GLOBALS['LANG']->getLL('action.add') . '</a></p>'; } else { /** @var t3lib_FlashMessage $flashMessage */ $flashMessage = t3lib_div::makeInstance('t3lib_FlashMessage', $GLOBALS['LANG']->getLL('msg.noTasksDefined'), '', t3lib_FlashMessage::INFO ); $content .= $flashMessage->render(); } // Display legend, if there's at least one registered task // Also display information about the usage of server time if ($numRows > 0) { $content .= $this->doc->spacer(20); $content .= '<h4>' . $GLOBALS['LANG']->getLL('status.legend') . '</h4> <ul> <li><img ' . t3lib_iconWorks::skinImg(t3lib_extMgm::extRelPath('scheduler'), 'res/gfx/status_failure.png') . ' alt="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.failure')) . '" title="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.failure')) . '" /> ' . $GLOBALS['LANG']->getLL('status.legend.failure') . '</li> <li><img ' . t3lib_iconWorks::skinImg(t3lib_extMgm::extRelPath('scheduler'), 'res/gfx/status_late.png') . ' alt="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.late')) . '" title="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.late')) . '" /> ' . $GLOBALS['LANG']->getLL('status.legend.late') . '</li> <li><img ' . t3lib_iconWorks::skinImg(t3lib_extMgm::extRelPath('scheduler'), 'res/gfx/status_running.png') . ' alt="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.running')) . '" title="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.running')) . '" /> ' . $GLOBALS['LANG']->getLL('status.legend.running') . '</li> <li><img ' . t3lib_iconWorks::skinImg(t3lib_extMgm::extRelPath('scheduler'), 'res/gfx/status_scheduled.png') . ' alt="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.scheduled')) . '" title="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.scheduled')) . '" /> ' . $GLOBALS['LANG']->getLL('status.legend.scheduled') . '</li> <li><img ' . t3lib_iconWorks::skinImg(t3lib_extMgm::extRelPath('scheduler'), 'res/gfx/status_disabled.png') . ' alt="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.disabled')) . '" title="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.disabled')) . '" /> ' . $GLOBALS['LANG']->getLL('status.legend.disabled') . '</li> </ul>'; $content .= $this->doc->spacer(10); $content .= $this->displayServerTime(); } $GLOBALS['TYPO3_DB']->sql_free_result($res); return $content; } /** * Saves a task specified in the backend form to the database * * @return void */ protected function saveTask() { // If a task is being edited fetch old task data if (!empty($this->submittedData['uid'])) { try { $taskRecord = $this->scheduler->fetchTaskRecord($this->submittedData['uid']); /** * @var tx_scheduler_Task */ $task = unserialize($taskRecord['serialized_task_object']); } catch (OutOfBoundsException $e) { // If the task could not be fetched, issue an error message // and exit early $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.taskNotFound'), $this->submittedData['uid']), t3lib_FlashMessage::ERROR); return; } // Register single execution if ($this->submittedData['type'] == 1) { $task->registerSingleExecution($this->submittedData['start']); // Else, it's a recurring task } else { if (!empty($this->submittedData['croncmd'])) { // Definition by cron-like syntax $interval = 0; $cronCmd = $this->submittedData['croncmd']; } else { // Definition by interval $interval = $this->submittedData['interval']; $cronCmd = ''; } // Register recurring execution $task->registerRecurringExecution($this->submittedData['start'], $interval, $this->submittedData['end'], $this->submittedData['multiple'], $cronCmd); } // Set disable flag $task->setDisabled($this->submittedData['disable']); // Save additional input values if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields'])) { $providerObject = t3lib_div::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields']); if ($providerObject instanceof tx_scheduler_AdditionalFieldProvider) { $providerObject->saveAdditionalFields($this->submittedData, $task); } } // Save to database $result = $this->scheduler->saveTask($task); if ($result) { $this->addMessage($GLOBALS['LANG']->getLL('msg.updateSuccess')); } else { $this->addMessage($GLOBALS['LANG']->getLL('msg.updateError'), t3lib_FlashMessage::ERROR); } } else { // A new task is being created // Create an instance of chosen class $task = t3lib_div::makeInstance($this->submittedData['class']); if ($this->submittedData['type'] == 1) { // Set up single execution $task->registerSingleExecution($this->submittedData['start']); } else { // Set up recurring execution $task->registerRecurringExecution($this->submittedData['start'], $this->submittedData['interval'], $this->submittedData['end'], $this->submittedData['multiple'], $this->submittedData['croncmd']); } // Save additional input values if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields'])) { $providerObject = t3lib_div::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields']); if ($providerObject instanceof tx_scheduler_AdditionalFieldProvider) { $providerObject->saveAdditionalFields($this->submittedData, $task); } } // Set disable flag $task->setDisabled($this->submittedData['disable']); // Add to database $result = $this->scheduler->addTask($task); if ($result) { $this->addMessage($GLOBALS['LANG']->getLL('msg.addSuccess')); } else { $this->addMessage($GLOBALS['LANG']->getLL('msg.addError'), t3lib_FlashMessage::ERROR); } } } /************************* * * INPUT PROCESSING UTILITIES * *************************/ /** * Checks the submitted data and performs some preprocessing on it * * @return boolean True if everything was ok, false otherwise */ protected function preprocessData() { $result = true; // Validate id $this->submittedData['uid'] = (empty($this->submittedData['uid'])) ? 0 : intval($this->submittedData['uid']); // Validate selected task class if (!class_exists($this->submittedData['class'])) { $this->addMessage($GLOBALS['LANG']->getLL('msg.noTaskClassFound'), t3lib_FlashMessage::ERROR); } // Check start date if (empty($this->submittedData['start'])) { $this->addMessage($GLOBALS['LANG']->getLL('msg.noStartDate'), t3lib_FlashMessage::ERROR); $result = false; } else { try { $timestamp = $this->checkDate($this->submittedData['start']); $this->submittedData['start'] = $timestamp; } catch (Exception $e) { $this->addMessage($GLOBALS['LANG']->getLL('msg.invalidStartDate'), t3lib_FlashMessage::ERROR); $result = false; } } // Check end date, if recurring task if ($this->submittedData['type'] == 2 && !empty($this->submittedData['end'])) { try { $timestamp = $this->checkDate($this->submittedData['end']); $this->submittedData['end'] = $timestamp; if ($this->submittedData['end'] < $this->submittedData['start']) { $this->addMessage($GLOBALS['LANG']->getLL('msg.endDateSmallerThanStartDate'), t3lib_FlashMessage::ERROR); $result = false; } } catch (Exception $e) { $this->addMessage($GLOBALS['LANG']->getLL('msg.invalidEndDate'), t3lib_FlashMessage::ERROR); $result = false; } } // Set default values for interval and cron command $this->submittedData['interval'] = 0; $this->submittedData['croncmd'] = ''; // Check type and validity of frequency, if recurring if ($this->submittedData['type'] == 2) { $frequency = trim($this->submittedData['frequency']); if (empty($frequency)) { // Empty frequency, not valid $this->addMessage($GLOBALS['LANG']->getLL('msg.noFrequency'), t3lib_FlashMessage::ERROR); $result = FALSE; } else { $cronErrorCode = 0; $cronErrorMessage = ''; // Try interpreting the cron command try { tx_scheduler_CronCmd_Normalize::normalize($frequency); $this->submittedData['croncmd'] = $frequency; } // If the cron command was invalid, we may still have a valid frequency in seconds catch (Exception $e) { // Store the exception's result $cronErrorMessage = $e->getMessage(); $cronErrorCode = $e->getCode(); // Check if the frequency is a valid number // If yes, assume it is a frequency in seconds, and unset cron error code if (is_numeric($frequency)) { $this->submittedData['interval'] = intval($frequency); unset($cronErrorCode); } } // If there's a cron error code, issue validation error message if (!empty($cronErrorCode)) { $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.frequencyError'), $cronErrorMessage, $cronErrorCode), t3lib_FlashMessage::ERROR); $result = FALSE; } } } // Validate additional input fields if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields'])) { $providerObject = t3lib_div::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields']); if ($providerObject instanceof tx_scheduler_AdditionalFieldProvider) { // The validate method will return true if all went well, but that must not // override previous false values => AND the returned value with the existing one $result &= $providerObject->validateAdditionalFields($this->submittedData, $this); } } return $result; } /** * This method checks whether the given string can be considered a valid date or not * Allowed values are anything that matches natural language (see PHP function strtotime()) * or TYPO3's date syntax: HH:ii yyyy-mm-dd * If the string is a valid date, the corresponding timestamp is returned. * Otherwise an exception is thrown * * @param string $string: string to check * @return integer Unix timestamp */ protected function checkDate($string) { // Try with strtotime $timestamp = strtotime($string); // That failed. Try TYPO3's standard date/time input format if ($timestamp === false) { // Split time and date $dateParts = t3lib_div::trimExplode(' ', $string, true); // Proceed if there are indeed two parts // Extract each component of date and time if (count($dateParts) == 2) { list($time, $date) = $dateParts; list($hour, $minutes) = t3lib_div::trimExplode(':', $time, true); list($day, $month, $year) = t3lib_div::trimExplode('-', $date, true); // Get a timestamp from all these parts $timestamp = mktime($hour, $minutes, 0, $month, $day, $year); } // If the timestamp is still false, throw an exception if ($timestamp === false) { throw new Exception; } } return $timestamp; } /************************* * * APPLICATION LOGIC UTILITIES * *************************/ /** * This method is used to add a message to the internal queue * * @param string the message itself * @param integer message level (-1 = success (default), 0 = info, 1 = notice, 2 = warning, 3 = error) * @return void */ public function addMessage($message, $severity = t3lib_FlashMessage::OK) { $message = t3lib_div::makeInstance( 't3lib_FlashMessage', $message, '', $severity ); t3lib_FlashMessageQueue::addMessage($message); } /** * This method a list of all classes that have been registered with the Scheduler * For each item the following information is provided, as an associative array: * * ['extension'] => Key of the extension which provides the class * ['filename'] => Path to the file containing the class * ['title'] => String (possibly localized) containing a human-readable name for the class * ['provider'] => Name of class that implements the interface for additional fields, if necessary * * The name of the class itself is used as the key of the list array * * @return array List of registered classes */ protected static function getRegisteredClasses() { $list = array(); if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'])) { foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'] as $class => $registrationInformation) { $title = isset($registrationInformation['title']) ? $GLOBALS['LANG']->sL($registrationInformation['title']) : ''; $description = isset($registrationInformation['description']) ? $GLOBALS['LANG']->sL($registrationInformation['description']) : ''; $list[$class] = array( 'extension' => $registrationInformation['extension'], 'title' => $title, 'description' => $description, 'provider' => isset($registrationInformation['additionalFields']) ? $registrationInformation['additionalFields'] : '' ); } } return $list; } /************************* * * RENDERING UTILITIES * *************************/ /** * Gets the filled markers that are used in the HTML template. * * @return array The filled marker array */ protected function getTemplateMarkers() { $markers = array( 'CSH' => t3lib_BEfunc::wrapInHelp('_MOD_tools_txschedulerM1', ''), 'FUNC_MENU' => $this->getFunctionMenu(), 'CONTENT' => $this->content, 'TITLE' => $GLOBALS['LANG']->getLL('title'), ); return $markers; } /** * Gets the function menu selector for this backend module. * * @return string The HTML representation of the function menu selector */ protected function getFunctionMenu() { $functionMenu = t3lib_BEfunc::getFuncMenu( 0, 'SET[function]', $this->MOD_SETTINGS['function'], $this->MOD_MENU['function'] ); return $functionMenu; } /** * Gets the buttons that shall be rendered in the docHeader. * * @return array Available buttons for the docHeader */ protected function getDocHeaderButtons() { $buttons = array( 'reload' => '', 'shortcut' => $this->getShortcutButton(), ); if (empty($this->CMD) || $this->CMD == 'list') { $buttons['reload'] = '<a href="' . $GLOBALS['MCONF']['_'] . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.reload', TRUE) . '">' . t3lib_iconWorks::getSpriteIcon('actions-system-refresh') . '</a>'; } return $buttons; } /** * Gets the button to set a new shortcut in the backend (if current user is allowed to). * * @return string HTML representiation of the shortcut button */ protected function getShortcutButton() { $result = ''; if ($GLOBALS['BE_USER']->mayMakeShortcut()) { $result = $this->doc->makeShortcutIcon('', 'function', $this->MCONF['name']); } return $result; } } if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/scheduler/mod1/index.php'])) { include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/scheduler/mod1/index.php']); } // Make instance: $SOBE = t3lib_div::makeInstance('tx_scheduler_Module'); $SOBE->init(); // Include files? foreach($SOBE->include_once as $INC_FILE) { include_once($INC_FILE); } $SOBE->main(); $SOBE->render(); ?>