Passed
Push — master ( 536f48...741d19 )
by Carlos
01:52 queued 12s
created

WorkLog::attributeLabels()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 0
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 1
rs 10
c 0
b 0
f 0
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
 *
18
 * @property Process $process
19
 */
20
abstract class WorkLog extends Pivot
21
{
22
    public const SCENARIO_INITIAL = 'initial';
23
    public const SCENARIO_FLOW = 'flow';
24
25
    /**
26
     * @return string class name for the process this worklog is attached to.
27
     */
28
    abstract protected function processClass(): string;
29
30
    /**
31
     * @inheritdoc
32
     */
33 8
    public function rules()
34
    {
35
        return [
36 8
            [['process_id'], 'required', 'except' => [self::SCENARIO_INITIAL]],
37
            [['stage_id'], 'required'],
38
            [['process_id', 'stage_id'], 'integer'],
39
            [
40
                ['process_id'],
41 8
                'exist',
42
                'targetAttribute' => ['process_id' => 'id'],
43 8
                'targetClass' => $this->processClass(),
44 8
                'except' => [self::SCENARIO_INITIAL],
45
            ],
46
            [
47
                ['stage_id'],
48 8
                'exist',
49
                'targetAttribute' => ['stage_id' => 'id'],
50
                'targetClass' => Stage::class,
51 8
                'filter' => function ($query) {
52 3
                    $query->andWhere(['initial' => true]);
53 8
                },
54 8
                'on' => [self::SCENARIO_INITIAL],
55 8
                'message' => 'Not an initial stage for the workflow.'
56
            ],
57
            [
58
                ['stage_id'],
59 8
                'exist',
60
                'targetAttribute' => ['stage_id' => 'target_stage_id'],
61
                'targetClass' => Transition::class,
62 8
                'filter' => function ($query) {
63 2
                    $query->andWhere([
64 2
                        'source_stage_id' => $this->process->activeWorkLog
65 2
                            ->stage_id
66
                    ]);
67 8
                },
68 8
                'when' => function () {
69 2
                    return !$this->hasErrors('process_id')
70 2
                        && null !== $this->process->activeWorkLog;
71 8
                },
72 8
                'on' => [self::SCENARIO_FLOW],
73 8
                'message' => 'There is no transition for the current stage'
74
            ],
75
        ];
76
    }
77
78
    /**
79
     * @inheritdoc
80
     */
81 6
    public function beforeSave($insert)
82
    {
83 6
        if (!parent::beforeSave($insert)) {
84
            return false;
85
        }
86
87 6
        if (!$insert || $this->scenario == self::SCENARIO_INITIAL) {
88
            // editing a worklog or creating initial worklog
89 3
            return true;
90
        }
91
92 3
        $transition = Transition::find()->andWhere([
93 3
            'source_stage_id' => $this->process->activeWorkLog->stage_id,
94 3
            'target_stage_id' => $this->stage_id,
95 3
        ])->one();
96
97 3
        if (!isset($transition)) {
98
            throw new BadRequestHttpException('Stage not transitionable.');
99
        }
100
101 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

101
        if (!$this->process->userAssigned(/** @scrutinizer ignore-type */ Yii::$app->user->id)) {
Loading history...
102
            throw new ForbiddenHttpException(
103
                'You are not assigned to move this process.'
104
            );
105
        }
106
107 3
        if (!$transition->userCan(Yii::$app->user->id, $this->process)) {
108 2
            throw new ForbiddenHttpException(
109 2
                'You dont have permission for the transition.'
110
            );
111
        }
112
113 3
        unset($this->process->activeWorkLog);
114
115 3
        return true;
116
    }
117
118
    /**
119
     * @inheritdoc
120
     */
121 4
    public function attributeLabels()
122
    {
123 4
        return array_merge([
124 4
            'id' => 'ID',
125
            'process_id' => 'Process ID',
126
            'stage_id' => 'Stage ID',
127 4
        ], parent::attributeLabels());
128
    }
129
130
    /**
131
     * @inheritdoc
132
     */
133 10
    public function init()
134
    {
135 10
        if (!is_subclass_of($this->processClass(), Process::class)) {
136
            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...
137
                static::class . '::processClass() must extend '
138
                    . Process::class
139
            );
140
        }
141 10
        parent::init();
142 10
    }
143
    /**
144
     * @return ActiveQuery
145
     */
146 8
    public function getProcess(): ActiveQuery
147
    {
148 8
        return $this->hasOne($this->processClass(), ['id' => 'process_id']);
149
    }
150
}
151