Server   B
last analyzed

Complexity

Total Complexity 48

Size/Duplication

Total Lines 384
Duplicated Lines 0 %

Test Coverage

Coverage 1.74%

Importance

Changes 15
Bugs 0 Features 0
Metric Value
wmc 48
eloc 147
c 15
b 0
f 0
dl 0
loc 384
ccs 2
cts 115
cp 0.0174
rs 8.5599

34 Methods

Rating   Name   Duplication   Size   Complexity  
A getSwitches() 0 3 1
A isLiveCDSupported() 0 3 1
A isOperable() 0 7 3
A getMailSettings() 0 3 1
A goodStates() 0 3 1
A getBindings() 0 4 1
B rules() 0 71 1
A canRrd() 0 3 2
A getHardwareSettings() 0 3 1
A isDedicatedDevice() 0 3 1
A canFullRefuse() 0 7 2
A isStateGood() 0 3 1
A getMonitoringSettings() 0 3 1
A getBinding() 0 7 2
A groupUsesForCharts() 0 3 1
A getConsumptions() 0 3 1
A getPanel() 0 11 4
A getSoftwareSettings() 0 3 1
A getHardwareSales() 0 3 1
A isVNCSupported() 0 3 1
A checkOperable() 0 7 2
A getIps() 0 7 2
A scenarioActions() 0 5 1
A isPwChangeSupported() 0 3 1
A getUses() 0 3 1
A getIsBlocked() 0 3 1
A canEnableVNC() 0 3 2
A getSales() 0 3 1
A isVirtualDevice() 0 3 1
A getStateOptions() 0 6 1
A getTypeOptions() 0 3 1
A canControlPower() 0 9 4
A find() 0 4 1
A attributeLabels() 0 28 1

How to fix   Complexity   

Complex Class

Complex classes like Server 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.

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 Server, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Server module for HiPanel
4
 *
5
 * @link      https://github.com/hiqdev/hipanel-module-server
6
 * @package   hipanel-module-server
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2015-2019, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hipanel\modules\server\models;
12
13
use hipanel\base\Model;
14
use hipanel\base\ModelTrait;
15
use hipanel\models\Ref;
16
use hipanel\modules\finance\models\Sale;
17
use hipanel\modules\hosting\models\Ip;
0 ignored issues
show
Bug introduced by
The type hipanel\modules\hosting\models\Ip 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...
18
use hipanel\modules\server\helpers\ServerHelper;
19
use hipanel\modules\server\models\query\ServerQuery;
20
use hipanel\modules\server\models\traits\AssignSwitchTrait;
21
use hipanel\validators\EidValidator;
22
use hipanel\validators\RefValidator;
23
use Yii;
24
use yii\base\NotSupportedException;
25
26
/**
27
 * Class Server.
28
 *
29
 * @property int $id
30
 * @property string $name
31
 *
32
 * @property-read HardwareSale[] $hardwareSales
33
 * @property-read HardwareSettings $hardwareSettings
34
 */
35
class Server extends Model implements AssignSwitchInterface
36
{
37
    use ModelTrait, AssignSwitchTrait;
0 ignored issues
show
introduced by
The trait hipanel\modules\server\m...raits\AssignSwitchTrait requires some properties which are not provided by hipanel\modules\server\models\Server: $device_name, $typeWithNo, $bindings, $switch_name, $switch_id, $port, $type
Loading history...
38
39
    const STATE_OK = 'ok';
40
    const STATE_DISABLED = 'disabled';
41
    const STATE_BLOCKED = 'blocked';
42
    const STATE_DELETED = 'deleted';
43
44
    const VIRTUAL_DEVICES = ['avds', 'svds', 'ovds'];
45
46
    const SVDS_TYPES = ['avds', 'svds'];
47
48
    const DEFAULT_PANEL = 'rcp';
49
50 1
    public function rules()
51
    {
52
        return [
53 1
            [['show_last_sale'], 'boolean'],
54
            [['id', 'tariff_id', 'client_id', 'seller_id', 'mails_num'], 'integer'],
55
            [['osimage'], EidValidator::class],
56
            [['panel'], RefValidator::class],
57
            [
58
                [
59
                    'name', 'dc',
60
                    'client', 'seller',
61
                    'os', 'panel', 'rcp',
62
                    'parent_tariff', 'tariff', 'tariff_note', 'discounts',
63
                    'request_state', 'request_state_label',
64
                    'autorenewal',
65
                    'type', 'type_label', 'state', 'state_label', 'statuses',
66
                    'block_reason_label',
67
                    'running_task',
68
                    'ip', 'ips_num', 'mac',
69
                    'acs_num', 'del_acs_num', 'wizzarded',
70
                    'vnc',
71
                    'note', 'label', 'hwsummary', 'order_no', 'hwcomment',
72
                ],
73
                'safe',
74
            ],
75
            [['show_del', 'show_nic', 'show_vds', 'show_jail'], 'boolean'],
76
            [['switches', 'rack', 'net', 'kvm', 'pdu', 'ipmi'], 'safe'],
77
            [['last_expires', 'expires', 'status_time'], 'date'],
78
            [['time'], 'date', 'format' => 'php:Y-m-d H:i:s'],
79
            [
80
                ['state'],
81
                'isOperable',
82
                'on' => [
83
                    'reinstall',
84
                    'reboot',
85
                    'reset',
86
                    'shutdown',
87
                    'power-off',
88
                    'power-on',
89
                    'boot-live',
90
                    'regen-root-password',
91
                    'reset-password',
92
                ],
93
            ],
94
            [
95
                ['id'],
96
                'required',
97
                'on' => [
98
                    'refuse', 'delete', 'enable-autorenewal',
99
                    'enable-vnc', 'set-note', 'set-label',
100
                    'enable-block', 'disable-block', 'clear-resources',
101
                    'flush-switch-graphs',
102
                ],
103
            ],
104
            [
105
                ['id'],
106
                'integer',
107
                'on' => [
108
                    'refuse', 'delete', 'enable-autorenewal',
109
                    'enable-vnc', 'set-note', 'set-label',
110
                    'enable-block', 'disable-block',
111
                ],
112
            ],
113
            [['note'], 'string', 'max' => 50, 'on' => 'set-note'],
114
            [['id', 'osimage'], 'required', 'on' => ['reinstall']],
115
            [['id', 'osimage'], 'required', 'on' => ['boot-live']],
116
            [['type', 'comment'], 'required', 'on' => ['enable-block', 'disable-block']],
117
118
            [['tariff_id', 'sale_time'], 'required', 'on' => ['sale']],
119
            [['move_accounts'], 'safe', 'on' => ['sale']],
120
            [['id', 'type'], 'required', 'on' => ['set-type']],
121
        ];
122
    }
123
124
    /**
125
     * Determine good server states.
126
     *
127
     * @return array
128
     */
129
    public function goodStates()
130
    {
131
        return [static::STATE_OK, static::STATE_DISABLED];
132
    }
133
134
    /**
135
     * @return bool
136
     */
137
    public function isOperable()
138
    {
139
        if ($this->running_task || !$this->isStateGood()) {
0 ignored issues
show
Bug Best Practice introduced by
The property running_task does not exist on hipanel\modules\server\models\Server. Since you implemented __get, consider adding a @property annotation.
Loading history...
140
            return false;
141
        }
142
143
        return true;
144
    }
145
146
    public function canEnableVNC()
147
    {
148
        return $this->isVNCSupported() && $this->isStateGood();
149
    }
150
151
    public function isStateGood()
152
    {
153
        return in_array($this->state, $this->goodStates(), true);
0 ignored issues
show
Bug Best Practice introduced by
The property state does not exist on hipanel\modules\server\models\Server. Since you implemented __get, consider adding a @property annotation.
Loading history...
154
    }
155
156
    /**
157
     * Checks whether server supports VNC.
158
     *
159
     * @return bool
160
     */
161
    public function isVNCSupported()
162
    {
163
        return in_array($this->type, static::SVDS_TYPES, true);
0 ignored issues
show
Bug Best Practice introduced by
The property type does not exist on hipanel\modules\server\models\Server. Since you implemented __get, consider adding a @property annotation.
Loading history...
164
    }
165
166
    /**
167
     * Checks whether server supports root password change.
168
     *
169
     * @return bool
170
     */
171
    public function isPwChangeSupported()
172
    {
173
        return $this->type === 'ovds';
0 ignored issues
show
Bug Best Practice introduced by
The property type does not exist on hipanel\modules\server\models\Server. Since you implemented __get, consider adding a @property annotation.
Loading history...
174
    }
175
176
    /**
177
     * Checks whether server supports LiveCD.
178
     *
179
     * @return bool
180
     */
181
    public function isLiveCDSupported()
182
    {
183
        return in_array($this->type, static::SVDS_TYPES, true);
0 ignored issues
show
Bug Best Practice introduced by
The property type does not exist on hipanel\modules\server\models\Server. Since you implemented __get, consider adding a @property annotation.
Loading history...
184
    }
185
186
    /**
187
     * Check whether server is virtual.
188
     *
189
     * @return bool
190
     */
191
    public function isVirtualDevice()
192
    {
193
        return in_array($this->type, static::VIRTUAL_DEVICES, true);
0 ignored issues
show
Bug Best Practice introduced by
The property type does not exist on hipanel\modules\server\models\Server. Since you implemented __get, consider adding a @property annotation.
Loading history...
194
    }
195
196
    /**
197
     * Check whether server is dedicated.
198
     *
199
     * @return bool
200
     */
201
    public function isDedicatedDevice()
202
    {
203
        return $this->type === 'dedicated';
0 ignored issues
show
Bug Best Practice introduced by
The property type does not exist on hipanel\modules\server\models\Server. Since you implemented __get, consider adding a @property annotation.
Loading history...
204
    }
205
206
    public function getIsBlocked()
207
    {
208
        return $this->state === static::STATE_BLOCKED;
0 ignored issues
show
Bug Best Practice introduced by
The property state does not exist on hipanel\modules\server\models\Server. Since you implemented __get, consider adding a @property annotation.
Loading history...
209
    }
210
211
    /**
212
     * Checks whether server can be operated not.
213
     *
214
     * @throws NotSupportedException
215
     * @return bool
216
     * @see isOperable()
217
     */
218
    public function checkOperable()
219
    {
220
        if (!$this->isOperable()) {
221
            throw new NotSupportedException(Yii::t('hipanel:server', 'Server already has a running task. Can not start new.'));
222
        }
223
224
        return true;
225
    }
226
227
    /**
228
     * {@inheritdoc}
229
     */
230
    public function scenarioActions()
231
    {
232
        return [
233
            'reinstall' => 'resetup',
234
            'reset-password' => 'regen-root-password',
235
        ];
236
    }
237
238
    /**
239
     * During 5 days after the last expiration client is able to refuse server with full refund.
240
     * Method checks, whether 5 days passed.
241
     * @return bool
242
     */
243
    public function canFullRefuse()
244
    {
245
        if (!is_numeric($this->last_expires)) {
0 ignored issues
show
Bug Best Practice introduced by
The property last_expires does not exist on hipanel\modules\server\models\Server. Since you implemented __get, consider adding a @property annotation.
Loading history...
246
            return null; // In case server is not sold
247
        }
248
249
        return (time() - Yii::$app->formatter->asTimestamp($this->last_expires)) / 3600 / 24 < 5;
250
    }
251
252
    /**
253
     * @return bool
254
     */
255
    public function canRrd(): bool
256
    {
257
        return isset($this->ip) && isset($this->wizzarded);
0 ignored issues
show
Bug Best Practice introduced by
The property wizzarded does not exist on hipanel\modules\server\models\Server. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property ip does not exist on hipanel\modules\server\models\Server. Since you implemented __get, consider adding a @property annotation.
Loading history...
258
    }
259
260
    public function groupUsesForCharts()
261
    {
262
        return ServerHelper::groupUsesForChart($this->uses);
0 ignored issues
show
Bug Best Practice introduced by
The property uses does not exist on hipanel\modules\server\models\Server. Since you implemented __get, consider adding a @property annotation.
Loading history...
263
    }
264
265
    public function getUses()
266
    {
267
        return $this->hasMany(ServerUse::class, ['object_id' => 'id']);
268
    }
269
270
    public function getIps()
271
    {
272
        if (Yii::getAlias('@ip', false)) {
273
            return $this->hasMany(Ip::class, ['device_id' => 'id'])->joinWith('links');
274
        }
275
276
        return [];
277
    }
278
279
    public function getSwitches()
280
    {
281
        return $this->hasMany(Server::class, ['obj_id' => 'id']);
282
    }
283
284
    public function getConsumptions()
285
    {
286
        return $this->hasMany(Consumption::class, ['object_id' => 'id'])->indexBy('type');
287
    }
288
289
    public function getBindings()
290
    {
291
        return $this->hasMany(Binding::class, ['device_id' => 'id'])->indexBy(function ($binding) {
292
            return $binding->typeWithNo;
293
        });
294
    }
295
296
    public function getSales()
297
    {
298
        return $this->hasMany(Sale::class, ['id' => 'object_id']);
299
    }
300
301
    public function getMonitoringSettings()
302
    {
303
        return $this->hasOne(MonitoringSettings::class, ['id' => 'id']);
304
    }
305
306
    public function getHardwareSettings()
307
    {
308
        return $this->hasOne(HardwareSettings::class, ['id' => 'id']);
309
    }
310
311
    public function getHardwareSales()
312
    {
313
        return $this->hasMany(HardwareSale::class, ['id' => 'id']);
314
    }
315
316
    public function getSoftwareSettings()
317
    {
318
        return $this->hasOne(SoftwareSettings::class, ['id' => 'id']);
319
    }
320
321
    public function getMailSettings()
322
    {
323
        return $this->hasOne(MailSettings::class, ['id' => 'id']);
324
    }
325
326
    public function getBinding($type)
327
    {
328
        if (!isset($this->bindings[$type])) {
0 ignored issues
show
Bug Best Practice introduced by
The property bindings does not exist on hipanel\modules\server\models\Server. Since you implemented __get, consider adding a @property annotation.
Loading history...
329
            return null;
330
        }
331
332
        return $this->bindings[$type];
333
    }
334
335
    public function getPanel()
336
    {
337
        if ($this->state === self::STATE_DISABLED) {
0 ignored issues
show
Bug Best Practice introduced by
The property state does not exist on hipanel\modules\server\models\Server. Since you implemented __get, consider adding a @property annotation.
Loading history...
338
            return null;
339
        }
340
341
        if ($this->panel || $this->isVirtualDevice()) {
0 ignored issues
show
Bug Best Practice introduced by
The property panel does not exist on hipanel\modules\server\models\Server. Since you implemented __get, consider adding a @property annotation.
Loading history...
342
            return $this->panel;
343
        }
344
345
        return self::DEFAULT_PANEL;
346
    }
347
348
    /**
349
     * {@inheritdoc}
350
     */
351
    public function attributeLabels()
352
    {
353
        return $this->mergeAttributeLabels([
354
            'remoteid' => Yii::t('hipanel:server', 'Remote ID'),
355
            'name' => Yii::t('hipanel:server', 'Name'),
356
            'dc' => Yii::t('hipanel:server', 'DC'),
357
            'net' => Yii::t('hipanel:server', 'Switch'),
358
            'kvm' => Yii::t('hipanel:server', 'KVM'),
359
            'pdu' => Yii::t('hipanel:server', 'APC'),
360
            'rack' => Yii::t('hipanel:server', 'Rack'),
361
            'ipmi' => Yii::t('hipanel:server', 'IPMI'),
362
            'status_time' => Yii::t('hipanel:server', 'Status update time'),
363
            'block_reason_label' => Yii::t('hipanel:server', 'Block reason label'),
364
            'request_state_label' => Yii::t('hipanel:server', 'Request state label'),
365
            'mac' => Yii::t('hipanel:server', 'MAC'),
366
            'ips' => Yii::t('hipanel:server', 'IPs'),
367
            'label' => Yii::t('hipanel:server', 'Internal note'),
368
            'os' => Yii::t('hipanel:server', 'OS'),
369
            'comment' => Yii::t('hipanel:server', 'Comment'),
370
            'hwsummary' => Yii::t('hipanel:server', 'Hardware Summary'),
371
            'hwcomment' => Yii::t('hipanel:server', 'Hardware Comment'),
372
            'sale_time' => Yii::t('hipanel:server', 'Sale time'),
373
            'expires' => Yii::t('hipanel:server', 'Expires'),
374
            'tariff_id' => Yii::t('hipanel:server', 'Tariff'),
375
            'order_no' => Yii::t('hipanel:server', 'Order'),
376
            'move_accounts' => Yii::t('hipanel:server', 'Move accounts to new client'),
377
            'server' => Yii::t('hipanel:server', 'Server name'),
378
            'mails_num' => Yii::t('hipanel:server', 'Number of mailboxes'),
379
        ]);
380
    }
381
382
    public function getTypeOptions(): array
383
    {
384
        return Ref::getList('type,device,server', 'hipanel:server');
385
    }
386
387
    public function getStateOptions(): array
388
    {
389
        return [
390
            self::STATE_DISABLED    => Yii::t('hipanel:server', 'Ok, panel OFF'),
391
            self::STATE_OK          => Yii::t('hipanel:server', 'Ok'),
392
            self::STATE_BLOCKED     => Yii::t('hipanel:server', 'Blocked'),
393
        ];
394
    }
395
396
    /**
397
     * {@inheritdoc}
398
     * @return ServerQuery
399
     */
400
    public static function find($options = [])
401
    {
402
        return new ServerQuery(get_called_class(), [
403
            'options' => $options,
404
        ]);
405
    }
406
407
    /**
408
     * @return bool
409
     */
410
    public function canControlPower(): bool
411
    {
412
        $powerManagementAllowed = Yii::$app->params['module.server.power.management.allowed'];
413
414
        $userCanControlPower = Yii::$app->user->can('support') &&
0 ignored issues
show
Bug introduced by
The method can() does not exist on null. ( Ignorable by Annotation )

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

414
        $userCanControlPower = Yii::$app->user->/** @scrutinizer ignore-call */ can('support') &&

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
415
            (Yii::$app->user->can('server.control-system') ||
416
            Yii::$app->user->can('server.control-power'));
417
418
        return $powerManagementAllowed || $userCanControlPower;
419
    }
420
}
421