Passed
Push — master ( 69a393...54385f )
by Pedro
02:00
created

BotParser   F

Complexity

Total Complexity 62

Size/Duplication

Total Lines 466
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 62
eloc 264
dl 0
loc 466
rs 3.44
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A parseAlignment() 0 15 4
B parseUniqueItem() 0 37 10
A sumFields() 0 7 2
A getItems() 0 25 4
A __construct() 0 3 1
A secondsToTime() 0 11 2
B getQuestData() 0 40 11
A getScoreboard() 0 23 4
A getCoordinates() 0 16 3
C getDatabase() 0 140 10
B getEvents() 0 27 7
A getPlayers() 0 17 4

How to fix   Complexity   

Complex Class

Complex classes like BotParser 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 BotParser, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Application\Service;
4
5
use Carbon\Carbon;
6
7
class BotParser
8
{
9
    const ITEMS = [
10
        'amulet',
11
        'boots',
12
        'charm',
13
        'gloves',
14
        'helm',
15
        'leggings',
16
        'ring',
17
        'shield',
18
        'tunic',
19
        'weapon',
20
    ];
21
    const PENALTIES = [
22
        'kick',
23
        'logout',
24
        'msg',
25
        'nick',
26
        'part',
27
        'quest',
28
        'quit',
29
    ];
30
    private $config;
31
32
    public function __construct(array $config)
33
    {
34
        $this->config = $config;
35
    }
36
37
    /**
38
     * Converts a DateInterval to a human readable format
39
     * Returns 'None' if the difference is zero
40
     * @param int $seconds
41
     * @return string
42
     */
43
    private function secondsToTime(int $seconds)
44
    {
45
        $result = 'None';
46
47
        if ($seconds > 0) {
48
            $dtF = new Carbon('@0');
49
            $dtT = new Carbon("@$seconds");
50
            $result = $dtF->diffForHumans($dtT, true, false, 2);
51
        }
52
53
        return $result;
54
    }
55
56
    /**
57
     * Returns the alignment
58
     * @param string $alignment
59
     * @return string
60
     */
61
    private function parseAlignment(string $alignment)
62
    {
63
        $align = "";
64
        switch ($alignment) {
65
            case 'n':
66
                $align = "Neutral";
67
                break;
68
            case 'e':
69
                $align = "Evil";
70
                break;
71
            case 'g':
72
                $align = "Good";
73
                break;
74
        }
75
        return $align;
76
    }
77
78
    /**
79
     * Returns the name of item if it is unique, or null if it isn't
80
     * @param mixed $item_value
81
     * @return null|string
82
     */
83
    private function parseUniqueItem($item_value)
84
    {
85
        $result = null;
86
87
        $regex = '/\d+([a-h])/';
88
        preg_match($regex, $item_value, $matches);
89
90
        if (isset($matches[1])) {
91
            switch ($matches[1]) {
92
                case 'a':
93
                    $result = "Mattt's Omniscience Grand Crown";
94
                    break;
95
                case 'b':
96
                    $result = "Res0's Protectorate Plate Mail";
97
                    break;
98
                case 'c':
99
                    $result = "Dwyn's Storm Magic Amulet";
100
                    break;
101
                case 'd':
102
                    $result = "Jotun's Fury Colossal Sword";
103
                    break;
104
                case 'e':
105
                    $result = "Drdink's Cane of Blind Rage";
106
                    break;
107
                case 'f':
108
                    $result = "Mrquick's Magical Boots of Swiftness";
109
                    break;
110
                case 'g':
111
                    $result = "Jeff's Cluehammer of Doom";
112
                    break;
113
                case 'h':
114
                    $result = "Juliet's Glorious Ring of Sparkliness";
115
                    break;
116
            }
117
        }
118
119
        return $result;
120
    }
121
122
    /**
123
     * Sums the values from the keys of the array $record from $start till $end
124
     * @param array $record
125
     * @param int $start
126
     * @param int $end
127
     * @return int
128
     */
129
    private function sumFields(array $record, int $start, int $end)
130
    {
131
        $total = 0;
132
        for ($i = $start; $i <= $end; $i++) {
133
            $total += (int) $record[$i];
134
        }
135
        return $total;
136
    }
137
138
    /**
139
     * Returns an array with a list of all the Items from the database
140
     * @return array
141
     */
142
    public function getItems()
143
    {
144
        $items = [];
145
        $row = 0;
146
        if (($handle = fopen($this->config['bot_item'], "r")) !== false) {
147
            while (($data = fgetcsv($handle, 1024, "\t")) !== false) {
148
                $row++;
149
                if ($row == 1) {
150
                    continue;
151
                }
152
153
                $record = [
154
                    'x_pos' => (int) $data[0],
155
                    'y_pos' => (int) $data[1],
156
                    'type'  => $data[2],
157
                    'level' => $data[3],
158
                    'age'   => $data[4]
159
                ];
160
161
                $items[] = $record;
162
            }
163
            fclose($handle);
164
        }
165
166
        return $items;
167
    }
168
169
    /**
170
     * Returns an array with the Players, sorted by level
171
     * Includes the fields needed for the scoreboard page
172
     * @return array
173
     */
174
    public function getScoreboard()
175
    {
176
        $players = [];
177
        $row = 0;
178
        if (($handle = fopen($this->config['bot_db'], "r")) !== false) {
179
            while (($data = fgetcsv($handle, 1024, "\t")) !== false) {
180
                $row++;
181
                if ($row == 1) {
182
                    continue;
183
                }
184
                $players[] = [
185
                    'nick'   => $data[0],
186
                    'level'  => (int) $data[3],
187
                    'class'  => $data[4],
188
                    'ttl'    => (int) $data[5],
189
                    'status' => (bool) $data[8],
190
                ];
191
            }
192
            fclose($handle);
193
        }
194
        array_multisort(array_column($players, 'level'), SORT_DESC, $players);
0 ignored issues
show
Bug introduced by
array_column($players, 'level') cannot be passed to array_multisort() as the parameter $arr expects a reference. ( Ignorable by Annotation )

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

194
        array_multisort(/** @scrutinizer ignore-type */ array_column($players, 'level'), SORT_DESC, $players);
Loading history...
195
196
        return $players;
197
    }
198
199
    /**
200
     * Returns a list with (almost) all the fields from the Players database
201
     * If the parameter $nick is used, only returns the data for that Player
202
     * or 0 if that Player doesn't exist
203
     * @param string|null $nick
204
     * @return array|int|mixed
205
     */
206
    public function getDatabase(string $nick = null)
207
    {
208
        $database = [];
209
        $row = 0;
210
        if (($handle = fopen($this->config['bot_db'], "r")) !== false) {
211
            while (($data = fgetcsv($handle, 1024, "\t")) !== false) {
212
                $row++;
213
                if ($row == 1) {
214
                    continue;
215
                }
216
217
                if ($nick !== null && strcmp($data[0], $nick) !== 0) {
218
                    continue;
219
                }
220
221
                $record = [
222
                    'nick' => $data[0], // nick
223
                    'level' => $data[3], // level
224
                    'admin' => ($data[2] ? 'Yes' : 'No'), // admin
225
                    'class' => $data[4], // class
226
                    'ttl' => [
227
                        'display' => $this->secondsToTime((int) $data[5]),
228
                        'numeric' => (int) $data[5], // ttl
229
                    ],
230
                    'nick_host' => $data[7], // nick and host
231
                    'online' => ($data[8] ? 'Yes' : 'No'), // online
232
                    'idled' => [
233
                        'display' => $this->secondsToTime((int) $data[9]), // idled
234
                        'numeric' => (int) $data[9],
235
                    ],
236
                    'x_pos' => (int) $data[10], // x pos
237
                    'y_pos' => (int) $data[11], // y pos
238
                    'msg_pen' => [
239
                        'display' => $this->secondsToTime((int) $data[12]), // msg pen
240
                        'numeric' => (int) $data[12],
241
                    ],
242
                    'nick_pen' => [
243
                        'display' => $this->secondsToTime((int) $data[13]), // nick pen
244
                        'numeric' => (int) $data[13],
245
                    ],
246
                    'part_pen' => [
247
                        'display' => $this->secondsToTime((int) $data[14]), // part pen
248
                        'numeric' => (int) $data[14],
249
                    ],
250
                    'kick_pen' => [
251
                        'display' => $this->secondsToTime((int) $data[15]), // kick pen
252
                        'numeric' => (int) $data[15],
253
                    ],
254
                    'quit_pen' => [
255
                        'display' => $this->secondsToTime((int) $data[16]), // quit pen
256
                        'numeric' => (int) $data[16],
257
                    ],
258
                    'quest_pen' => [
259
                        'display' => $this->secondsToTime((int) $data[17]), // quest pen
260
                        'numeric' => (int) $data[17],
261
                    ],
262
                    'logout_pen' => [
263
                        'display' => $this->secondsToTime((int) $data[18]), // logout pen
264
                        'numeric' => (int) $data[18],
265
                    ],
266
                    'total_pen' => [
267
                        'display' => $this->secondsToTime($this->sumFields($data, 12, 18)),
268
                        'numeric' => $this->sumFields($data, 12, 18),
269
                    ],
270
                    'created' => [
271
                        'display' => date('Y-m-d H:i:s', (int) $data[19]), // created
272
                        'numeric' => (int) $data[19],
273
                    ],
274
                    'last_login' => [
275
                        'display' => date('Y-m-d H:i:s', (int) $data[20]), // last login
276
                        'numeric' => (int) $data[20],
277
                    ],
278
                    'amulet' => [
279
                        'display' => $data[21], // amulet
280
                        'numeric' => (int) $data[21],
281
                        'unique' => $this->parseUniqueItem($data[21])
282
                    ],
283
                    'charm' => [
284
                        'display' => $data[22], // charm
285
                        'numeric' => (int) $data[22],
286
                        'unique' => $this->parseUniqueItem($data[22])
287
                    ],
288
                    'helm' => [
289
                        'display' => $data[23], // helm
290
                        'numeric' => (int) $data[23],
291
                        'unique' => $this->parseUniqueItem($data[23])
292
                    ],
293
                    'boots' => [
294
                        'display' => $data[24], // boots
295
                        'numeric' => (int) $data[24],
296
                        'unique' => $this->parseUniqueItem($data[24])
297
                    ],
298
                    'gloves' => [
299
                        'display' => $data[25], // gloves
300
                        'numeric' => (int) $data[25],
301
                        'unique' => $this->parseUniqueItem($data[25])
302
                    ],
303
                    'ring' => [
304
                        'display' => $data[26], // ring
305
                        'numeric' => (int) $data[26],
306
                        'unique' => $this->parseUniqueItem($data[26])
307
                    ],
308
                    'leggings' => [
309
                        'display' => $data[27], // leggings
310
                        'numeric' => (int) $data[27],
311
                        'unique' => $this->parseUniqueItem($data[27])
312
                    ],
313
                    'shield' => [
314
                        'display' => $data[28], // shield
315
                        'numeric' => (int) $data[28],
316
                        'unique' => $this->parseUniqueItem($data[28])
317
                    ],
318
                    'tunic' => [
319
                        'display' => $data[29], // tunic
320
                        'numeric' => (int) $data[29],
321
                        'unique' => $this->parseUniqueItem($data[29])
322
                    ],
323
                    'weapon' => [
324
                        'display' => $data[30], // weapon
325
                        'numeric' => (int) $data[30],
326
                        'unique' => $this->parseUniqueItem($data[30])
327
                    ],
328
                    'sum' => $this->sumFields($data, 21, 30),
329
                    'alignment' => $this->parseAlignment($data[31]), // alignment
330
                ];
331
332
                if ($nick != null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $nick of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
333
                    return $record;
334
                }
335
336
                $database[] = $record;
337
            }
338
            fclose($handle);
339
        }
340
341
        if ($nick != null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $nick of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
342
            return 0;
343
        }
344
345
        return $database;
346
    }
347
348
    /**
349
     * Returns the last $limit events [from the user $nick]
350
     * If $limit is 0 returns all
351
     * @param int $limit
352
     * @param string|null $nick
353
     * @return array|mixed
354
     */
355
    public function getEvents(int $limit, string $nick = null)
356
    {
357
        $modifiers = [
358
            'items' => [],
359
            'total' => 0,
360
        ];
361
362
        $tmp = [];
363
        $handle = fopen($this->config['bot_mod'], "r");
364
        if ($handle) {
0 ignored issues
show
introduced by
$handle is of type resource|false, thus it always evaluated to false.
Loading history...
365
            while (($line = fgets($handle)) !== false) {
366
                if ($nick != null && strpos($line, $nick) !== false) {
367
                    $tmp[] = $line;
368
                }
369
370
                if ($nick == null) {
371
                    $tmp[] = $line;
372
                }
373
            }
374
            fclose($handle);
375
        }
376
377
        $tmp = array_reverse($tmp);
378
        $modifiers['total'] = count($tmp);
379
        $modifiers['items'] = array_slice($tmp, 0, ($limit > 0 ) ? $limit : null);
380
381
        return $modifiers;
382
    }
383
384
    /**
385
     * Returns an array with the coordinates and name of all Players and Items
386
     * @return array
387
     */
388
    public function getCoordinates()
389
    {
390
        $coordinates = [];
391
392
        $players = $this->getDatabase();
393
        $items = $this->getItems();
394
395
        foreach ($players as $player) {
396
            $coordinates[] = ['x' => $player['x_pos'], 'y' => $player['y_pos'], 'text' => $player['nick']];
397
        }
398
399
        foreach ($items as $item) {
400
            $coordinates[] = ['x' => $item['x_pos'], 'y' => $item['y_pos'], 'text' => $item['type']];
401
        }
402
403
        return $coordinates;
404
    }
405
406
    /**
407
     * Returns an array with all the data associated with the current quest
408
     * @return array
409
     */
410
    public function getQuestData()
411
    {
412
        $quest = [];
413
        if (($handle = fopen($this->config['bot_quest'], "r")) !== false) {
414
            while (($data = fgets($handle, 1024)) !== false) {
415
                // T - title
416
                if (! isset($data['title']) && $data[0] == "T") {
417
                    $quest['title'] = substr($data, 2);
418
                }
419
                // Y - type. 1 for time based, 2 for stages
420
                if (! isset($data['type']) && $data[0] == "Y") {
421
                    $quest['type'] = (int) substr($data, 2);
422
                }
423
                // S - objective
424
                if ($data[0] == "S") {
425
                    $quest['objective'] = (int) substr($data, 2);
426
                }
427
                if ($data[0] == "P") {
428
                    $data_exploded = explode(" ", $data);
429
                    // P - stages position
430
                    if ($data_exploded[0] == "P") {
431
                        $quest['stages'] = [
432
                            ['x_pos' => (int) $data_exploded[1], 'y_pos' => (int) $data_exploded[2]],
433
                            ['x_pos' => (int) $data_exploded[3], 'y_pos' => (int) $data_exploded[4]],
434
                        ];
435
                    }
436
                    // P{1-4} - player position
437
                    if (isset($data_exploded[0][1])) {
438
                        $quest['players'][] = [
439
                            'nick'  => $data_exploded[1],
440
                            'x_pos' => (int) $data_exploded[2],
441
                            'y_pos' => (int) $data_exploded[3]
442
                        ];
443
                    }
444
                }
445
            }
446
            fclose($handle);
447
        }
448
449
        return $quest;
450
    }
451
452
    /**
453
     * Returns an array with all the Players nicks
454
     * @return array
455
     */
456
    public function getPlayers()
457
    {
458
        $players = [];
459
460
        $row = 0;
461
        if (($handle = fopen($this->config['bot_db'], "r")) !== false) {
462
            while (($data = fgetcsv($handle, 1024, "\t")) !== false) {
463
                $row++;
464
                if ($row == 1) {
465
                    continue;
466
                }
467
468
                $players[] = $data[0]; // nick
469
            }
470
        }
471
472
        return $players;
473
    }
474
}
475