GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Task::attributeHints()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace app\backgroundtasks\models;
4
5
use app\backend\models\Notification;
6
use app\backgroundtasks\traits\SearchModelTrait;
7
use app\modules\user\models\User;
8
use yii\data\ActiveDataProvider;
9
use yii\db\ActiveRecord;
10
use yii\helpers\Json;
11
12
/**
13
 * This is the model class for table "backgroundtasks_task".
14
 *
15
 * @property integer $id
16
 * @property string $action
17
 * @property string $type
18
 * @property integer $initiator
19
 * @property string $name
20
 * @property string $description
21
 * @property string $params
22
 * @property string $data
23
 * @property string $init_event
24
 * @property string $cron_expression
25
 * @property string $status
26
 * @property integer $fail_counter
27
 * @property string $ts
28
 * @property string $options
29
 */
30
class Task extends ActiveRecord
31
{
32
    use SearchModelTrait;
33
34
    public $username;
35
36
    const MAX_FAIL_COUNT = 5;
37
38
    const STATUS_ACTIVE     = 'ACTIVE';
39
    const STATUS_STOPPED    = 'STOPPED';
40
    const STATUS_RUNNING    = 'RUNNING';
41
    const STATUS_PROCESS    = 'PROCESS';
42
    const STATUS_COMPLETED  = 'COMPLETED';
43
    const STATUS_FAILED     = 'FAILED';
44
45
    const TYPE_EVENT    = 'EVENT';
46
    const TYPE_REPEAT   = 'REPEAT';
47
48
    private $logname = '';
49
    private $task_options = [];
50
51
    /**
52
     * @inheritdoc
53
     */
54
    public static function tableName()
55
    {
56
        return '{{%backgroundtasks_task}}';
57
    }
58
59
    /**
60
     * Return array of statuses
61
     * @param string $type
62
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
63
     */
64
    public static function getStatuses($type = '')
65
    {
66
        switch ($type) {
67 View Code Duplication
            case Task::TYPE_EVENT:
68
                return [
69
                    self::STATUS_ACTIVE => self::STATUS_ACTIVE,
70
                    self::STATUS_COMPLETED => self::STATUS_COMPLETED,
71
                    self::STATUS_FAILED => self::STATUS_FAILED,
72
                    self::STATUS_RUNNING => self::STATUS_RUNNING,
73
                ];
74 View Code Duplication
            case Task::TYPE_REPEAT:
75
                return [
76
                    self::STATUS_ACTIVE => self::STATUS_ACTIVE,
77
                    self::STATUS_STOPPED => self::STATUS_STOPPED,
78
                    self::STATUS_FAILED => self::STATUS_FAILED,
79
                    self::STATUS_RUNNING => self::STATUS_RUNNING,
80
                    self::STATUS_PROCESS => self::STATUS_PROCESS,
81
                ];
82
            default:
83
                return [
84
                    self::STATUS_ACTIVE => self::STATUS_ACTIVE,
85
                    self::STATUS_STOPPED => self::STATUS_STOPPED,
86
                    self::STATUS_RUNNING => self::STATUS_RUNNING,
87
                    self::STATUS_PROCESS => self::STATUS_PROCESS,
88
                    self::STATUS_COMPLETED => self::STATUS_COMPLETED,
89
                    self::STATUS_FAILED => self::STATUS_FAILED,
90
                ];
91
        }
92
    }
93
94
    /**
95
     * Return array of types
96
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
97
     */
98
    public static function getTypes()
99
    {
100
        return [
101
            self::TYPE_EVENT => self::TYPE_EVENT,
102
            self::TYPE_REPEAT => self::TYPE_REPEAT,
103
        ];
104
    }
105
106
    /**
107
     * @inheritdoc
108
     */
109
    public function rules()
110
    {
111
        return [
112
            [['action', 'initiator', 'name'], 'required', 'except' => 'search'],
113
            [['cron_expression'], 'required', 'on' => 'repeat'],
114
            [['init_event'], 'required', 'on' => 'event'],
115
            [['type', 'description', 'params', 'data', 'status', 'options'], 'string'],
116
            [['initiator'], 'integer'],
117
            [['ts', 'username', 'fail_counter'], 'safe'],
118
            [['action', 'name', 'init_event', 'cron_expression'], 'string', 'max' => 255],
119
            [['status'], 'default', 'value' => self::STATUS_ACTIVE],
120
        ];
121
    }
122
123
    /**
124
     * @inheritdoc
125
     */
126
    public function attributeLabels()
127
    {
128
        return [
129
            'id' => \Yii::t('app', 'ID'),
130
            'action' => \Yii::t('app', 'Action'),
131
            'type' => \Yii::t('app', 'Type'),
132
            'initiator' => \Yii::t('app', 'Initiator'),
133
            'name' => \Yii::t('app', 'Name'),
134
            'description' => \Yii::t('app', 'Description'),
135
            'params' => \Yii::t('app', 'Parameters'),
136
            'data' => \Yii::t('app', 'Data'),
137
            'init_event' => \Yii::t('app', 'Event'),
138
            'cron_expression' => \Yii::t('app', 'Condition'),
139
            'ts' => \Yii::t('app', 'Date Modify'),
140
            'status' => \Yii::t('app', 'Status'),
141
            'fail_counter' => \Yii::t('app', 'Fail Status Count'),
142
            'username' => \Yii::t('app', 'Initiator'),
143
            'options' => \Yii::t('app', 'Options'),
144
        ];
145
    }
146
147
    /**
148
     * Return attribute hints
149
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
150
     */
151
    public function attributeHints()
152
    {
153
        return [
154
            'action' => \Yii::t('app', '[route to the action module/controller/action]'),
155
            'params' => \Yii::t('app', '[action parameters separated by spaces]'),
156
        ];
157
    }
158
159
    /**
160
     * Users relation
161
     * @return mixed
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use \yii\db\ActiveQuery.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
162
     */
163
    public function getUsers()
164
    {
165
        return $this->hasMany(User::className(), ['id' => 'user_id'])
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
166
            ->viaTable('Notification', ['task_id' => 'id']);
167
    }
168
169
    /**
170
     * Initiator user relation
171
     * @return \yii\db\ActiveQueryInterface
172
     */
173
    public function getInitiatorUser()
174
    {
175
        return $this->hasOne(User::className(), ['id' => 'initiator']);
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
176
    }
177
178
    /**
179
     * Set running status
180
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be false|integer?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
181
     */
182
    public function setRunning()
183
    {
184
        return $this->setStatus(self::STATUS_RUNNING);
185
    }
186
187
    /**
188
     * Set process status
189
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be false|integer?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
190
     */
191
    public function setProcess()
192
    {
193
        return $this->setStatus(self::STATUS_PROCESS);
194
    }
195
196
    /**
197
     * Set stopped status
198
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be false|integer?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
199
     */
200
    public function setStopped()
201
    {
202
        return $this->setStatus(self::STATUS_STOPPED);
203
    }
204
205
    /**
206
     * Set completed status
207
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be false|integer?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
208
     */
209
    public function setCompleted()
210
    {
211
        return $this->setStatus(self::STATUS_COMPLETED);
212
    }
213
214
    /**
215
     * Set active status
216
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be false|integer?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
217
     */
218
    public function setActive()
219
    {
220
        return $this->setStatus(self::STATUS_ACTIVE);
221
    }
222
223
    /**
224
     * Set failed status
225
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be false|integer?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
226
     */
227
    public function setFailed()
228
    {
229
        return $this->setStatus(self::STATUS_FAILED);
230
    }
231
232
    /**
233
     * Set status
234
     * @param $status
235
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be false|integer?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
236
     */
237
    public function setStatus($status)
238
    {
239
        $this->status = $status;
240
        return $this->update(false, ['status']);
241
    }
242
243
    /**
244
     * @return array
245
     */
246
    public function getOptions()
247
    {
248
        return $this->task_options;
249
    }
250
251
    /**
252
     * @param $options
253
     */
254
    public function setOptions($options)
255
    {
256
        if (is_array($options)) {
257
            $this->task_options = $options;
258
        }
259
    }
260
261
    /**
262
     * Set failed status counter
263
     * @return bool
264
     */
265
    private function incrementCounter()
266
    {
267
        return $this->updateCounters(['fail_counter' => 1]);
268
    }
269
270
    /**
271
     * Refresh failed status counter
272
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be false|integer?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
273
     */
274
    private function refreshCounter()
275
    {
276
        $this->fail_counter = 0;
277
        return $this->update(false, ['fail_counter']);
278
    }
279
280
    /**
281
     * Run task
282
     */
283
    public function run()
284
    {
285
        $oldts = $this->ts;
286
        $this->refresh();
287
        if (($this->status == self::STATUS_ACTIVE || $this->status == self::STATUS_PROCESS) && $this->ts == $oldts) {
288
            $this->setRunning();
289
            $message = new NotifyMessage();
290
            $message->task_id = $this->id;
291
            \Yii::trace($this->name.' is running', $this->getLogname());
0 ignored issues
show
Deprecated Code introduced by
The method yii\BaseYii::trace() has been deprecated with message: since 2.0.14. Use [[debug()]] instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
292
            $args = ' ' . escapeshellarg($this->action);
293
            /* isJson validate*/
294
            $params = preg_match('/^{[^}]+}$/iu',$this->params) ? [$this->params]: [$this->params];
295
296
            if (!empty($params)) {
297
                foreach ($params as $param) {
298
                    $args .= ' ' . escapeshellarg($param);
299
                }
300
            }
301
            exec(\Yii::getAlias('@app/yii') . $args . ' 2>&1', $output, $return_val);
302
            $message->result = $this->printCommandResult($output);
303
304
            if ($return_val === 0) {
305
                switch ($this->type) {
306
                    case self::TYPE_EVENT:
307
                        $this->setCompleted();
308
                        \Yii::trace($this->name.' completed', $this->getLogname());
0 ignored issues
show
Deprecated Code introduced by
The method yii\BaseYii::trace() has been deprecated with message: since 2.0.14. Use [[debug()]] instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
309
                        break;
310
                    case self::TYPE_REPEAT:
311
                        $this->setActive();
312
                        $this->refreshCounter();
313
                        \Yii::trace($this->name.' completed', $this->getLogname());
0 ignored issues
show
Deprecated Code introduced by
The method yii\BaseYii::trace() has been deprecated with message: since 2.0.14. Use [[debug()]] instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
314
                        break;
315
                    default:
316
                        $this->setFailed();
317
                        \Yii::error($this->name.' failed', $this->getLogname());
318
                        break;
319
                }
320
                $message->result_status = NotifyMessage::STATUS_SUCCESS;
321
            } else {
322
                switch ($this->type) {
323
                    case self::TYPE_EVENT:
324
                        $this->setFailed();
325
                        \Yii::trace($this->name.' failed', $this->getLogname());
0 ignored issues
show
Deprecated Code introduced by
The method yii\BaseYii::trace() has been deprecated with message: since 2.0.14. Use [[debug()]] instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
326
                        break;
327
                    case self::TYPE_REPEAT:
328
                        $this->incrementCounter();
329
                        if ($this->fail_counter >= self::MAX_FAIL_COUNT) {
330
                            $this->setFailed();
331
                        } else {
332
                            $this->setActive();
333
                        }
334
                        \Yii::trace($this->name.' failed', $this->getLogname());
0 ignored issues
show
Deprecated Code introduced by
The method yii\BaseYii::trace() has been deprecated with message: since 2.0.14. Use [[debug()]] instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
335
                        break;
336
                    default:
337
                        $this->setFailed();
338
                        \Yii::error($this->name.' failed', $this->getLogname());
339
                        break;
340
                }
341
                $message->result_status = NotifyMessage::STATUS_FAULT;
342
            }
343
            $message->save();
344
        }
345
    }
346
347
    /**
348
     * Logging script output and return string representation
349
     * @param $output
350
     * @return string
351
     */
352
    private function printCommandResult($output)
353
    {
354
        $result = '';
355
        foreach ($output as $line) {
356
            \Yii::trace($line, $this->getLogname());
0 ignored issues
show
Deprecated Code introduced by
The method yii\BaseYii::trace() has been deprecated with message: since 2.0.14. Use [[debug()]] instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
357
            $result .= "$line\n";
358
        }
359
        return strlen($result) > 0 ? $result : '(no message)';
360
    }
361
362
    /**
363
     * Get log category
364
     * @return string
365
     */
366
    private function getLogname()
367
    {
368
        if ($this->logname == '') {
369
            $this->logname = 'background\task:'
370
                . ($this->name ? $this->name : 'undefined')
371
                . '\action:'
372
                . ($this->action ? $this->action : 'undefined');
373
        }
374
        return $this->logname;
375
    }
376
377
    /**
378
     * @inheritdoc
379
     */
380
    public function scenarios()
381
    {
382
        return [
383
            'default' => [
384
                'id',
385
                'type',
386
                'name',
387
                'description',
388
                'action',
389
                'params',
390
                'initiator',
391
                'init_event',
392
                'cron_expression',
393
                'ts',
394
                'status'
395
            ],
396
            'repeat' => [
397
                'id',
398
                'type',
399
                'name',
400
                'description',
401
                'action',
402
                'params',
403
                'initiator',
404
                'cron_expression',
405
                'ts',
406
                'status'
407
            ],
408
            'event' => [
409
                'id',
410
                'type',
411
                'name',
412
                'description',
413
                'action',
414
                'params',
415
                'initiator',
416
                'init_event',
417
                'ts',
418
                'status'
419
            ],
420
            'search' => [
421
                'id',
422
                'name',
423
                'description',
424
                'action',
425
                'params',
426
                'cron_expression',
427
                'ts',
428
                'status',
429
                'username'
430
            ],
431
        ];
432
    }
433
434
    /**
435
     * Search tasks
436
     * @param $params
437
     * @return ActiveDataProvider
438
     */
439
    public function search($params)
440
    {
441
        /* @var $query \yii\db\ActiveQuery */
442
        $query = self::find();
443
        $query->joinWith('initiatorUser');
444
445
        $dataProvider = new ActiveDataProvider(
446
            [
447
                'query' => $query,
448
                'pagination' => [
449
                    'pageSize' => 10,
450
                ],
451
            ]
452
        );
453
454
        $dataProvider->sort->attributes['username'] = [
455
            'asc' => [User::tableName().'.username' => SORT_ASC],
456
            'desc' => [User::tableName().'.username' => SORT_DESC],
457
        ];
458
459
        $query->andWhere($this->tableName().'.type = :type', [':type' => 'REPEAT']);
460
461
        if (!($this->load($params) && $this->validate())) {
462
            return $dataProvider;
463
        }
464
465
        $this->addCondition($query, $this->tableName(), 'id');
466
        $this->addCondition($query, $this->tableName(), 'name', true);
467
        $this->addCondition($query, $this->tableName(), 'description', true);
468
        $this->addCondition($query, $this->tableName(), 'action', true);
469
        $this->addCondition($query, $this->tableName(), 'params', true);
470
        $this->addCondition($query, $this->tableName(), 'cron_expression', true);
471
        $this->addCondition($query, $this->tableName(), 'ts', true);
472
        $this->addCondition($query, $this->tableName(), 'status');
473
        $this->addCondition($query, User::tableName(), 'username', true);
474
475
        return $dataProvider;
476
    }
477
478
    /**
479
     * @param bool $insert
480
     * @return bool
481
     */
482
    public function beforeSave($insert)
483
    {
484
        $result = parent::beforeSave($insert);
485
486
        $this->options = Json::encode($this->task_options);
487
488
        return $result;
489
    }
490
491
492
    /**
493
     * @param bool $insert
494
     * @param array $changedAttributes
495
     */
496
    public function afterSave($insert, $changedAttributes)
497
    {
498
        parent::afterSave($insert, $changedAttributes);
499
500
        if (empty($changedAttributes)) {
501
            return ;
502
        }
503
504
        if (!isset($this->task_options['create_notification']) || (false == $this->task_options['create_notification'])) {
505
            return ;
506
        }
507
508
        if (self::STATUS_ACTIVE === $this->status) {
509
            Notification::addNotification(
510
                $this->initiator,
511
                'Задание "'.$this->description.'" добавлено в очередь.',
512
                'Задание',
513
                'info'
514
            );
515
        } else if (self::STATUS_RUNNING === $this->status) {
516
            Notification::addNotification(
517
                $this->initiator,
518
                'Задание "'.$this->description.'" выполняется.',
519
                'Задание',
520
                'info'
521
            );
522
        } else if (self::STATUS_COMPLETED === $this->status) {
523
            Notification::addNotification(
524
                $this->initiator,
525
                'Задание "'.$this->description.'" успешно выполнено.',
526
                'Задание',
527
                'success'
528
            );
529
        } else if (self::STATUS_FAILED === $this->status) {
530
            Notification::addNotification(
531
                $this->initiator,
532
                'Задание "'.$this->description.'" завершилось с ошибкой.',
533
                'Задание',
534
                'danger'
535
            );
536
        }
537
    }
538
539
    /**
540
     *
541
     */
542
    public function afterFind()
543
    {
544
        parent::afterFind();
545
546
        $options = [];
547
        try {
548
            $options = Json::decode($this->options);
549
        } catch(\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
550
        }
551
552
        $this->task_options = $options;
0 ignored issues
show
Documentation Bug introduced by
It seems like $options of type * is incompatible with the declared type array of property $task_options.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
553
    }
554
}
555