├── Module.php ├── README.md ├── commands ├── CronController.php └── JobController.php ├── composer.json ├── controllers ├── CronJobController.php └── CronJobRunController.php ├── messages ├── config.php ├── en │ └── vbt-cron.php └── hu │ └── vbt-cron.php ├── migrations ├── m190426_144151_create_cron_job_table.php ├── m190426_144159_create_cron_job_run_table.php └── m190525_122152_add_max_execution_time_column_to_cron_job_table.php ├── models ├── CronJob.php ├── CronJobQuery.php ├── CronJobRun.php ├── CronJobRunQuery.php ├── CronJobRunSearch.php └── CronJobSearch.php └── views ├── cron-job-run └── index.php └── cron-job ├── _form.php ├── create.php ├── index.php └── update.php /Module.php: -------------------------------------------------------------------------------- 1 | controllerNamespace = 'vasadibt\cron\commands'; 47 | } 48 | 49 | $this->registerTranslations(); 50 | $this->configureBsVersion(); 51 | 52 | $this->yiiFile = realpath(\Yii::getAlias($this->yiiFile)); 53 | } 54 | 55 | /** 56 | * Register translations 57 | */ 58 | public function registerTranslations() 59 | { 60 | \Yii::$app->i18n->translations['vbt-cron'] = [ 61 | 'class' => '\yii\i18n\PhpMessageSource', 62 | 'sourceLanguage' => 'en-US', 63 | 'basePath' => '@vasadibt/cron/messages', 64 | ]; 65 | } 66 | 67 | /** 68 | * Validate if Bootstrap 4.x version 69 | * @return bool 70 | */ 71 | public function isBs4() 72 | { 73 | if (!isset($this->_isBs4)) { 74 | $this->configureBsVersion(); 75 | } 76 | return $this->_isBs4; 77 | } 78 | 79 | /** 80 | * Configures the bootstrap version settings 81 | * @return string the bootstrap lib parsed version number 82 | */ 83 | protected function configureBsVersion() 84 | { 85 | $version = empty($this->bsVersion) ? ArrayHelper::getValue(Yii::$app->params, 'bsVersion', '3') : $this->bsVersion; 86 | $version = static::parseVer($version); 87 | $this->_isBs4 = $version === '4'; 88 | return $version; 89 | } 90 | 91 | /** 92 | * Parses and returns the major BS version 93 | * @param string $ver 94 | * @return bool|string 95 | */ 96 | protected static function parseVer($ver) 97 | { 98 | $ver = (string)$ver; 99 | return substr(trim($ver), 0, 1); 100 | } 101 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Yii2 Cron job Manager 2 | ===================== 3 | Create Cron jobs from browser, and look that run logs 4 | 5 | Installation 6 | ------------ 7 | 8 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/). 9 | 10 | Either run 11 | 12 | ``` 13 | php composer.phar require --prefer-dist vasadibt/yii2-cron "*" 14 | ``` 15 | 16 | or add 17 | 18 | ``` 19 | "vasadibt/yii2-cron": "*" 20 | ``` 21 | 22 | to the require section of your `composer.json` file. 23 | 24 | 25 | ### Migration 26 | 27 | Run the following command in Terminal for database migration: 28 | 29 | ``` 30 | yii migrate/up --migrationPath=@vasadibt/cron/migrations 31 | ``` 32 | 33 | Or use the [namespaced migration](http://www.yiiframework.com/doc-2.0/guide-db-migrations.html#namespaced-migrations) (requires at least Yii 2.0.10): 34 | 35 | ```php 36 | // Add namespace to console config: 37 | 'controllerMap' => [ 38 | 'migrate' => [ 39 | 'class' => 'yii\console\controllers\MigrateController', 40 | 'migrationPath' => [ 41 | '@vasadibt/cron/migrations', 42 | ], 43 | ], 44 | ], 45 | ``` 46 | 47 | Then run: 48 | ``` 49 | yii migrate/up 50 | ``` 51 | 52 | ### Web Application Config 53 | 54 | Turning on the Cron Job Manager Module in the web application: 55 | 56 | Simple example: 57 | 58 | ```php 59 | 'modules' => [ 60 | 'cron' => [ 61 | 'class' => 'vasadibt\cron\Module', 62 | ], 63 | ], 64 | ``` 65 | 66 | ### Console Application Config 67 | 68 | Turning on the Cron Job Manager Module in the console application: 69 | 70 | Simple example: 71 | 72 | ```php 73 | 'modules' => [ 74 | 'cron' => [ 75 | 'class' => 'vasadibt\cron\Module', 76 | ], 77 | ], 78 | ``` 79 | 80 | ### Schedule Config 81 | 82 | Set the server schedule to run the following command 83 | 84 | On Linux: 85 | 86 | Add to the crontab with the user who you want to run the script (possibly not root) with the `crontab -e` command or by editing the `/etc/crontab` file 87 | 88 | ```bash 89 | * * * * * /yii cron/cron/run 2>&1 90 | ``` 91 | 92 | On Windows: 93 | 94 | Open the task scheduler and create a new task -------------------------------------------------------------------------------- /commands/CronController.php: -------------------------------------------------------------------------------- 1 | where(['active' => true]) 36 | ->all(); 37 | 38 | echo PHP_EOL; 39 | echo Table::widget([ 40 | 'headers' => ['ID', 'Name', 'Schedule', 'Command', 'Max execution time', 'Active'], 41 | 'rows' => ArrayHelper::getColumn($jobs, function (CronJob $job) { 42 | return [ 43 | $job->id, 44 | $job->name, 45 | $job->schedule, 46 | $job->command, 47 | $job->max_execution_time, 48 | $job->active ? true : false, 49 | ]; 50 | }) 51 | ]); 52 | } 53 | 54 | /** 55 | * Run cron jobs 56 | */ 57 | public function actionRun() 58 | { 59 | foreach (CronJob::findRunnable() as $job) { 60 | if (CronExpression::factory($job->schedule)->isDue()) { 61 | $this->run('/cron/job/run-quick', [$job->id]); 62 | } 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /commands/JobController.php: -------------------------------------------------------------------------------- 1 | run(); 23 | 24 | Console::output('Process is finished, exit code: #' . $run->exit_code); 25 | Console::output($run->output); 26 | if (!empty($run->error_output)) { 27 | Console::output($run->error_output); 28 | } 29 | } 30 | 31 | /** 32 | * @param $id 33 | */ 34 | public function actionRunQuick($id) 35 | { 36 | $job = CronJob::findOne($id); 37 | $job->runQuick(); 38 | Console::output('Job started without wait finish: ' . $job->name); 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vasadibt/yii2-cron", 3 | "description": "Create Cron jobs from browser, and look that run logs", 4 | "type": "yii2-extension", 5 | "keywords": [ 6 | "yii2", 7 | "extension", 8 | "cron", 9 | "schedule", 10 | "module" 11 | ], 12 | "license": "MIT", 13 | "authors": [ 14 | { 15 | "name": "vasadibt", 16 | "email": "vasadibt@gmail.com" 17 | } 18 | ], 19 | "require": { 20 | "yiisoft/yii2": "~2.0.0", 21 | "symfony/process": "^4.2", 22 | "mtdowling/cron-expression": "^1.2", 23 | "kartik-v/yii2-grid": "@dev" 24 | }, 25 | "autoload": { 26 | "psr-4": { 27 | "vasadibt\\cron\\": "" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /controllers/CronJobController.php: -------------------------------------------------------------------------------- 1 | [ 24 | 'class' => VerbFilter::class, 25 | 'actions' => [ 26 | 'delete' => ['POST'], 27 | ], 28 | ], 29 | ]; 30 | } 31 | 32 | /** 33 | * Lists all CronJob models. 34 | * @return mixed 35 | */ 36 | public function actionIndex() 37 | { 38 | $searchModel = new CronJobSearch(); 39 | $dataProvider = $searchModel->search(Yii::$app->request->queryParams); 40 | 41 | return $this->render('index', [ 42 | 'searchModel' => $searchModel, 43 | 'dataProvider' => $dataProvider, 44 | ]); 45 | } 46 | 47 | /** 48 | * Creates a new CronJob model. 49 | * If creation is successful, the browser will be redirected to the 'view' page. 50 | * @return mixed 51 | */ 52 | public function actionCreate() 53 | { 54 | $model = new CronJob(); 55 | $model->loadDefaultValues(); 56 | 57 | if ($model->load(Yii::$app->request->post())) { 58 | $model->active = (bool)$model->active; 59 | $model->save(); 60 | return $this->redirect(['update', 'id' => $model->id]); 61 | } 62 | 63 | return $this->render('create', [ 64 | 'model' => $model, 65 | ]); 66 | } 67 | 68 | /** 69 | * Updates an existing CronJob model. 70 | * If update is successful, the browser will be redirected to the 'view' page. 71 | * @param integer $id 72 | * @return mixed 73 | * @throws NotFoundHttpException if the model cannot be found 74 | */ 75 | public function actionUpdate($id) 76 | { 77 | $model = $this->findModel($id); 78 | 79 | if ($model->load(Yii::$app->request->post())) { 80 | $model->active = (bool)$model->active; 81 | $model->save(); 82 | return $this->refresh(); 83 | } 84 | 85 | return $this->render('update', [ 86 | 'model' => $model, 87 | ]); 88 | } 89 | 90 | /** 91 | * Deletes an existing CronJob model. 92 | * If deletion is successful, the browser will be redirected to the 'index' page. 93 | * @param integer $id 94 | * @return mixed 95 | * @throws NotFoundHttpException if the model cannot be found 96 | * @throws \Throwable 97 | * @throws \yii\db\StaleObjectException 98 | */ 99 | public function actionDelete($id) 100 | { 101 | $this->findModel($id)->delete(); 102 | 103 | return $this->redirect(['index']); 104 | } 105 | 106 | /** 107 | * Finds the CronJob model based on its primary key value. 108 | * If the model is not found, a 404 HTTP exception will be thrown. 109 | * @param integer $id 110 | * @return CronJob the loaded model 111 | * @throws NotFoundHttpException if the model cannot be found 112 | */ 113 | protected function findModel($id) 114 | { 115 | if (($model = CronJob::findOne($id)) !== null) { 116 | return $model; 117 | } 118 | 119 | throw new NotFoundHttpException(Yii::t('vbt-cron', 'The requested page does not exist.')); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /controllers/CronJobRunController.php: -------------------------------------------------------------------------------- 1 | search(Yii::$app->request->queryParams); 22 | $dataProvider->sort->defaultOrder = ['start' => SORT_DESC]; 23 | 24 | return $this->render('index', [ 25 | 'searchModel' => $searchModel, 26 | 'dataProvider' => $dataProvider, 27 | ]); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /messages/config.php: -------------------------------------------------------------------------------- 1 | __DIR__ . DIRECTORY_SEPARATOR . '..', 6 | // array, required, list of language codes that the extracted messages 7 | // should be translated to. For example, ['zh-CN', 'de']. 8 | 'languages' => [ 9 | 'en', 10 | 'hu', 11 | ], 12 | // string, the name of the function for translating messages. 13 | // Defaults to 'Yii::t'. This is used as a mark to find the messages to be 14 | // translated. You may use a string for single function name or an array for 15 | // multiple function names. 16 | 'translator' => 'Yii::t', 17 | // boolean, whether to sort messages by keys when merging new messages 18 | // with the existing ones. Defaults to false, which means the new (untranslated) 19 | // messages will be separated from the old (translated) ones. 20 | 'sort' => false, 21 | // boolean, whether to remove messages that no longer appear in the source code. 22 | // Defaults to false, which means these messages will NOT be removed. 23 | 'removeUnused' => false, 24 | // boolean, whether to mark messages that no longer appear in the source code. 25 | // Defaults to true, which means each of these messages will be enclosed with a pair of '@@' marks. 26 | 'markUnused' => true, 27 | // array, list of patterns that specify which files (not directories) should be processed. 28 | // If empty or not set, all files will be processed. 29 | // See helpers/FileHelper::findFiles() for pattern matching rules. 30 | // If a file/directory matches both a pattern in "only" and "except", it will NOT be processed. 31 | 'only' => ['*.php'], 32 | // array, list of patterns that specify which files/directories should NOT be processed. 33 | // If empty or not set, all files/directories will be processed. 34 | // See helpers/FileHelper::findFiles() for pattern matching rules. 35 | // If a file/directory matches both a pattern in "only" and "except", it will NOT be processed. 36 | 'except' => [ 37 | '.svn', 38 | '.git', 39 | '.gitignore', 40 | '.gitkeep', 41 | '.hgignore', 42 | '.hgkeep', 43 | '/messages', 44 | ], 45 | 46 | // 'php' output format is for saving messages to php files. 47 | 'format' => 'php', 48 | // Root directory containing message translations. 49 | 'messagePath' => __DIR__, 50 | // boolean, whether the message file should be overwritten with the merged messages 51 | 'overwrite' => true, 52 | /* 53 | // File header used in generated messages files 54 | 'phpFileHeader' => '', 55 | // PHPDoc used for array of messages with generated messages files 56 | 'phpDocBlock' => null, 57 | */ 58 | 59 | /* 60 | // Message categories to ignore 61 | 'ignoreCategories' => [ 62 | 'yii', 63 | ], 64 | */ 65 | 66 | /* 67 | // 'db' output format is for saving messages to database. 68 | 'format' => 'db', 69 | // Connection component to use. Optional. 70 | 'db' => 'db', 71 | // Custom source message table. Optional. 72 | // 'sourceMessageTable' => '{{%source_message}}', 73 | // Custom name for translation message table. Optional. 74 | // 'messageTable' => '{{%message}}', 75 | */ 76 | 77 | /* 78 | // 'po' output format is for saving messages to gettext po files. 79 | 'format' => 'po', 80 | // Root directory containing message translations. 81 | 'messagePath' => __DIR__ . DIRECTORY_SEPARATOR . 'messages', 82 | // Name of the file that will be used for translations. 83 | 'catalog' => 'messages', 84 | // boolean, whether the message file should be overwritten with the merged messages 85 | 'overwrite' => true, 86 | */ 87 | ]; 88 | -------------------------------------------------------------------------------- /messages/en/vbt-cron.php: -------------------------------------------------------------------------------- 1 | 'Active', 21 | 'Command' => 'Command', 22 | 'Create Cron Job' => 'Create cron job', 23 | 'Cron Job Runs' => 'Cron job runs', 24 | 'Cron Jobs' => 'Cron jobs', 25 | 'Error Output' => 'Error output', 26 | 'Exit Code' => 'Exit code', 27 | 'Finish' => 'Finish', 28 | 'ID' => 'ID', 29 | 'In Progress' => 'In progress', 30 | 'Job' => 'Job', 31 | 'Last' => 'Last', 32 | 'Logs' => 'Logs', 33 | 'Name' => 'Name', 34 | 'Output' => 'Output', 35 | 'Pid' => 'Pid', 36 | 'Reset' => 'Reset', 37 | 'Runtime' => 'Runtime', 38 | 'Save' => 'Save', 39 | 'Schedule' => 'Schedule', 40 | 'Start' => 'Start', 41 | 'Success' => 'Success', 42 | 'The requested page does not exist.' => 'The requested page does not exist.', 43 | 'Update' => 'Update', 44 | 'Update Cron Job: {nameAttribute}' => 'Update cron job: {nameAttribute}', 45 | 'Max execution time' => 'Max execution time', 46 | ]; 47 | -------------------------------------------------------------------------------- /messages/hu/vbt-cron.php: -------------------------------------------------------------------------------- 1 | 'Aktív', 21 | 'Command' => 'Parancs', 22 | 'Create Cron Job' => 'Cron feladat létrehozása', 23 | 'Cron Job Runs' => 'Cron feladat futások', 24 | 'Cron Jobs' => 'Cron feladatok', 25 | 'Error Output' => 'Hiba kimenet', 26 | 'Exit Code' => 'Kimeneti kód', 27 | 'Finish' => 'Befejezés', 28 | 'ID' => 'ID', 29 | 'In Progress' => 'Folyamatban', 30 | 'Job' => 'Feladat', 31 | 'Last' => 'Utolsó', 32 | 'Logs' => 'Logok', 33 | 'Name' => 'Név', 34 | 'Output' => 'Kimenet', 35 | 'Pid' => 'PID', 36 | 'Reset' => 'Visszaállítás', 37 | 'Runtime' => 'Futási idő', 38 | 'Save' => 'Mentés', 39 | 'Schedule' => 'Ütemterv', 40 | 'Start' => 'Kezdés', 41 | 'Success' => 'Sikeres', 42 | 'The requested page does not exist.' => 'A keresett oldal nem létezik', 43 | 'Update' => 'Módosítás', 44 | 'Update Cron Job: {nameAttribute}' => 'Cron feledat módosítása: {nameAttribute}', 45 | 'Max execution time' => 'Maximum futási idó', 46 | ]; 47 | -------------------------------------------------------------------------------- /migrations/m190426_144151_create_cron_job_table.php: -------------------------------------------------------------------------------- 1 | createTable('{{%cron_job}}', [ 16 | 'id' => $this->primaryKey(), 17 | 'last_id' => $this->integer(), 18 | 'name' => $this->string()->notNull(), 19 | 'schedule' => $this->string()->notNull(), 20 | 'command' => $this->string()->notNull(), 21 | 'active' => $this->boolean()->notNull()->defaultValue(true), 22 | ]); 23 | } 24 | 25 | /** 26 | * {@inheritdoc} 27 | */ 28 | public function safeDown() 29 | { 30 | $this->dropTable('{{%cron_job}}'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /migrations/m190426_144159_create_cron_job_run_table.php: -------------------------------------------------------------------------------- 1 | createTable('{{%cron_job_run}}', [ 16 | 'id' => $this->primaryKey(), 17 | 'job_id' => $this->integer()->notNull(), 18 | 'pid' => $this->string()->notNull(), 19 | 20 | 'in_progress' => $this->boolean()->notNull(), 21 | 22 | 'start' => $this->dateTime()->notNull(), 23 | 'finish' => $this->dateTime(), 24 | 'runtime' => $this->float(), 25 | 26 | 'exit_code' => $this->integer(), 27 | 'output' => $this->text(), 28 | 'error_output' => $this->text(), 29 | ]); 30 | 31 | $this->createIndex('idx-cron_job_run-job_id', 'cron_job_run', 'job_id'); 32 | $this->addForeignKey('fk-cron_job_run-job_id', 'cron_job_run', 'job_id', 'cron_job', 'id', 'CASCADE'); 33 | } 34 | 35 | /** 36 | * {@inheritdoc} 37 | */ 38 | public function safeDown() 39 | { 40 | $this->dropTable('{{%cron_job_run}}'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /migrations/m190525_122152_add_max_execution_time_column_to_cron_job_table.php: -------------------------------------------------------------------------------- 1 | addColumn('{{%cron_job}}', 'max_execution_time', $this->integer()->after('command')); 16 | } 17 | 18 | /** 19 | * {@inheritdoc} 20 | */ 21 | public function safeDown() 22 | { 23 | $this->dropColumn('{{%cron_job}}', 'max_execution_time'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /models/CronJob.php: -------------------------------------------------------------------------------- 1 | 255], 50 | ]; 51 | } 52 | 53 | /** 54 | * {@inheritdoc} 55 | */ 56 | public function attributeLabels() 57 | { 58 | return [ 59 | 'id' => Yii::t('vbt-cron', 'ID'), 60 | 'last_id' => Yii::t('vbt-cron', 'Last'), 61 | 'name' => Yii::t('vbt-cron', 'Name'), 62 | 'schedule' => Yii::t('vbt-cron', 'Schedule'), 63 | 'command' => Yii::t('vbt-cron', 'Command'), 64 | 'max_execution_time' => Yii::t('vbt-cron', 'Max execution time'), 65 | 'active' => Yii::t('vbt-cron', 'Active'), 66 | ]; 67 | } 68 | 69 | /** 70 | * @return ActiveQuery|CronJobQuery|ActiveQueryInterface 71 | */ 72 | public function getCronJobRuns() 73 | { 74 | return $this->hasMany(CronJobRun::class, ['job_id' => 'id']); 75 | } 76 | 77 | /** 78 | * @return ActiveQuery|CronJobQuery|ActiveQueryInterface 79 | */ 80 | public function getLast() 81 | { 82 | return $this->hasOne(CronJobRun::class, ['id' => 'last_id']); 83 | } 84 | 85 | /** 86 | * {@inheritdoc} 87 | * @return CronJobQuery the active query used by this AR class. 88 | */ 89 | public static function find() 90 | { 91 | return new CronJobQuery(get_called_class()); 92 | } 93 | 94 | /** 95 | * @return array|CronJob[] 96 | */ 97 | public static function findRunnable() 98 | { 99 | return static::find() 100 | ->leftJoin('cron_job_run', 'cron_job_run.id = cron_job.last_id') 101 | ->where(['AND', 102 | ['active' => 1], 103 | ['OR', 104 | ['cron_job_run.id' => null], 105 | ['cron_job_run.in_progress' => 0], 106 | ], 107 | ]) 108 | ->all(); 109 | } 110 | 111 | /** 112 | * Run cron job 113 | * 114 | * @return CronJobRun 115 | */ 116 | public function run() 117 | { 118 | $process = $this->buildProcess($this->command, $this->max_execution_time ?? 60); 119 | $process->start(); 120 | 121 | $start = microtime(true); 122 | 123 | $run = new CronJobRun(); 124 | $run->job_id = $this->id; 125 | $run->start = date('Y-m-d H:i:s'); 126 | $run->pid = (string)$process->getPid(); 127 | $run->in_progress = true; 128 | $run->save(false); 129 | $this->last_id = $run->id; 130 | $this->save(); 131 | 132 | $run->exit_code = $process->wait(); 133 | $run->runtime = microtime(true) - $start; 134 | $run->finish = date('Y-m-d H:i:s'); 135 | $run->output = $process->getOutput(); 136 | $run->error_output = $process->getErrorOutput(); 137 | $run->in_progress = false; 138 | $run->save(true); 139 | 140 | return $run; 141 | } 142 | 143 | /** 144 | * Run cron job without waiting the result 145 | */ 146 | public function runQuick() 147 | { 148 | $process = $this->buildProcess('cron/job/run ' . $this->id); 149 | $process->start(); 150 | } 151 | 152 | /** 153 | * @param string $command 154 | * @param int $timeout 155 | * @return Process 156 | */ 157 | public function buildProcess($command, $timeout = 60) 158 | { 159 | $command = $this->buildCommand($command); 160 | $process = new Process($command, null, null, null, $timeout); 161 | return $process; 162 | } 163 | 164 | /** 165 | * Build cron job command 166 | * 167 | * @return string 168 | */ 169 | public function buildCommand($command) 170 | { 171 | $module = Module::getInstance(); 172 | 173 | return strtr('{php} {yii} {command}', [ 174 | '{php}' => $module->phpBinary, 175 | '{yii}' => $module->yiiFile, 176 | '{command}' => $command, 177 | ]); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /models/CronJobQuery.php: -------------------------------------------------------------------------------- 1 | 255], 52 | [['job_id'], 'exist', 'targetRelation' => 'Job'], 53 | ]; 54 | } 55 | 56 | /** 57 | * {@inheritdoc} 58 | */ 59 | public function attributeLabels() 60 | { 61 | return [ 62 | 'id' => Yii::t('vbt-cron', 'ID'), 63 | 'job_id' => Yii::t('vbt-cron', 'Job'), 64 | 'pid' => Yii::t('vbt-cron', 'Pid'), 65 | 'in_progress' => Yii::t('vbt-cron', 'In Progress'), 66 | 'start' => Yii::t('vbt-cron', 'Start'), 67 | 'finish' => Yii::t('vbt-cron', 'Finish'), 68 | 'runtime' => Yii::t('vbt-cron', 'Runtime'), 69 | 'exit_code' => Yii::t('vbt-cron', 'Exit Code'), 70 | 'output' => Yii::t('vbt-cron', 'Output'), 71 | 'error_output' => Yii::t('vbt-cron', 'Error Output'), 72 | ]; 73 | } 74 | 75 | /** 76 | * @return ActiveQuery|CronJobRunQuery|ActiveQueryInterface 77 | */ 78 | public function getJob() 79 | { 80 | return $this->hasOne(CronJob::class, ['id' => 'job_id']); 81 | } 82 | 83 | /** 84 | * {@inheritdoc} 85 | * @return CronJobRunQuery the active query used by this AR class. 86 | */ 87 | public static function find() 88 | { 89 | return new CronJobRunQuery(get_called_class()); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /models/CronJobRunQuery.php: -------------------------------------------------------------------------------- 1 | $query, 48 | ]); 49 | 50 | $this->load($params); 51 | 52 | if (!$this->validate()) { 53 | // uncomment the following line if you do not want to return any records when validation fails 54 | // $query->where('0=1'); 55 | return $dataProvider; 56 | } 57 | 58 | $query->andFilterWhere(['AND', 59 | ['id' => $this->id], 60 | ['job_id' => $this->job_id], 61 | ['like', 'pid', $this->pid], 62 | ['runtime' => $this->runtime], 63 | ['exit_code' => $this->exit_code], 64 | ['like', 'output', $this->output], 65 | ['like', 'error_output', $this->error_output], 66 | ]); 67 | 68 | if (is_numeric($this->in_progress) || is_bool($this->in_progress)) { 69 | $query->where(['in_progress' => (bool)$this->in_progress]); 70 | } 71 | 72 | if ($this->start) { 73 | if (strpos($this->start, ' ') === false) { 74 | $query->andWhere(['AND', 75 | ['>=', 'start', $this->start . ' 00:00:00'], 76 | ['<=', 'start', $this->start . ' 23:59:59'], 77 | ]); 78 | } else { 79 | $query->andWhere(['start', $this->start]); 80 | } 81 | } 82 | 83 | if ($this->finish) { 84 | if (strpos($this->finish, ' ') === false) { 85 | $query->andWhere(['AND', 86 | ['>=', 'finish', $this->finish . ' 00:00:00'], 87 | ['<=', 'finish', $this->finish . ' 23:59:59'], 88 | ]); 89 | } else { 90 | $query->andWhere(['finish', $this->finish]); 91 | } 92 | } 93 | 94 | return $dataProvider; 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /models/CronJobSearch.php: -------------------------------------------------------------------------------- 1 | $query, 47 | ]); 48 | 49 | $this->load($params); 50 | 51 | if (!$this->validate()) { 52 | // uncomment the following line if you do not want to return any records when validation fails 53 | // $query->where('0=1'); 54 | return $dataProvider; 55 | } 56 | 57 | $query->andFilterWhere(['AND', 58 | ['id' => $this->id], 59 | ['last_id' => $this->last_id], 60 | ['like', 'name', $this->name], 61 | ['like', 'schedule', $this->schedule], 62 | ['like', 'command', $this->command], 63 | ['max_execution_time' => $this->max_execution_time], 64 | ]); 65 | 66 | if (is_numeric($this->active) || is_bool($this->active)) { 67 | $query->where(['active' => (bool)$this->active]); 68 | } 69 | 70 | return $dataProvider; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /views/cron-job-run/index.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('vbt-cron', 'Cron Job Runs'); 16 | $this->params['breadcrumbs'][] = $this->title; 17 | ?> 18 | 19 |
20 |
21 | $dataProvider, 23 | 'filterModel' => $searchModel, 24 | 'pjax' => true, 25 | 'bsVersion' => Module::getInstance()->bsVersion, 26 | 'columns' => [ 27 | ['class' => 'kartik\grid\SerialColumn'], 28 | [ 29 | 'class' => '\kartik\grid\DataColumn', 30 | 'attribute' => 'job_id', 31 | 'vAlign' => 'middle', 32 | 'value' => function (CronJobRun $model) { 33 | return $model->job->name; 34 | }, 35 | 'filter' => ArrayHelper::map( 36 | CronJob::find()->all(), 37 | 'id', 38 | 'name' 39 | ) 40 | ], 41 | [ 42 | 'class' => '\kartik\grid\DataColumn', 43 | 'attribute' => 'pid', 44 | 'vAlign' => 'middle', 45 | ], 46 | [ 47 | 'class' => '\kartik\grid\DataColumn', 48 | 'attribute' => 'in_progress', 49 | 'format' => 'boolean', 50 | 'vAlign' => 'middle', 51 | 'filter' => [ 52 | 0 => Yii::t('app', 'No'), 53 | 1 => Yii::t('app', 'Yes'), 54 | ] 55 | ], 56 | [ 57 | 'class' => '\kartik\grid\DataColumn', 58 | 'attribute' => 'start', 59 | 'vAlign' => 'middle', 60 | ], 61 | [ 62 | 'class' => '\kartik\grid\DataColumn', 63 | 'attribute' => 'finish', 64 | 'vAlign' => 'middle', 65 | ], 66 | [ 67 | 'class' => '\kartik\grid\DataColumn', 68 | 'attribute' => 'runtime', 69 | 'vAlign' => 'middle', 70 | ], 71 | [ 72 | 'class' => '\kartik\grid\DataColumn', 73 | 'attribute' => 'exit_code', 74 | 'vAlign' => 'middle', 75 | ], 76 | [ 77 | 'class' => '\kartik\grid\DataColumn', 78 | 'attribute' => 'output', 79 | 'value' => function (CronJobRun $model) { 80 | return Html::tag('pre', Console::ansiToHtml($model->output), ['style' => 'padding:15px']); 81 | }, 82 | 'format' => 'raw', 83 | 'hAlign' => 'left', 84 | 'vAlign' => 'middle', 85 | ], 86 | [ 87 | 'class' => '\kartik\grid\DataColumn', 88 | 'attribute' => 'error_output', 89 | 'value' => function (CronJobRun $model) { 90 | return Html::tag('pre', Console::ansiToHtml($model->error_output), ['style' => 'padding:15px']); 91 | }, 92 | 'format' => 'raw', 93 | 'hAlign' => 'left', 94 | 'vAlign' => 'middle', 95 | ], 96 | ], 97 | 'toolbar' => [ 98 | Html::a(' ' . Yii::t('vbt-cron', 'Reset'), [''], [ 99 | 'class' => 'btn btn-default', 100 | 'title' => Yii::t('vbt-cron', 'Reset'), 101 | ]), 102 | ], 103 | 'panel' => [ 104 | 'type' => 'green', 105 | 'heading' => ' ' . $this->title, 106 | ] 107 | ]) ?> 108 |
109 |
110 | -------------------------------------------------------------------------------- /views/cron-job/_form.php: -------------------------------------------------------------------------------- 1 | 10 | 11 |
12 | 13 | 14 | 15 | errorSummary($model); ?> 16 | 17 | field($model, 'name')->textInput(['maxlength' => true]) ?> 18 | 19 | field($model, 'schedule')->textInput(['maxlength' => true, 'placeholder' => '* * * * *']) ?> 20 | 21 | field($model, 'command')->textInput(['maxlength' => true]) ?> 22 | 23 | field($model, 'max_execution_time')->textInput() ?> 24 | 25 | field($model, 'active')->checkbox() ?> 26 | 27 |
28 | 'btn btn-success']) ?> 29 |
30 | 31 | 32 | 33 |
34 | -------------------------------------------------------------------------------- /views/cron-job/create.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('vbt-cron', 'Create Cron Job'); 11 | $this->params['breadcrumbs'][] = ['label' => Yii::t('vbt-cron', 'Cron Jobs'), 'url' => ['index']]; 12 | $this->params['breadcrumbs'][] = $this->title; 13 | 14 | ?> 15 |
16 | isBs4()): ?> 17 |
18 |
19 |
title) ?>
20 |
21 |
22 | render('_form', ['model' => $model]) ?> 23 |
24 |
25 | 26 |
27 |
28 |
title) ?>
29 |
30 |
31 | render('_form', ['model' => $model]) ?> 32 |
33 |
34 | 35 |
36 | -------------------------------------------------------------------------------- /views/cron-job/index.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('vbt-cron', 'Cron Jobs'); 13 | $this->params['breadcrumbs'][] = $this->title; 14 | ?> 15 | 16 |
17 |
18 | $dataProvider, 20 | 'filterModel' => $searchModel, 21 | 'pjax' => true, 22 | 'bsVersion' => Module::getInstance()->bsVersion, 23 | 'columns' => [ 24 | ['class' => 'kartik\grid\SerialColumn'], 25 | [ 26 | 'class' => '\kartik\grid\DataColumn', 27 | 'attribute' => 'name', 28 | ], 29 | [ 30 | 'class' => '\kartik\grid\DataColumn', 31 | 'attribute' => 'schedule', 32 | ], 33 | [ 34 | 'class' => '\kartik\grid\DataColumn', 35 | 'attribute' => 'command', 36 | ], 37 | [ 38 | 'class' => '\kartik\grid\DataColumn', 39 | 'attribute' => 'max_execution_time', 40 | ], 41 | [ 42 | 'class' => '\kartik\grid\DataColumn', 43 | 'attribute' => 'active', 44 | 'format' => 'boolean', 45 | ], 46 | [ 47 | 'class' => '\kartik\grid\DataColumn', 48 | 'attribute' => 'last.start' 49 | ], 50 | [ 51 | 'class' => '\kartik\grid\DataColumn', 52 | 'attribute' => 'last.runtime' 53 | ], 54 | [ 55 | 'class' => '\kartik\grid\DataColumn', 56 | 'attribute' => 'last.exit_code' 57 | ], 58 | [ 59 | 'class' => '\kartik\grid\DataColumn', 60 | 'value' => function (CronJob $job) { 61 | if ($job->last_id === null) { 62 | return null; 63 | } 64 | return $job->last->exit_code == 0 ? true : false; 65 | }, 66 | 'label' => Yii::t('vbt-cron', 'Success'), 67 | 'format' => 'boolean', 68 | ], 69 | [ 70 | 'class' => 'kartik\grid\ActionColumn', 71 | 'template' => '{update} {delete} {run}', 72 | 'buttons' => [ 73 | 'run' => function ($url, CronJob $model) { 74 | return Html::a('', ['/cron/cron-job-run/index', 'CronJobRunSearch' => ['job_id' => $model->id]], [ 75 | 'title' => Yii::t('vbt-cron', 'Logs'), 76 | 'data-pjax' => 0, 77 | ]); 78 | }, 79 | ] 80 | ], 81 | ], 82 | 'toolbar' => [['content' => 83 | Html::a(' ' . Yii::t('vbt-cron', 'Create Cron Job'), ['create'], [ 84 | 'class' => 'btn btn-info', 85 | 'title' => Yii::t('vbt-cron', 'Create Cron Job'), 86 | 'data-pjax' => 0, 87 | ]) . 88 | Html::a(' ' . Yii::t('vbt-cron', 'Reset'), [''], [ 89 | 'class' => 'btn btn-default', 90 | 'title' => Yii::t('vbt-cron', 'Reset'), 91 | ]) 92 | ]], 93 | 'panel' => [ 94 | 'type' => 'success', 95 | 'heading' => ' ' . $this->title, 96 | ] 97 | ]) ?> 98 |
99 |
100 | -------------------------------------------------------------------------------- /views/cron-job/update.php: -------------------------------------------------------------------------------- 1 | title = Yii::t('vbt-cron', 'Update Cron Job: {nameAttribute}', [ 10 | 'nameAttribute' => $model->name, 11 | ]); 12 | $this->params['breadcrumbs'][] = ['label' => Yii::t('vbt-cron', 'Cron Jobs'), 'url' => ['index']]; 13 | $this->params['breadcrumbs'][] = Yii::t('vbt-cron', 'Update'); 14 | 15 | ?> 16 |
17 | isBs4()): ?> 18 |
19 |
20 |
title) ?>
21 |
22 |
23 | render('_form', ['model' => $model]) ?> 24 |
25 |
26 | 27 |
28 |
29 |
title) ?>
30 |
31 |
32 | render('_form', ['model' => $model]) ?> 33 |
34 |
35 | 36 |
37 | --------------------------------------------------------------------------------