bootstrap = true; $this->list_no_link = true; $this->table = 'qctm_cron_task'; $this->className = 'QctmCronTask'; $this->identifier = 'id_cron_task'; $this->_orderBy = 'id_cron_task'; $this->lang = false; $this->_orderWay = 'ASC'; parent::__construct(); // Exclude hidden system tasks from the listing $this->_where = ' AND a.`is_system` = 0'; $this->_join = 'LEFT JOIN ( SELECT ctl.`id_cron_task`, ctl.`date_add` AS `last_run`, ctl.`status` AS `last_status` FROM `' . _DB_PREFIX_ . 'qctm_cron_task_log` ctl INNER JOIN ( SELECT `id_cron_task`, MAX(`id_cron_task_log`) AS `max_id` FROM `' . _DB_PREFIX_ . 'qctm_cron_task_log` GROUP BY `id_cron_task` ) latest ON ctl.`id_cron_task_log` = latest.`max_id` ) AS llog ON (llog.`id_cron_task` = a.`id_cron_task`) LEFT JOIN `' . _DB_PREFIX_ . 'module` m ON (m.`id_module` = a.`id_module`)'; $this->_select = 'm.`name` as `module_name`, llog.`last_run`, llog.`last_status`, a.`cron_expression` AS `next_run_expression`'; $this->addRowAction('viewLogs'); $this->addRowAction('edit'); $this->addRowAction('resetModuleCrons'); $this->bulk_actions = array( 'enableSelection' => array( 'text' => $this->l('Enable selected'), 'icon' => 'icon-power-off text-success', ), 'disableSelection' => array( 'text' => $this->l('Disable selected'), 'icon' => 'icon-power-off text-danger', ), ); $this->fields_list = array( 'id_cron_task' => array( 'title' => $this->l('ID'), 'align' => 'center', 'class' => 'fixed-width-xs', ), 'module_name' => array( 'title' => $this->l('Module Name'), 'filter_key' => 'm!name', 'order_key' => 'm!name', 'callback' => 'displayModuleName', ), 'task_name' => array( 'title' => $this->l('Task Name'), 'filter_key' => 'a!task_name', ), 'cron_expression' => array( 'title' => $this->l('Cron Expression'), 'align' => 'center', 'class' => 'fixed-width-lg', 'search' => false, 'callback' => 'getCronWithReadable', ), 'last_run' => array( 'title' => $this->l('Last Run'), 'align' => 'center', 'filter' => false, 'search' => false, ), 'last_status' => array( 'title' => $this->l('Last Status'), 'align' => 'center', 'filter' => false, 'search' => false, 'callback' => 'getLastStatus', ), 'next_run_expression' => array( 'title' => $this->l('Next Run'), 'align' => 'center', 'filter' => false, 'search' => false, 'callback' => 'getNextRun', ), 'date_add' => array( 'title' => $this->l('Added Time'), 'align' => 'center', 'filter' => false, 'search' => false, ), 'active' => array( 'title' => $this->l('Active'), 'active' => 'status', 'type' => 'bool', 'align' => 'center', 'class' => 'fixed-width-sm', 'filter_key' => 'a!active', ), ); } public function init() { parent::init(); if(!Validate::isUnsignedInt($idCronTask = Tools::getValue('id_cron_task')) && $this->display == 'edit') { $this->errors = array($this->l('Invalid Cron Task ID')); $this->display = 'list'; }else{ if (Validate::isUnsignedInt($idCronTask = Tools::getValue('id_cron_task')) && Validate::isLoadedObject($objCronTask = new QctmCronTask($idCronTask)) && $this->display == 'edit' ) { $this->toolbar_title = $this->l('Edit Cron Task: ') . $objCronTask->task_name; } } } public function initToolbar() { parent::initToolbar(); unset($this->toolbar_btn['new']); if($this->display && $this->display == 'list') { $this->page_header_toolbar_btn['view_all_logs'] = array( 'href' => $this->context->link->getAdminLink('AdminCronTaskLogs'), 'desc' => $this->l('View All Logs'), 'icon' => 'icon-history', ); }else if($this->display && $this->display == 'edit') { $idCronTask = Tools::getValue('id_cron_task'); $this->page_header_toolbar_btn['view_logs'] = array( 'href' => $this->context->link->getAdminLink('AdminCronTaskLogs') . '&id_cron_task=' . (int) $idCronTask, 'desc' => $this->l('View Logs'), 'icon' => 'icon-history', ); } } public function renderForm() { $cronExpression = '* * * * *'; if(Validate::isLoadedObject($this->object)){ $cronExpression = $this->object->cron_expression; } $isValidExpression = \Cron\CronExpression::isValidExpression($cronExpression); if ($isValidExpression) { try { $readable = $this->l('Runs ') . \Lorisleiva\CronTranslator\CronTranslator::translate($cronExpression); } catch (\Exception $e) { $readable = ''; } } else { $readable = $this->l('Invalid cron expression.'); } $moduleDisplayName = ''; if (Validate::isLoadedObject($this->object) && $this->object->id_module) { $module = Module::getInstanceById($this->object->id_module); $moduleDisplayName = ($module && $module->displayName) ? $module->displayName : '#' . (int) $this->object->id_module; } $this->fields_value['module_display_name'] = $moduleDisplayName; $this->context->smarty->assign(array( 'qctmCronExpression' => $cronExpression, 'qctmCronReadable' => $readable, 'qctmAjaxUrl' => $this->context->link->getAdminLink($this->controller_name) . '&ajax=1', )); $this->fields_form = array( 'legend' => array( 'title' => $this->l('Cron Task'), 'icon' => 'icon-time', ), 'input' => array( array( 'type' => 'text', 'label' => $this->l('Module Name'), 'name' => 'module_display_name', 'disabled' => true, 'col' => 5, 'desc' => $this->l('The module that owns this task.'), ), array( 'type' => 'text', 'label' => $this->l('Task Name'), 'name' => 'task_name', 'disabled' => true, 'required' => true, 'col' => 5, 'hint' => $this->l('e.g. send_daily_report'), 'desc' => $this->l('A unique identifier for this task within the module.'), ), array( 'type' => 'text', 'label' => $this->l('Description'), 'name' => 'description', 'required' => true, 'disabled' => true, 'col' => 7, 'hint' => $this->l('e.g. Sends the daily booking summary report'), 'desc' => $this->l('A short human-readable description of what this task does.'), ), array( 'type' => 'text', 'label' => $this->l('Cron Expression'), 'name' => 'cron_expression', 'required' => true, 'col' => 4, 'class' => 'qctm-cron-expression', 'hint' => $this->l('e.g. 0 0 * * *'), 'desc' => $readable, ), array( 'type' => 'html', 'name' => 'qctm_cron_helper', 'html_content' => $this->createTemplate('qctm_cron_expression_helper.tpl')->fetch(), ), array( 'type' => 'switch', 'label' => $this->l('Active'), 'name' => 'active', 'required' => false, 'desc' => $this->l('Disabled tasks are skipped.'), 'values' => array( array('id' => 'active_on', 'value' => 1, 'label' => $this->l('Enabled')), array('id' => 'active_off', 'value' => 0, 'label' => $this->l('Disabled')), ), ), ), 'submit' => array( 'title' => $this->l('Save'), ), ); return parent::renderForm(); } public function ajaxProcessGetCronReadable() { $expression = Tools::getValue('cron_expression'); $result = array('readable' => $this->l('Invalid cron expression'), 'valid' => false); if (\Cron\CronExpression::isValidExpression($expression)) { $result['valid'] = true; try { $result['readable'] = $this->l('Runs ') . \Lorisleiva\CronTranslator\CronTranslator::translate($expression); } catch (\Exception $e) { $result['readable'] = $this->l('Invalid cron expression'); } } die(Tools::jsonEncode($result)); } public function processSave() { if (!$this->validateCronExpression()) { $this->display = 'edit'; return false; } return parent::processSave(); } protected function validateCronExpression() { $cronExpression = Tools::getValue('cron_expression'); if (!\Cron\CronExpression::isValidExpression($cronExpression)) { $this->errors[] = $this->l('Invalid cron expression. Must have exactly 5 parts: minute hour day month weekday. Example: * * * * *'); return false; } return true; } public function processStatus() { return parent::processStatus(); } protected function processBulkEnableSelection() { return parent::processBulkEnableSelection(); } protected function processBulkDisableSelection() { return parent::processBulkDisableSelection(); } public function displayViewLogsLink($token = null, $id = null, $row = array()) { $this->context->smarty->assign( 'viewLogsLink', $this->context->link->getAdminLink('AdminCronTaskLogs') . '&id_cron_task=' . (int) $id ); return $this->createTemplate('qctm_view_logs_link.tpl')->fetch(); } public function displayResetModuleCronsLink($token = null, $id = null, $row = array()) { $this->context->smarty->assign( 'resetLink', $this->context->link->getAdminLink('AdminCronTaskManager') . '&action=resetModuleCrons&' . $this->identifier . '=' . (int) $id ); return $this->createTemplate('qctm_reset_module_crons_link.tpl')->fetch(); } public function processResetModuleCrons() { $idCronTask = (int) Tools::getValue($this->identifier); $cronTask = new QctmCronTask($idCronTask); if (!Validate::isLoadedObject($cronTask)) { $this->errors[] = $this->l('Cron task not found.'); return false; } $module = Module::getInstanceById($cronTask->id_module); if (!$module) { $this->errors[] = $this->l('Module not found.'); return false; } if (!method_exists($module, 'hookRegisterCronTasks')) { $this->errors[] = $this->l('Module does not define any cron tasks.'); return false; } $tasks = $module->hookRegisterCronTasks(); if (empty($tasks) || !is_array($tasks)) { $this->errors[] = $this->l('No tasks returned by module.'); return false; } foreach ($tasks as $task) { if ($task['name'] === $cronTask->task_name) { $cronTask->cron_expression = $task['cron']; $cronTask->description = $task['description']; $cronTask->callback = $task['callback']; if (!$cronTask->save()) { $this->errors[] = $this->l('Failed to reset cron task.'); return false; } $this->confirmations[] = $this->l('Cron task reset to module defaults successfully.'); return true; } } $this->errors[] = $this->l('Task definition not found in module.'); return false; } public function getCronWithReadable($cronExpression, $row) { try { $readable = \Lorisleiva\CronTranslator\CronTranslator::translate($cronExpression); } catch (\Exception $e) { $readable = $cronExpression; } return '' . htmlspecialchars($cronExpression) . '' . '
' . htmlspecialchars($readable) . ''; } public function displayModuleName($moduleName, $row) { $cacheKey = 'displayModuleName_' . $moduleName; if (!Cache::isStored($cacheKey)) { $module = Module::getInstanceByName($moduleName); $displayName = ($module && $module->displayName) ? $module->displayName : $moduleName; Cache::store($cacheKey, $displayName); } return Cache::retrieve($cacheKey); } public function getNextRun($cronExpression, $row) { if (!$cronExpression || !\Cron\CronExpression::isValidExpression($cronExpression)) { return '-'; } try { $next = \Cron\CronExpression::factory($cronExpression)->getNextRunDate(); return $next->format('Y-m-d H:i:s'); } catch (\Exception $e) { return '-'; } } public function getLastStatus($lastStatus, $row) { $this->context->smarty->assign('status', $lastStatus); return $this->createTemplate('qctm_badge_status.tpl')->fetch(); } public function setMedia() { parent::setMedia(); Media::addJsDef( array( 'INVALID_CRON_EXPRESSION' => $this->l('Invalid cron expression.'), ) ); $this->addCSS($this->module->getPathUri() . 'views/css/admin/qlo_cron_task_manager_admin.css'); $this->addJS($this->module->getPathUri() . 'views/js/admin/qlo_cron_task_manager_admin.js'); } }