Completed
Push — master ( 2a3483...c07a8d )
by De Cramer
02:05 queued 02:03
created

GuiHandler   B

Complexity

Total Complexity 53

Size/Duplication

Total Lines 349
Duplicated Lines 11.17 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 95.56%

Importance

Changes 0
Metric Value
wmc 53
lcom 1
cbo 6
dl 39
loc 349
ccs 129
cts 135
cp 0.9556
rs 7.4757
c 0
b 0
f 0

19 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 16 1
A addToDisplay() 0 12 2
A addToHide() 0 16 3
A getManialink() 0 12 4
B displayManialinks() 0 35 6
A executeMultiCall() 9 9 2
F getManialinksToDisplay() 0 59 14
A setCharLimit() 0 4 1
A getDisplayeds() 0 4 1
A onPostLoop() 0 4 1
A onPreLoop() 0 3 1
A onEverySecond() 0 3 1
B onExpansionGroupAddUser() 15 15 5
B onExpansionGroupRemoveUser() 15 15 5
A onExpansionGroupDestroy() 0 6 2
A onPlayerConnect() 0 3 1
A onPlayerDisconnect() 0 5 1
A onPlayerInfoChanged() 0 3 1
A onPlayerAlliesChanged() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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

1
<?php
2
3
namespace eXpansion\Framework\Core\Plugins;
4
5
use eXpansion\Framework\Core\DataProviders\Listener\ListenerInterfaceExpTimer;
6
use eXpansion\Framework\Core\DataProviders\Listener\ListenerInterfaceExpUserGroup;
7
use eXpansion\Framework\GameManiaplanet\DataProviders\Listener\ListenerInterfaceMpLegacyPlayer;
8
use eXpansion\Framework\Core\Model\Gui\ManialinkFactoryInterface;
9
use eXpansion\Framework\Core\Model\Gui\ManialinkInterface;
10
use eXpansion\Framework\Core\Model\UserGroups\Group;
11
use eXpansion\Framework\Core\Plugins\Gui\ActionFactory;
12
use eXpansion\Framework\Core\Services\Console;
13
use eXpansion\Framework\Core\Storage\Data\Player;
14
use Maniaplanet\DedicatedServer\Connection;
15
use oliverde8\AssociativeArraySimplified\AssociativeArray;
16
use Psr\Log\LoggerInterface;
17
18
/**
19
 * Class GuiHandler will send manialinks to player as needed.
20
 *
21
 * @package eXpansion\Framework\Core\Plugins\Gui
22
 * @author Oliver de Cramer
23
 */
24
class GuiHandler implements
25
    ListenerInterfaceExpTimer,
26
    ListenerInterfaceExpUserGroup,
27
    ListenerInterfaceMpLegacyPlayer,
28
    GuiHandlerInterface
29
{
30
    /** @var Connection */
31
    protected $connection;
32
33
    /** @var LoggerInterface */
34
    protected $logger;
35
36
    /** @var Console */
37
    protected $console;
38
39
    /** @var ActionFactory */
40
    protected $actionFactory;
41
42
    /** @var int */
43
    protected $charLimit;
44
45
    /** @var ManialinkInterface[][] */
46
    protected $displayQueu = [];
47
48
    /** @var ManialinkInterface[][] */
49
    protected $individualQueu = [];
50
51
    /** @var ManialinkInterface[][] */
52
    protected $displayeds = [];
53
54
    /** @var ManialinkInterface[][] */
55
    protected $hideQueu = [];
56
57
    /** @var ManialinkInterface[][] */
58
    protected $hideIndividualQueu = [];
59
60
    /** @var String[] */
61
    protected $disconnectedLogins = [];
62
63
    /**
64
     * GuiHandler constructor.
65
     *
66
     * @param Connection $connection
67
     */
68 15
    public function __construct(
69
        Connection $connection,
70
        LoggerInterface $logger,
71
        Console $console,
72
        ActionFactory $actionFactory,
73
        $charLimit = 262144
74
    ) {
75 15
        $this->connection = $connection;
76
77 15
        $this->connection->sendHideManialinkPage(null);
78
79 15
        $this->logger = $logger;
80 15
        $this->console = $console;
81 15
        $this->actionFactory = $actionFactory;
82 15
        $this->charLimit = $charLimit;
83 15
    }
84
85
86
    /**
87
     * @inheritdoc
88
     **/
89 13
    public function addToDisplay(ManialinkInterface $manialink)
90
    {
91
92 13
        $userGroup = $manialink->getUserGroup()->getName();
93 13
        $id = $manialink->getManialinkFactory()->getId();
94
95 13
        if (AssociativeArray::getFromKey($this->hideQueu, [$userGroup, $id])) {
96 1
            unset($this->hideQueu[$userGroup][$id]);
97
        }
98
99 13
        $this->displayQueu[$userGroup][$id] = $manialink;
100 13
    }
101
102
    /**
103
     * @inheritdoc
104
     */
105 3
    public function addToHide(ManialinkInterface $manialink)
106
    {
107 3
        $userGroup = $manialink->getUserGroup()->getName();
108 3
        $id = $manialink->getManialinkFactory()->getId();
109
110 3
        if (AssociativeArray::getFromKey($this->displayQueu, [$userGroup, $id])) {
111 1
            unset($this->displayQueu[$userGroup][$id]);
112
        }
113
114 3
        if (AssociativeArray::getFromKey($this->displayeds, [$userGroup, $id])) {
115 1
            unset($this->displayeds[$userGroup][$id]);
116
        }
117
118 3
        $this->actionFactory->destroyManialinkActions($manialink);
119 3
        $this->hideQueu[$userGroup][$id] = $manialink;
120 3
    }
121
122
    /**
123
     * @inheritdoc
124
     */
125
    public function getManialink(Group $group, ManialinkFactoryInterface $manialinkFactory)
126
    {
127
        $varsToCheck = ['displayeds', 'hideQueu', 'displayQueu'];
128
129
        foreach ($varsToCheck as $var) {
130
            if (isset($this->$var[$group->getName()]) && isset($this->$var[$group->getName()][$manialinkFactory->getId()])) {
131
                return $this->$var[$group->getName()][$manialinkFactory->getId()];
132
            }
133
        }
134
135
        return null;
136
    }
137
138
    /**
139
     * Display & hide all manialinks.
140
     */
141 14
    protected function displayManialinks()
142
    {
143 14
        $size = 0;
144 14
        foreach ($this->getManialinksToDisplay() as $mlData) {
145 14
            $currentSize = $size;
146 14
            $size += strlen($mlData['ml']);
147
148 14
            if ($currentSize != 0 && $size > $this->charLimit) {
149 2
                $this->executeMultiCall();
150 2
                $size = strlen($mlData['ml']);
151
            }
152
153
            $logins = array_filter($mlData['logins'], function($value) { return $value != '';});
154 14
            if (!empty($logins)) {
155 14
                $this->connection->sendDisplayManialinkPage(
156 14
                    $mlData['logins'],
157 14
                    $mlData['ml'],
158 14
                    0,
159 14
                    false,
160 14
                    true
161
                );
162
            }
163
        }
164
165 14
        if ($size > 0) {
166 14
            $this->executeMultiCall();
167
        }
168
169
        // Reset the queues.
170 14
        $this->displayQueu = [];
171 14
        $this->individualQueu = [];
172 14
        $this->hideQueu = [];
173 14
        $this->hideIndividualQueu = [];
174 14
        $this->disconnectedLogins = [];
175 14
    }
176
177
    /**
178
     * Execute multi call & handle error.
179
     */
180 14 View Code Duplication
    protected function executeMultiCall()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
181
    {
182
        try {
183 14
            $this->connection->executeMulticall();
184 1
        } catch (\Exception $e) {
185 1
            $this->logger->error("Couldn't deliver all manialinks : ".$e->getMessage(), ['exception' => $e]);
186 1
            $this->console->writeln('$F00ERROR - Couldn\'t deliver all manialinks : '.$e->getMessage());
187
        }
188 14
    }
189
190
    /**
191
     * Get list of all manialinks that needs to be displayed
192
     *
193
     * @return \Generator
194
     */
195 14
    protected function getManialinksToDisplay()
196
    {
197 14
        foreach ($this->displayQueu as $groupName => $manialinks) {
198 13
            foreach ($manialinks as $factoryId => $manialink) {
199 13
                $logins = $manialink->getUserGroup()->getLogins();
200
201 13
                $this->displayeds[$groupName][$factoryId] = $manialink;
202 13
                if (!empty($logins)) {
203 13
                    yield ['logins' => $logins, 'ml' => $manialink->getXml()];
204
                }
205
            }
206
        }
207
208 14
        foreach ($this->individualQueu as $manialinks) {
209
            // Fetch all logins
210 4
            $logins = [];
211 4
            $lastManialink = null;
212 4
            foreach ($manialinks as $login => $manialink) {
213 3
                $logins[] = $login;
214 3
                $lastManialink = $manialink;
215
            }
216
217 4
            if ($lastManialink) {
218 3
                $xml = $manialink->getXml();
0 ignored issues
show
Bug introduced by
The variable $manialink does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
219 4
                yield ['logins' => $logins, 'ml' => $xml];
220
            }
221
        }
222
223 14
        foreach ($this->hideQueu as $manialinks) {
224 3
            foreach ($manialinks as $manialink) {
225 2
                $id = $manialink->getId();
226 2
                $manialink->destroy();
227
228 2
                $logins = $manialink->getUserGroup()->getLogins();
229 2
                $logins = array_diff($logins, $this->disconnectedLogins);
230
231 2
                if (!empty($logins)) {
232 3
                    yield ['logins' => $logins, 'ml' => '<manialink id="'.$id.'" />'];
233
                }
234
            }
235
        }
236
237 14
        foreach ($this->hideIndividualQueu as $id => $manialinks) {
238
            // Fetch all logins.
239 5
            $logins = [];
240 5
            $lastManialink = null;
241 5
            foreach ($manialinks as $login => $manialink) {
242 4
                if (!in_array($login, $this->disconnectedLogins)) {
243 3
                    $logins[] = $login;
244 4
                    $lastManialink = $manialink;
245
                }
246
            }
247
248 5
            if ($lastManialink) {
249
                // Manialink is not destroyed just not shown at a particular user that left the group.
250 5
                yield ['logins' => $logins, 'ml' => '<manialink id="'.$lastManialink->getId().'" />'];
251
            }
252
        }
253 14
    }
254
255
    /**
256
     * @param int $charLimit
257
     */
258 2
    public function setCharLimit($charLimit)
259
    {
260 2
        $this->charLimit = $charLimit;
261 2
    }
262
263
    /**
264
     * List of all manialinks that are currently displayed.
265
     *
266
     * @return ManialinkInterface[][]
267
     */
268 1
    public function getDisplayeds()
269
    {
270 1
        return $this->displayeds;
271
    }
272
273
    /**
274
     * @inheritdoc
275
     */
276 14
    public function onPostLoop()
277
    {
278 14
        $this->displayManialinks();
279 14
    }
280
281
    /**
282
     * @inheritdoc
283
     */
284 1
    public function onPreLoop()
285
    {
286 1
    }
287
288
    /**
289
     * @inheritdoc
290
     */
291 1
    public function onEverySecond()
292
    {
293 1
    }
294
295
    /**
296
     * @inheritdoc
297
     */
298 4 View Code Duplication
    public function onExpansionGroupAddUser(Group $group, $loginAdded)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
299
    {
300 4
        $group = $group->getName();
301
302
        // User was added to group, need to display all manialinks of the group to this user
303 4
        if (isset($this->displayeds[$group])) {
304 4
            foreach ($this->displayeds[$group] as $mlId => $manialink) {
305 4
                $this->individualQueu[$mlId][$loginAdded] = $manialink;
306
307 4
                if (isset($this->hideIndividualQueu[$mlId]) && isset($this->hideIndividualQueu[$mlId][$loginAdded])) {
308 4
                    unset ($this->hideIndividualQueu[$mlId][$loginAdded]);
309
                }
310
            }
311
        }
312 4
    }
313
314
    /**
315
     * @inheritdoc
316
     */
317 5 View Code Duplication
    public function onExpansionGroupRemoveUser(Group $group, $loginRemoved)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
318
    {
319 5
        $group = $group->getName();
320
321
        // User was removed from group, need to hide all manialinks of the group to this user
322 5
        if (isset($this->displayeds[$group])) {
323 5
            foreach ($this->displayeds[$group] as $mlId => $manialink) {
324 5
                $this->hideIndividualQueu[$mlId][$loginRemoved] = $manialink;
325
326 5
                if (isset($this->individualQueu[$mlId]) && isset($this->individualQueu[$mlId][$loginRemoved])) {
327 5
                    unset ($this->individualQueu[$mlId][$loginRemoved]);
328
                }
329
            }
330
        }
331 5
    }
332
333
    /**
334
     * @inheritdoc
335
     */
336 1
    public function onExpansionGroupDestroy(Group $group, $lastLogin)
337
    {
338 1
        if (isset($this->displayeds[$group->getName()])) {
339 1
            unset($this->displayeds[$group->getName()]);
340
        }
341 1
    }
342
343
    /**
344
     * @inheritdoc
345
     */
346 1
    public function onPlayerConnect(Player $player)
347
    {
348 1
    }
349
350
    /**
351
     * @inheritdoc
352
     */
353 1
    public function onPlayerDisconnect(Player $player, $disconnectionReason)
354
    {
355
        // To prevent sending manialinks to those players.
356 1
        $this->disconnectedLogins[] = $player->getLogin();
357 1
    }
358
359
    /**
360
     * @inheritdoc
361
     */
362 1
    public function onPlayerInfoChanged(Player $oldPlayer, Player $player)
363
    {
364 1
    }
365
366
    /**
367
     * @inheritdoc
368
     */
369 1
    public function onPlayerAlliesChanged(Player $oldPlayer, Player $player)
370
    {
371 1
    }
372
}
373