Completed
Push3d7113...c00f94
errored — Build
created

AuditController   B

↳ Parent: Project

Coupling/Cohesion

Components 1
Dependencies 9

Complexity

Total Complexity 43

Size/Duplication

Total Lines 270
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 270
rs 8.3157
c 0
b 0
f 0
wmc 43
lcom 1
cbo 9

7 Methods

Rating   Name   Duplication   Size   Complexity  
A options() 0 7 2
D actionCleanup() 0 41 10
D preCleanupSummary() 0 38 9
A cleanupEntry() 0 20 4
D cleanupEntrySolo() 0 29 10
A cleanupPanel() 0 21 4
B actionErrorEmail() 0 43 4

How to fix   Complexity   

Complex Class

Complex classes like AuditController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AuditController, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace bedezign\yii2\audit\commands;
4
5
use bedezign\yii2\audit\Audit;
6
use bedezign\yii2\audit\components\panels\Panel;
7
use bedezign\yii2\audit\models\AuditEntry;
8
use bedezign\yii2\audit\models\AuditError;
9
use Yii;
10
use yii\base\Exception;
11
use yii\console\Controller;
12
use yii\helpers\Console;
13
use yii\helpers\Html;
14
use yii\helpers\Url;
15
16
/**
17
 * Task runner commands for Audit.
18
 *
19
 * @package bedezign\yii2\audit\commands
20
 */
21
class AuditController extends Controller
22
{
23
24
    /**
25
     * @var bool True to cleanup the AuditEntry.
26
     */
27
    public $entry;
28
29
    /**
30
     * @var bool True to cleanup solo AuditEntry records (no trail/mail/error/javascript).
31
     */
32
    public $entrySolo;
33
34
    /**
35
     * @var string|null Comma separated list of panels to cleanup.
36
     */
37
    public $panels;
38
39
    /**
40
     * @var int|null Max age in days to cleanup, if null then the panel settings are used.
41
     */
42
    public $age;
43
44
    /**
45
     * @inheritdoc
46
     */
47
    public function options($actionID)
48
    {
49
        return array_merge(
50
            parent::options($actionID),
51
            ($actionID == 'cleanup') ? ['entry', 'entrySolo', 'panels', 'age'] : []
52
        );
53
    }
54
55
    /**
56
     * Cleanup the Audit data
57
     *
58
     * @return int|void
59
     */
60
    public function actionCleanup()
61
    {
62
        /** @var Audit $audit */
63
        $audit = Yii::$app->getModule(Audit::findModuleIdentifier());
64
        if ($this->panels === '') {
65
            $panels = [];
66
        } else {
67
            $panels = !empty($this->panels) ? explode(',', $this->panels) : array_keys($audit->panels);
68
        }
69
70
        // summary
71
        $this->preCleanupSummary($this->entry, $this->entrySolo, $panels, $this->age);
72
73
        // confirm
74
        if ($this->confirm('Cleanup the above data?')) {
75
            // cleanup panels
76
            foreach ($panels as $id) {
77
                if (!$this->cleanupPanel($id, $this->age)) {
78
                    $this->stdout("\nCleanup failed. The rest of the cleanups are canceled.\n", Console::FG_RED);
79
                    return self::EXIT_CODE_ERROR;
80
                }
81
            }
82
            // cleanup audit_entry
83
            if ($this->entry) {
84
                if (!$this->cleanupEntry($this->age)) {
85
                    $this->stdout("\nCleanup failed.\n", Console::FG_RED);
86
                    return self::EXIT_CODE_ERROR;
87
                }
88
            }
89
            // cleanup solo audit_entry
90
            if ($this->entrySolo) {
91
                if (!$this->cleanupEntrySolo()) {
92
                    $this->stdout("\nCleanup failed.\n", Console::FG_RED);
93
                    return self::EXIT_CODE_ERROR;
94
                }
95
            }
96
            // success!
97
            $this->stdout("\nCleanup was successful.\n", Console::FG_GREEN);
98
        }
99
        return self::EXIT_CODE_NORMAL;
100
    }
101
102
    /**
103
     * Displays a summary of the data and dates to clean
104
     *
105
     * @param bool $entry
106
     * @param bool $entrySolo
107
     * @param array $panels
108
     * @param int|null $maxAge
109
     */
110
    protected function preCleanupSummary($entry, $entrySolo, $panels, $maxAge)
111
    {
112
        $audit = Audit::getInstance();
113
114
        // heading
115
        $n = count($panels);
116
        $this->stdout("Total $n " . ($n === 1 ? 'cleanup' : 'cleanups') . " to be applied:\n", Console::FG_YELLOW);
117
        $this->stdout("\t" . 'DATA                      CLEANUP TO DATETIME' . "\n");
118
        $this->stdout("\t" . '---------------------------------------------' . "\n");
119
120
        // audit panels
121
        foreach ($panels as $id) {
122
            /** @var Panel $panel */
123
            $panel = $audit->getPanel($id);
124
            $age = $maxAge !== null ? $maxAge : $panel->maxAge;
125
            $dots = str_repeat('.', 24 - strlen($id));
126
            if ($age !== null) {
127
                $date = date('Y-m-d 23:59:59', strtotime("-$age days"));
128
                $this->stdout("\t" . $id . ' ' . $dots . ' ' . $date . "\n");
129
            } else {
130
                $this->stdout("\t" . $id . ' ' . $dots . ' no maxAge, skipping' . "\n");
131
            }
132
        }
133
134
        // audit entry
135
        if ($entry) {
136
            $maxAge = $maxAge !== null ? $maxAge : $audit->maxAge;
137
            $date = $maxAge !== null ? date('Y-m-d 23:59:59', strtotime("-$maxAge days")) : 'no maxAge, skipping';
138
            $this->stdout("\t" . 'AuditEntry .............. ' . $date . "\n");
139
        }
140
141
        // audit entry solo
142
        if ($entrySolo) {
143
            $this->stdout("\t" . 'AuditEntry solo ......... ' . date('Y-m-d 23:59:59') . "\n");
144
        }
145
146
        $this->stdout("\n");
147
    }
148
149
    /**
150
     * Cleans the AuditEntry data
151
     *
152
     * @param $maxAge
153
     * @return bool
154
     */
155
    protected function cleanupEntry($maxAge)
156
    {
157
        $maxAge = $maxAge !== null ? $maxAge : Audit::getInstance()->maxAge;
158
        if ($maxAge === null) {
159
            $this->stdout("\n*** skipped AuditEntry\n", Console::FG_PURPLE);
160
            return true;
161
        }
162
        $date = date('Y-m-d 23:59:59', strtotime("-$maxAge days"));
163
        $this->stdout("\n*** cleaning AuditEntry", Console::FG_YELLOW);
164
        $start = microtime(true);
165
        $count = AuditEntry::deleteAll(['<=', 'created', $date]);
166
        if ($count !== false) {
167
            $time = microtime(true) - $start;
168
            $this->stdout("\n*** cleaned AuditEntry (records: " . $count . ",time: " . sprintf("%.3f", $time) . "s)\n", Console::FG_GREEN);
169
            return true;
170
        }
171
        $time = microtime(true) - $start;
172
        $this->stdout("\n*** failed to clean AuditEntry (time: " . sprintf("%.3f", $time) . "s)\n", Console::FG_RED);
173
        return false;
174
    }
175
176
    /**
177
     * Cleans the AuditEntry solo data (no trail/mail/error/javascript)
178
     *
179
     * @return bool
180
     */
181
    protected function cleanupEntrySolo()
182
    {
183
        $this->stdout("\n*** cleaning AuditEntry solo", Console::FG_YELLOW);
184
        $start = microtime(true);
185
        $count = 0;
186
        foreach (AuditEntry::find()->each(100) as $auditEntry) {
187
            /** @var AuditEntry $auditEntry */
188
            /** @var Audit $audit */
189
            $audit = Yii::$app->getModule('audit');
190
            $auditEntryCurrent = $audit->getEntry();
191
            if ($auditEntryCurrent && $auditEntryCurrent->id == $auditEntry->id) {
192
                continue;
193
            }
194
            if (!$auditEntry->errors && !$auditEntry->javascripts && !$auditEntry->mails && !$auditEntry->trails) {
195
                foreach ($auditEntry->data as $data) {
196
                    $data->delete();
197
                }
198
                try {
199
                    $auditEntry->delete();
200
                    $count++;
201
                    $this->stdout('.', Console::FG_CYAN);
202
                } catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by cornernote
Consider adding a comment why this CATCH block is empty.
Loading history...
203
                }
204
            }
205
        }
206
        $time = microtime(true) - $start;
207
        $this->stdout("\n*** cleaned AuditEntry (records: " . $count . ",time: " . sprintf("%.3f", $time) . "s)\n", Console::FG_GREEN);
208
        return true;
209
    }
210
211
    /**
212
     * Cleans the Panel data
213
     *
214
     * @param $id
215
     * @param $maxAge
216
     * @return bool
217
     */
218
    protected function cleanupPanel($id, $maxAge)
219
    {
220
        /** @var Panel $panel */
221
        $panel = Audit::getInstance()->getPanel($id);
222
        $age = $maxAge !== null ? $maxAge : $panel->maxAge;
223
        if ($age === null) {
224
            $this->stdout("\n*** skipped $id\n", Console::FG_PURPLE);
225
            return true;
226
        }
227
        $this->stdout("\n*** cleaning $id", Console::FG_YELLOW);
228
        $start = microtime(true);
229
        $count = $panel->cleanup($maxAge);
230
        if ($count !== false) {
231
            $time = microtime(true) - $start;
232
            $this->stdout("\n*** cleaned $id (records: " . $count . ", time: " . sprintf("%.3f", $time) . "s)\n", Console::FG_GREEN);
233
            return true;
234
        }
235
        $time = microtime(true) - $start;
236
        $this->stdout("\n*** failed to clean $id (time: " . sprintf("%.3f", $time) . "s)\n", Console::FG_RED);
237
        return false;
238
    }
239
240
    /**
241
     * Email errors to support email.
242
     *
243
     * @param string|null $email
244
     * @return int
245
     */
246
    public function actionErrorEmail($email = null)
247
    {
248
        $email = $email ? $email : Yii::$app->params['supportEmail'];
249
250
        // find all errors to email
251
        $batch = AuditError::find()->where(['emailed' => 0])->batch();
252
        foreach ($batch as $auditErrors) {
253
            /** @var AuditError $model */
254
            foreach ($auditErrors as $model) {
255
256
                // define params and message
257
                $url = ['audit/default/view', 'id' => $model->entry_id];
258
                $params = [
259
                    'entry_id' => $model->entry_id,
260
                    'message' => $model->message,
261
                    'file' => $model->file,
262
                    'line' => $model->line,
263
                    'url' => Url::to($url),
264
                    'link' => Html::a(Yii::t('audit', 'view audit entry'), $url),
265
                ];
266
                $message = [
267
                    'subject' => Yii::t('audit', 'Audit Error in Audit Entry #{entry_id}', $params),
268
                    'text' => Yii::t('audit', '{message}' . "\n" . 'in {file} on line {line}.' . "\n" . '-- {url}', $params),
269
                    'html' => Yii::t('audit', '<b>{message}</b><br />in <i>{file}</i> on line <i>{line}</i>.<br/>-- {link}', $params),
270
                ];
271
272
                // send email
273
                Yii::$app->mailer->compose()
274
                    ->setFrom([$email => 'Audit :: ' . Yii::$app->name])
275
                    ->setTo($email)
276
                    ->setSubject($message['subject'])
277
                    ->setTextBody($message['text'])
278
                    ->setHtmlBody($message['html'])
279
                    ->send();
280
281
                // mark as emailed
282
                $model->emailed = 1;
283
                $model->save(false, ['emailed']);
284
285
            }
286
        }
287
        return self::EXIT_CODE_NORMAL;
288
    }
289
290
}
291