commit c24d319159af4ca9800b1c85081cd7a61acf0f80 Author: Sasha Rybkin Date: Wed Nov 20 16:40:08 2024 +0300 init diff --git a/Module.php b/Module.php new file mode 100644 index 0000000..ee225ed --- /dev/null +++ b/Module.php @@ -0,0 +1,75 @@ +getUrlManager()->addRules([ + ['class' => 'yii\web\UrlRule', 'pattern' => $this->id, 'route' => $this->id . '/default/index'], + ['class' => 'yii\web\UrlRule', 'pattern' => $this->id . '/', 'route' => $this->id . '/default/view'], + ['class' => 'yii\web\UrlRule', 'pattern' => $this->id . '//', 'route' => $this->id . '//'], + ], false); + } + elseif ($app instanceof \yii\console\Application) + { + $app->controllerMap[$this->id] = [ + 'class' => 'dominion\cron\console\MoleController', + // 'module' => $this, + ]; + } + + if (!isset($app->get('i18n')->translations['mole*'])) + { + $app->get('i18n')->translations['mole*'] = [ + 'class' => PhpMessageSource::className(), + 'basePath' => __DIR__ . '/messages', + 'sourceLanguage' => 'en-US' + ]; + } + } + /** + * Добавление агента (обертка) + * @param string $controller + * @param string $name + * @param array $params + * @param int $priority + * @param int $period + * @param date $dateAdd + * @param string $project + * @return boolean + */ + public function add($controller, $name, $params = array(), $priority = 0, $period = 0, $dateAdd = false, $project = false) + { + return MoleTask::add($controller, $name, $params, $priority, $period, $dateAdd, $project); + } + + /** + * Выбираем все строки с project + */ + public function getAllTask($project = false) + { + $model = new MoleTask(); + return $model->getAllTask($project); + } + + +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..2e31d2b --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +Агент для работы с кроном +========================= +Функционал для работы с кроном + +Installation +------------ + +The preferred way to install this extension is through [composer](http://getcomposer.org/download/). + +Either run + +``` +php composer.phar require --prefer-dist dominion/yii2-cron "*" +``` + +or add + +``` +"dominion/yii2-cron": "*" +``` + +to the require section of your `composer.json` file. + + +Usage +----- + +Once the extension is installed, simply use it in your code by : + +```php +``` \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..d63cad5 --- /dev/null +++ b/composer.json @@ -0,0 +1,21 @@ +{ + "name": "dominion/yii2-cron", + "description": "Функционал для работы с кроном", + "type": "yii2-extension", + "keywords": ["yii2","extension"], + "license": "MIT", + "authors": [ + { + "name": "Rybkin Sasha", + "email": "ribkin@dominion.ru" + } + ], + "require": { + "yiisoft/yii2": "~2.0.0" + }, + "autoload": { + "psr-4": { + "dominion\\cron\\": "" + } + } +} diff --git a/console/MoleController.php b/console/MoleController.php new file mode 100644 index 0000000..cdad692 --- /dev/null +++ b/console/MoleController.php @@ -0,0 +1,99 @@ + + * @since 0.1 + */ +class MoleController extends Controller +{ + + /** + * Запуск всех агентов для проекта yii из mole_task + * @return int Exit code + */ + public function actionIndex() + { + $filePatch = Yii::getAlias('@app/runtime/lock.lock'); + if (!file_exists($filePatch)) + { + $fp = fopen($filePatch, "w"); + fwrite($fp, ""); + fclose($fp); + } + $file = fopen($filePatch, 'r+'); + + if (flock($file, LOCK_EX | LOCK_NB)) + { + $model = new MoleTask; + $tasks = $model->getAllTask(); + foreach ($tasks as $task) + { + try + { + $task->dateStart = date('Y-m-d H:i:s'); + $task->save(); + $params = explode('/', $task->controller); + $controller = $this->format($params[0]); + $action = 'actionIndex'; + if (isset($params[1])) + { + $action = 'action' . $this->format($params[1]); + } + if(stripos($controller, 'Controller') === false) + { + $controller .= 'Controller'; + } + + $class = 'app\\commands\\' . $controller; + if (class_exists($class)) + { + $control = new $class($task->controller, 'product'); + if (method_exists($control, $action)) + { + $params = $control->{$action}(unserialize($task->params)); + if(!empty($params)) + { + $task->params = serialize($params); + } + $task->isReady = 1; + } + } + $task->setCompleted(); + } catch (\Exception $ex) + { + $task->dateStart = null; + $task->save(); + print_r($ex->getMessage()); + } + } + } + return ExitCode::OK; + } + + protected function format($controller) + { + $params = explode('-', $controller); + foreach ($params as $key => $value) + { + $params[$key] = ucfirst($value); + } + return implode('', $params); + } + +} diff --git a/controllers/DefaultController.php b/controllers/DefaultController.php new file mode 100644 index 0000000..65ef016 --- /dev/null +++ b/controllers/DefaultController.php @@ -0,0 +1,135 @@ +user->getIsGuest() && in_array(Yii::$app->user->id, $this->module->admins)) + { + return [ + 'verbs' => [ + 'class' => VerbFilter::className(), + 'actions' => [ + 'delete' => ['POST'], + ], + ], + ]; + } + else + { + throw new NotFoundHttpException(Yii::t('mole', 'access denied')); + } + } + + /** + * Renders the index view for the module + * @return string + */ + public function actionIndex() + { + $searchModel = new MoleTaskSearch(); + $dataProvider = $searchModel->search(Yii::$app->request->queryParams); + + return $this->render('index', [ + 'searchModel' => $searchModel, + 'dataProvider' => $dataProvider, + ]); + } + + /** + * Displays a single MoleTask model. + * @param integer $id + * @return mixed + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionView($id) + { + $model = $this->findModel($id); + return $this->render('view', [ + 'model' => $model, + ]); + } + + /** + * Creates a new MoleTask model. + * If creation is successful, the browser will be redirected to the 'view' page. + * @return mixed + */ + public function actionCreate() + { + $model = new MoleTask(); + + if ($model->load(Yii::$app->request->post()) && $model->save()) + { + return $this->redirect(['view', 'id' => $model->id]); + } + return $this->render('create', [ + 'model' => $model, + ]); + } + + /** + * Updates an existing MoleTask model. + * If update is successful, the browser will be redirected to the 'view' page. + * @param integer $id + * @return mixed + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionUpdate($id) + { + $model = $this->findModel($id); + + if ($model->load(Yii::$app->request->post()) && $model->save()) + { + return $this->redirect(['view', 'id' => $model->id]); + } + + return $this->render('update', [ + 'model' => $model, + ]); + } + + /** + * Deletes an existing MoleTask model. + * If deletion is successful, the browser will be redirected to the 'index' page. + * @param integer $id + * @return mixed + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionDelete($id) + { + $this->findModel($id)->delete(); + + return $this->redirect(['index']); + } + + /** + * Finds the MoleTask model based on its primary key value. + * If the model is not found, a 404 HTTP exception will be thrown. + * @param integer $id + * @return MoleTask the loaded model + * @throws NotFoundHttpException if the model cannot be found + */ + protected function findModel($id) + { + if (($model = MoleTask::findOne($id)) !== null) + { + return $model; + } + + throw new NotFoundHttpException(Yii::t('mole', 'The requested page does not exist.')); + } + +} diff --git a/messages/ru-RU/mole.php b/messages/ru-RU/mole.php new file mode 100644 index 0000000..52c74e9 --- /dev/null +++ b/messages/ru-RU/mole.php @@ -0,0 +1,29 @@ + 'Список задач', + 'Project' => 'Проект', + 'Parent ID' => 'Родительский процесс', + 'Date Add' => 'Дата создания', + 'Date Start' => 'Дата запуска', + 'Date End' => 'Дата завершения', + 'Module' => 'Модуль', + 'Controller' => 'Контроллер', + 'Type' => 'Тип', + 'Name' => 'Название', + 'Params' => 'Параметры', + 'Is Ready' => 'Готов', + 'Completed' => 'Завершен', + 'Priority' => 'Приоритет', + 'Period' => 'Периодичность', + // 'Childs Total Count' => '', + // 'Childs Completed' => '', + 'Status' => 'Статус', + 'Yes' => 'Да', + 'No' => 'Нет', + 'Create Task' => 'Создать задачу', + 'Save' => 'Сохранить', + 'Update'=> 'Изменить', + 'Update Task: {nameAttribute}' => 'Изменить задачу: {nameAttribute}', + 'Delete' => 'Удалить', + ]; diff --git a/models/MoleTask.php b/models/MoleTask.php new file mode 100644 index 0000000..891535e --- /dev/null +++ b/models/MoleTask.php @@ -0,0 +1,151 @@ + 255], + [['project'], 'string', 'max' => 50], + ]; + } + + /** + * {@inheritdoc} + */ + public function attributeLabels() + { + return [ + 'id' => Yii::t('mole', 'ID'), + 'parentId' => Yii::t('mole', 'Parent ID'), + 'dateAdd' => Yii::t('mole', 'Date Add'), + 'dateStart' => Yii::t('mole', 'Date Start'), + 'dateEnd' => Yii::t('mole', 'Date End'), + 'module' => Yii::t('mole', 'Module'), + 'controller' => Yii::t('mole', 'Controller'), + 'type' => Yii::t('mole', 'Type'), + 'name' => Yii::t('mole', 'Name'), + 'params' => Yii::t('mole', 'Params'), + 'isReady' => Yii::t('mole', 'Is Ready'), + 'completed' => Yii::t('mole', 'Completed'), + 'priority' => Yii::t('mole', 'Priority'), + 'childsTotalCount' => Yii::t('mole', 'Childs Total Count'), + 'childsCompleted' => Yii::t('mole', 'Childs Completed'), + 'status' => Yii::t('mole', 'Status'), + 'project' => Yii::t('mole', 'Project'), + 'period' => Yii::t('mole', 'Period'), + ]; + } + + /** + * Выбираем все строки с project + */ + public function getAllTask($project = false) + { + return self::find() + ->andWhere([ + 'project' => $project ?: Yii::$app->getModule('cron')->project, + 'completed' => 0, + ]) + ->andWhere(['IS', 'dateStart', NULL]) + ->andWhere(['IS', 'dateEnd', NULL]) + ->andWhere(['<=', 'dateAdd', date('Y-m-d H:i:s')]) + ->orderBy('priority DESC') + ->all(); + } + + public function setCompleted() + { + $this->dateEnd = date('Y-m-d H:i:s'); + $this->completed = 1; + if ($this->save() && $this->period > 0) + { + $model = new MoleTask; + $model->attributes = $this->attributes; + $model->isReady = 0; + $model->completed = 0; + $model->dateStart = null; + $model->dateEnd = null; + $model->dateAdd = date('Y-m-d H:i:s', (strtotime($this->dateAdd . " +$this->period seconds"))); + $model->save(); + } + } + + /** + * Добавление агента (обертка) + * @param string $controller + * @param string $name + * @param array $params + * @param int $priority + * @param int $period + * @param date $dateAdd + * @param string $project + * @return boolean + */ + public static function add($controller, $name, $params = array(), $priority = 0, $period = 0, $dateAdd = false, $project = false) + { + $module = ''; + if(stripos($controller, '.') !== false) + { + $arController = explode('.', $controller); + $module = $arController[0]; + $controller = $arController[1]; + } + + $model = new MoleTask(); + $model->controller = $controller; + $model->name = $name; + $model->params = serialize($params); + $model->priority = $priority; + $model->period = $period; + $model->dateAdd = $dateAdd ?: date('Y-m-d H:i:s'); + $model->project = $project ?: Yii::$app->getModule('cron')->project; + $model->module = $module; + $model->type = ((empty($model->module) ? $model->project : $model->module) . '.' . $model->controller); // для совместимости + $model->isReady = 1; + return $model->save(); + } + +} diff --git a/models/search/MoleTaskSearch.php b/models/search/MoleTaskSearch.php new file mode 100644 index 0000000..eb8d026 --- /dev/null +++ b/models/search/MoleTaskSearch.php @@ -0,0 +1,91 @@ + 255], + [['project'], 'string', 'max' => 50], + ]; + } + + /** + * @inheritdoc + */ + public function scenarios() + { + // bypass scenarios() implementation in the parent class + return Model::scenarios(); + } + + /** + * Creates data provider instance with search query applied + * + * @param array $params + * + * @return ActiveDataProvider + */ + public function search($params) + { + $query = MoleTask::find(); + // add conditions that should always apply here + + $this->load($params); + $dataProvider = new ActiveDataProvider([ + 'query' => $query, + 'sort' => [ + 'defaultOrder' => [ + 'id' => SORT_DESC + ] + ] + ]); + + if (!$this->validate()) + { + // uncomment the following line if you do not want to return any records when validation fails + // $query->where('0=1'); + return $dataProvider; + } + + + + $query->andFilterWhere([ + 'id' => $this->id, + 'parentId' => $this->parentId, + 'isReady' => $this->isReady, + 'completed' => $this->completed, + 'priority' => $this->priority, + 'childsTotalCount' => $this->childsTotalCount, + 'childsCompleted' => $this->childsCompleted, + ]); + + $query->andFilterWhere(['like', 'params', $this->params]) + ->andFilterWhere(['like', 'controller', $this->controller]) + ->andFilterWhere(['like', 'module', $this->module]) + ->andFilterWhere(['like', 'type', $this->type]) + ->andFilterWhere(['like', 'name', $this->name]) + ->andFilterWhere(['like', 'status', $this->status]) + ->andFilterWhere(['like', 'project', $this->project]); + + return $dataProvider; + } + +} diff --git a/views/default/_form.php b/views/default/_form.php new file mode 100644 index 0000000..0d5df99 --- /dev/null +++ b/views/default/_form.php @@ -0,0 +1,36 @@ + + +
+ + + field($model, 'project'); ?> + + field($model, 'name'); ?> + + field($model, 'dateAdd'); ?> + field($model, 'dateStart'); ?> + field($model, 'dateEnd'); ?> + + field($model, 'module'); ?> + + field($model, 'controller'); ?> + field($model, 'params'); ?> + field($model, 'period'); ?> + +
+ + 'btn btn-success']) ?> + +
+ + +
+ diff --git a/views/default/create.php b/views/default/create.php new file mode 100644 index 0000000..97b0811 --- /dev/null +++ b/views/default/create.php @@ -0,0 +1,30 @@ +title = Yii::t('mole', 'Create Task'); +$this->params['breadcrumbs'][] = ['label' => Yii::t('mole', 'Task List'), 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +?> +
+
+
+
+
+
+
+ render('_form', [ + 'model' => $model, + ]) + ?> +
+
+
+
+
+
+
\ No newline at end of file diff --git a/views/default/index.php b/views/default/index.php new file mode 100644 index 0000000..565e8fa --- /dev/null +++ b/views/default/index.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE.md + * file that was distributed with this source code. + */ + +use yii\grid\GridView; +use yii\helpers\Html; +use yii\helpers\Url; +use yii\web\View; +use yii\widgets\Pjax; + +/** + * @var \yii\web\View $this + * @var \yii\data\ActiveDataProvider $dataProvider + * @var \dektrium\user\models\UserSearch $searchModel + */ +$this->title = Yii::t('mole', 'Task List'); +$this->params['breadcrumbs'][] = $this->title; +?> +
+
+
+
+
+
+
+ +

+ 'btn btn-success']) ?> +

+ + $dataProvider, + 'filterModel' => $searchModel, + 'layout' => "{items}\n{pager}", + 'columns' => [ + 'id', + 'project', + 'name', + // 'parentId', + 'dateAdd:datetime', + 'dateStart:datetime', + 'dateEnd:datetime', + //'module', + 'controller', + // 'type', + //'params', + [ + 'attribute' => 'isReady', + 'value' => function($model) + { + return $model->isReady ? Yii::t('mole', 'Yes') : Yii::t('mole', 'No'); + }, + // 'filter' => [0 => Yii::t('mole', 'No'), 1 => Yii::t('mole', 'Yes')] + ], + [ + 'attribute' => 'completed', + 'value' => function($model) + { + return $model->completed ? Yii::t('mole', 'Yes') : Yii::t('mole', 'No'); + }, + // 'filter' => [0 => Yii::t('mole', 'No'), 1 => Yii::t('mole', 'Yes')] + ], + 'priority', + [ + 'attribute' => 'period', + 'value' => function($model) + { + return $model->period > 0 ? $model->period : Yii::t('mole', 'No'); + }, + ], + //'childsTotalCount', + //'childsCompleted', + // 'status', + [ + 'class' => 'yii\grid\ActionColumn', + ], + ], + ]); + ?> +
+
+
+
+
+
+
diff --git a/views/default/update.php b/views/default/update.php new file mode 100644 index 0000000..c841fdc --- /dev/null +++ b/views/default/update.php @@ -0,0 +1,35 @@ +title = Yii::t('mole', 'Update Task: {nameAttribute}', [ + 'nameAttribute' => $model->name, + ]); +$this->params['breadcrumbs'][] = ['label' => Yii::t('mole', 'Task List'), 'url' => ['index']]; +$this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->id]]; +$this->params['breadcrumbs'][] = Yii::t('mole', 'Update'); +?> +
+
+
+
+
+
+
+ + render('_form', [ + 'model' => $model, + ]) + ?> + +
+
+
+
+
+
+
\ No newline at end of file diff --git a/views/default/view.php b/views/default/view.php new file mode 100644 index 0000000..5ca3004 --- /dev/null +++ b/views/default/view.php @@ -0,0 +1,92 @@ +title = $model->name; +$this->params['breadcrumbs'][] = ['label' => Yii::t('mole', 'Task List'), 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +?> +
+
+
+
+
+
+
+ +

+ $model->id], ['class' => 'btn btn-primary']) ?> + $model->id], [ + 'class' => 'btn btn-danger', + 'data' => [ + 'confirm' => Yii::t('mole', 'Are you sure you want to delete this item?'), + 'method' => 'post', + ], + ]) + ?> +

+ + $model, + 'attributes' => [ + 'id', + 'project', + 'name', + 'parentId', + 'dateAdd:datetime', + 'dateStart:datetime', + 'dateEnd:datetime', + 'module', + 'controller', + 'type', + [ + 'attribute' => 'params', + 'value' => function($model) + { + return print_r(json_decode($model->params, true), true); + }, + ], + [ + 'attribute' => 'isReady', + 'value' => function($model) + { + return $model->isReady ? Yii::t('mole', 'Yes') : Yii::t('mole', 'No'); + }, + ], + [ + 'attribute' => 'completed', + 'value' => function($model) + { + return $model->completed ? Yii::t('mole', 'Yes') : Yii::t('mole', 'No'); + }, + ], + 'priority', + 'status', + [ + 'attribute' => 'period', + 'value' => function($model) + { + return $model->period > 0 ? $model->period : Yii::t('mole', 'No'); + }, + ], + ], + ]) + ?> + + +
+
+
+
+
+
+
+