WorkLog   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 131
Duplicated Lines 0 %

Test Coverage

Coverage 87.27%

Importance

Changes 0
Metric Value
eloc 63
dl 0
loc 131
ccs 48
cts 55
cp 0.8727
rs 10
c 0
b 0
f 0
wmc 13

5 Methods

Rating   Name   Duplication   Size   Complexity  
B beforeSave() 0 35 7
A attributeLabels() 0 7 1
A getProcess() 0 3 1
A init() 0 9 2
A rules() 0 42 2
1
<?php
2
3
namespace roaresearch\yii2\workflow\models;
4
5
use roaresearch\yii2\rmdb\models\Pivot;
6
use Yii;
7
use yii\{
8
    db\ActiveQuery,
9
    web\ForbiddenHttpException,
10
    web\BadRequestHttpException
11
};
12
13
/**
14
 * @property int $id
15
 * @property int $process_id
16
 * @property int $stage_id
17
 * @property string $comment
18
 *
19
 * @property Process $process
20
 */
21
abstract class WorkLog extends Pivot
22
{
23
    public const SCENARIO_INITIAL = 'initial';
24
    public const SCENARIO_FLOW = 'flow';
25
26
    /**
27
     * @return string class name for the process this worklog is attached to.
28
     */
29
    abstract protected function processClass(): string;
30
31
    /**
32
     * @inheritdoc
33
     */
34 8
    public function rules()
35
    {
36
        return [
37 8
            [['process_id'], 'required', 'except' => [self::SCENARIO_INITIAL]],
38
            [['stage_id'], 'required'],
39
            [['process_id', 'stage_id'], 'integer'],
40
            [['comment'], 'string', 'max' => 1024],
41
            [
42
                ['process_id'],
43 8
                'exist',
44
                'targetAttribute' => ['process_id' => 'id'],
45 8
                'targetClass' => $this->processClass(),
46 8
                'except' => [self::SCENARIO_INITIAL],
47
            ],
48
            [
49
                ['stage_id'],
50 8
                'exist',
51
                'targetAttribute' => ['stage_id' => 'id'],
52
                'targetClass' => Stage::class,
53 8
                'filter' => function ($query) {
54 3
                    $query->andWhere(['initial' => true]);
55 8
                },
56 8
                'on' => [self::SCENARIO_INITIAL],
57 8
                'message' => 'Not an initial stage for the workflow.'
58
            ],
59
            [
60
                ['stage_id'],
61 8
                'exist',
62
                'targetAttribute' => ['stage_id' => 'target_stage_id'],
63
                'targetClass' => Transition::class,
64 8
                'filter' => function ($query) {
65 2
                    $query->andWhere([
66 2
                        'source_stage_id' => $this->process->activeWorkLog
67 2
                            ->stage_id
68
                    ]);
69 8
                },
70 8
                'when' => function () {
71 2
                    return !$this->hasErrors('process_id')
72 2
                        && null !== $this->process->activeWorkLog;
73 8
                },
74 8
                'on' => [self::SCENARIO_FLOW],
75 8
                'message' => 'There is no transition for the current stage'
76
            ],
77
        ];
78
    }
79
80
    /**
81
     * @inheritdoc
82
     */
83 6
    public function beforeSave($insert)
84
    {
85 6
        if (!parent::beforeSave($insert)) {
86
            return false;
87
        }
88
89 6
        if (!$insert || $this->scenario == self::SCENARIO_INITIAL) {
90
            // editing a worklog or creating initial worklog
91 3
            return true;
92
        }
93
94 3
        $transition = Transition::find()->andWhere([
95 3
            'source_stage_id' => $this->process->activeWorkLog->stage_id,
96 3
            'target_stage_id' => $this->stage_id,
97 3
        ])->one();
98
99 3
        if (!isset($transition)) {
100
            throw new BadRequestHttpException('Stage not transitionable.');
101
        }
102
103 3
        if (!$this->process->userAssigned(Yii::$app->user->id)) {
0 ignored issues
show
Bug introduced by
It seems like Yii::app->user->id can also be of type string; however, parameter $userId of roaresearch\yii2\workflo...Process::userAssigned() does only seem to accept integer|null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

103
        if (!$this->process->userAssigned(/** @scrutinizer ignore-type */ Yii::$app->user->id)) {
Loading history...
104
            throw new ForbiddenHttpException(
105
                'You are not assigned to move this process.'
106
            );
107
        }
108
109 3
        if (!$transition->userCan(Yii::$app->user->id, $this->process)) {
110 2
            throw new ForbiddenHttpException(
111 2
                'You dont have permission for the transition.'
112
            );
113
        }
114
115 3
        unset($this->process->activeWorkLog);
116
117 3
        return true;
118
    }
119
120
    /**
121
     * @inheritdoc
122
     */
123 4
    public function attributeLabels()
124
    {
125 4
        return array_merge([
126 4
            'id' => 'ID',
127
            'process_id' => 'Process ID',
128
            'stage_id' => 'Stage ID',
129 4
        ], parent::attributeLabels());
130
    }
131
132
    /**
133
     * @inheritdoc
134
     */
135 12
    public function init()
136
    {
137 12
        if (!is_subclass_of($this->processClass(), Process::class)) {
138
            throw new InvalidConfigException(
0 ignored issues
show
Bug introduced by
The type roaresearch\yii2\workflo...\InvalidConfigException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
139
                static::class . '::processClass() must extend '
140
                    . Process::class
141
            );
142
        }
143 12
        parent::init();
144 12
    }
145
146
    /**
147
     * @return ActiveQuery
148
     */
149 10
    public function getProcess(): ActiveQuery
150
    {
151 10
        return $this->hasOne($this->processClass(), ['id' => 'process_id']);
152
    }
153
}
154