RecurrenceService   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 135
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
eloc 69
c 2
b 0
f 1
dl 0
loc 135
rs 10
wmc 22

6 Methods

Rating   Name   Duplication   Size   Complexity  
A updateAllExecutionDate() 0 15 2
B getExecutionDate() 0 37 11
A findCurrentOne() 0 6 2
A updateStatus() 0 13 4
A countByTransactionId() 0 5 1
A updateAllLegalWorkingDay() 0 11 2
1
<?php
2
3
namespace app\core\services;
4
5
use app\core\exceptions\InvalidArgumentException;
6
use app\core\exceptions\ThirdPartyServiceErrorException;
7
use app\core\helpers\HolidayHelper;
8
use app\core\models\Recurrence;
9
use app\core\traits\SendRequestTrait;
10
use app\core\traits\ServiceTrait;
11
use app\core\types\RecurrenceFrequency;
12
use app\core\types\RecurrenceStatus;
13
use Yii;
14
use yii\base\BaseObject;
15
use yii\base\InvalidConfigException;
16
use yii\db\Exception;
17
use yii\web\NotFoundHttpException;
18
use yiier\helpers\Setup;
19
20
class RecurrenceService extends BaseObject
21
{
22
    use SendRequestTrait;
23
    use ServiceTrait;
24
25
    /**
26
     * @param int $id
27
     * @param string $status
28
     * @return Recurrence
29
     * @throws Exception
30
     * @throws InvalidConfigException
31
     * @throws NotFoundHttpException
32
     * @throws InvalidArgumentException
33
     */
34
    public function updateStatus(int $id, string $status): Recurrence
35
    {
36
        $model = $this->findCurrentOne($id);
37
        $model->load($model->toArray(), '');
38
        if (RecurrenceStatus::ACTIVE == RecurrenceStatus::toEnumValue($status)) {
39
            $model->started_at = strtotime($model->started_at) > time() ? $model->started_at : 'now';
0 ignored issues
show
Bug introduced by
It seems like $model->started_at can also be of type null; however, parameter $datetime of strtotime() does only seem to accept string, 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

39
            $model->started_at = strtotime(/** @scrutinizer ignore-type */ $model->started_at) > time() ? $model->started_at : 'now';
Loading history...
40
        }
41
        $model->started_at = Yii::$app->formatter->asDate($model->started_at);
42
        $model->status = $status;
0 ignored issues
show
Documentation Bug introduced by
It seems like $status of type string is incompatible with the declared type integer|null of property $status.

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...
43
        if (!$model->save()) {
44
            throw new Exception(Setup::errorMessage($model->firstErrors));
45
        }
46
        return $model;
47
    }
48
49
50
    /**
51
     * @param int $id
52
     * @return Recurrence|object
53
     * @throws NotFoundHttpException
54
     */
55
    public function findCurrentOne(int $id): Recurrence
56
    {
57
        if (!$model = Recurrence::find()->where(['id' => $id, 'user_id' => \Yii::$app->user->id])->one()) {
58
            throw new NotFoundHttpException('No data found');
59
        }
60
        return $model;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $model returns the type array which is incompatible with the type-hinted return app\core\models\Recurrence.
Loading history...
61
    }
62
63
    /**
64
     * @param Recurrence $recurrence
65
     * @return string|null
66
     * @throws InvalidConfigException
67
     * @throws \Exception
68
     */
69
    public static function getExecutionDate(Recurrence $recurrence)
70
    {
71
        $formatter = Yii::$app->formatter;
72
        switch ($recurrence->frequency) {
73
            case RecurrenceFrequency::DAY:
74
                $date = strtotime("+1 day", strtotime($recurrence->started_at));
0 ignored issues
show
Bug introduced by
It seems like $recurrence->started_at can also be of type null; however, parameter $datetime of strtotime() does only seem to accept string, 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

74
                $date = strtotime("+1 day", strtotime(/** @scrutinizer ignore-type */ $recurrence->started_at));
Loading history...
75
                break;
76
            case RecurrenceFrequency::WEEK:
77
                $currentWeekDay = $formatter->asDatetime('now', 'php:N') - 1;
78
                $weekDay = $recurrence->schedule;
79
                $addDay = $currentWeekDay > $weekDay ? 7 - $currentWeekDay + $weekDay : $weekDay - $currentWeekDay;
80
                $date = strtotime("+{$addDay} day", strtotime($recurrence->started_at));
81
                break;
82
83
            case RecurrenceFrequency::MONTH:
84
                $currDay = $formatter->asDatetime('now', 'php:d');
85
                $d = $recurrence->schedule;
86
                $date = Yii::$app->formatter->asDatetime($currDay > $d ? strtotime('+1 month') : time(), 'php:Y-m');
87
                $d = sprintf("%02d", $d);
88
                return "{$date}-{$d}";
89
            case RecurrenceFrequency::YEAR:
90
                $m = current(explode('-', $recurrence->schedule));
0 ignored issues
show
Bug introduced by
It seems like $recurrence->schedule can also be of type null; however, parameter $string of explode() does only seem to accept string, 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

90
                $m = current(explode('-', /** @scrutinizer ignore-type */ $recurrence->schedule));
Loading history...
91
                $currMonth = $formatter->asDatetime('now', 'php:m');
92
                $y = Yii::$app->formatter->asDatetime($currMonth > $m ? strtotime('+1 year') : time(), 'php:Y');
93
                return "{$y}-{$recurrence->schedule}";
94
            case RecurrenceFrequency::WORKING_DAY:
95
                if (($currentWeekDay = $formatter->asDatetime('now', 'php:N') - 1) > 5) {
0 ignored issues
show
Unused Code introduced by
The assignment to $currentWeekDay is dead and can be removed.
Loading history...
96
                    return null;
97
                }
98
                $date = strtotime("+1 day", strtotime($recurrence->started_at));
99
                break;
100
            case RecurrenceFrequency::LEGAL_WORKING_DAY:
101
                return HolidayHelper::getNextWorkday();
102
            default:
103
                return null;
104
        }
105
        return $formatter->asDatetime($date, 'php:Y-m-d');
106
    }
107
108
    /**
109
     * @param int $transactionId
110
     * @param int $userId
111
     * @return bool|int|string|null
112
     */
113
    public static function countByTransactionId(int $transactionId, int $userId)
114
    {
115
        return Recurrence::find()
116
            ->where(['user_id' => $userId, 'transaction_id' => $transactionId])
117
            ->count();
118
    }
119
120
    /**
121
     * @throws InvalidConfigException|ThirdPartyServiceErrorException
122
     */
123
    public static function updateAllExecutionDate()
124
    {
125
        $items = Recurrence::find()
126
            ->where(['status' => RecurrenceStatus::ACTIVE])
127
            ->andWhere(['!=', 'frequency', RecurrenceFrequency::LEGAL_WORKING_DAY])
128
            ->all();
129
        /** @var Recurrence $item */
130
        foreach ($items as $item) {
131
            $date = self::getExecutionDate($item);
132
            Recurrence::updateAll(
133
                ['execution_date' => $date, 'updated_at' => Yii::$app->formatter->asDatetime('now')],
134
                ['id' => $item->id]
0 ignored issues
show
Bug introduced by
Accessing id on the interface yii\db\ActiveRecordInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
135
            );
136
        }
137
        self::updateAllLegalWorkingDay();
138
    }
139
140
    /**
141
     * @throws InvalidConfigException
142
     * @throws ThirdPartyServiceErrorException
143
     */
144
    private static function updateAllLegalWorkingDay()
145
    {
146
        $items = Recurrence::find()
147
            ->where(['frequency' => RecurrenceFrequency::LEGAL_WORKING_DAY, 'status' => RecurrenceStatus::ACTIVE])
148
            ->asArray()
149
            ->all();
150
        $nextWorkday = HolidayHelper::getNextWorkday();
151
        foreach ($items as $key => $item) {
152
            Recurrence::updateAll(
153
                ['execution_date' => $nextWorkday, 'updated_at' => Yii::$app->formatter->asDatetime('now')],
154
                ['id' => $item['id']]
155
            );
156
        }
157
    }
158
}
159