Completed
Pull Request — master (#393)
by De Cramer
02:39
created

PluginManager   A

Complexity

Total Complexity 39

Size/Duplication

Total Lines 285
Duplicated Lines 10.18 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 14.43%

Importance

Changes 0
Metric Value
wmc 39
lcom 1
cbo 7
dl 29
loc 285
ccs 14
cts 97
cp 0.1443
rs 9.28
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 13 13 1
A init() 0 4 1
A reset() 0 8 1
C enableDisablePlugins() 16 49 13
A enablePlugin() 0 21 5
A disablePlugin() 0 21 5
A isPluginEnabled() 0 4 1
A registerPlugin() 0 10 2
B isPluginCompatible() 0 48 10

How to fix   Duplicated Code   

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:

1
<?php
2
3
namespace eXpansion\Framework\Core\Services;
4
5
use eXpansion\Framework\Core\Model\Plugin\PluginDescription;
6
use eXpansion\Framework\Core\Model\Plugin\PluginDescriptionFactory;
7
use eXpansion\Framework\Core\Plugins\StatusAwarePluginInterface;
8
use eXpansion\Framework\Core\Storage\GameDataStorage;
9
use Maniaplanet\DedicatedServer\Structures\Map;
10
use Symfony\Component\DependencyInjection\ContainerInterface;
11
12
/**
13
 * Class PluginManager handles all the plugins.
14
 *
15
 * @package eXpansion\Framework\Core\Services
16
 */
17
class PluginManager
18
{
19
    /** @var PluginDescription[] List of all the plugins adescriptions. */
20
    protected $plugins = [];
21
22
    /** @var PluginDescription[] Current List of enabled plugins */
23
    protected $enabledPlugins = [];
24
25
    /** @var PluginDescriptionFactory */
26
    protected $pluginDescriptionFactory;
27
28
    /** @var ContainerInterface */
29
    protected $container;
30
31
    /** @var DataProviderManager */
32
    protected $dataProviderManager;
33
34
    /** @var GameDataStorage */
35
    protected $gameDataStorage;
36
37
    /** @var Console */
38
    protected $console;
39
40
    /**
41
     * PluginManager constructor.
42
     *
43
     * @param ContainerInterface $container
44
     * @param PluginDescriptionFactory $pluginDescriptionFactory
45
     * @param DataProviderManager $dataProviderManager
46
     * @param GameDataStorage $gameDataStorage
47
     * @param Console $console
48
     */
49 44 View Code Duplication
    public function __construct(
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...
50
        ContainerInterface $container,
51
        PluginDescriptionFactory $pluginDescriptionFactory,
52
        DataProviderManager $dataProviderManager,
53
        GameDataStorage $gameDataStorage,
54
        Console $console
55
    ) {
56 44
        $this->container = $container;
57 44
        $this->pluginDescriptionFactory = $pluginDescriptionFactory;
58 44
        $this->dataProviderManager = $dataProviderManager;
59 44
        $this->gameDataStorage = $gameDataStorage;
60 44
        $this->console = $console;
61 44
    }
62
63
    /**
64
     * Initialize.
65
     *
66
     * @throws \eXpansion\Framework\Core\Exceptions\DataProvider\UncompatibleException
67
     */
68
    public function init(Map $map)
69
    {
70
        $this->reset($map);
71
    }
72
73
    /**
74
     * Do a reset to plugins/
75
     *
76
     * @param Map $map
77
     *
78
     * @throws \eXpansion\Framework\Core\Exceptions\DataProvider\UncompatibleException
79
     */
80
    public function reset(Map $map)
81
    {
82
        $title = $this->gameDataStorage->getTitle();
83
        $mode = $this->gameDataStorage->getGameModeCode();
84
        $script = strtolower($this->gameDataStorage->getGameInfos()->scriptName);
85
86
        $this->enableDisablePlugins($title, $mode, $script, $map);
87
    }
88
89
    /**
90
     * @param $title
91
     * @param $mode
92
     * @param $script
93
     * @param Map $map
94
     *
95
     * @throws \eXpansion\Framework\Core\Exceptions\DataProvider\UncompatibleException
96
     */
97
    protected function enableDisablePlugins($title, $mode, $script, Map $map)
98
    {
99
        $pluginsToEnable = [];
100
        $pluginsToProcess = $this->plugins;
101
102
        do {
103
            $lastEnabledPluginCount = count($pluginsToEnable);
104
            $pluginsToProcessNew = [];
105
106
            foreach ($pluginsToProcess as $pluginId => $plugin) {
107
                if ($this->isPluginCompatible($plugin, $pluginsToEnable, $title, $mode, $script, $map)) {
108
                    $pluginsToEnable[$pluginId] = $plugin;
109
                } else {
110
                    $pluginsToProcessNew[$pluginId] = $plugin;
111
                }
112
            }
113
114
            $pluginsToProcess = $pluginsToProcessNew;
115
        } while ($lastEnabledPluginCount != count($pluginsToEnable) && !empty($pluginsToProcess));
116
117
        /* Enable plugins so that the data providers are propelry connected */
118
        $enableNotify = [];
119
        foreach ($pluginsToEnable as $pluginId => $plugin) {
120
            $enableNotify[$pluginId] = $this->enablePlugin($plugin, $title, $mode, $script, $map);
121
        }
122
123
        $disableNotify = [];
124
        foreach ($pluginsToProcess as $pluginId => $plugin) {
125
            $disableNotify[$pluginId] = $this->disablePlugin($plugin);
126
        }
127
128
        /* Once all is connected send status update */
129 View Code Duplication
        foreach ($enableNotify as $pluginId => $plugin) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
130
            if (!is_null($plugin)) {
131
                $this->console->getConsoleOutput()->writeln("<info>Enabling plugin : $pluginId</info>");
132
                if ($plugin instanceof StatusAwarePluginInterface) {
133
                    $plugin->setStatus(true);
134
                }
135
            }
136
        }
137 View Code Duplication
        foreach ($disableNotify as $pluginId => $plugin) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
138
            if (!is_null($plugin)) {
139
                $this->console->writeln("<info>Disabling plugin : $pluginId</info>");
140
                if ($plugin instanceof StatusAwarePluginInterface) {
141
                    $plugin->setStatus(false);
142
                }
143
            }
144
        }
145
    }
146
147
    /**
148
     * Check if a plugin is compatible or not.
149
     *
150
     * @param PluginDescription $plugin
151
     * @param $enabledPlugins
152
     * @param $title
153
     * @param $mode
154
     * @param $script
155
     * @param $map
156
     *
157
     * @return bool
158
     */
159
    protected function isPluginCompatible(PluginDescription $plugin, $enabledPlugins, $title, $mode, $script, Map $map)
160
    {
161
162
        // first check for other plugins.
163
        foreach ($plugin->getParents() as $parentPluginId) {
164
            if (!isset($enabledPlugins[$parentPluginId])) {
165
                // A parent plugin is missing. Can't enable plugin.
166
                return false;
167
            }
168
        }
169
170
        // Now check for data providers.
171
        foreach ($plugin->getDataProviders() as $dataProvider) {
172
            $dataProviders = explode("|", $dataProvider);
173
            $foundOne = false;
174
175
            foreach ($dataProviders as $provider) {
176
                $providerId = $this->dataProviderManager->getCompatibleProviderId($provider, $title, $mode, $script, $map);
177
                if (!is_null($providerId) && isset($enabledPlugins[$providerId])) {
178
                    // Either there are no data providers compatible or the only one compatible
179
                    $foundOne = true;
180
                    break;
181
                }
182
            }
183
184
            if (!$foundOne) {
185
                return false;
186
            }
187
        }
188
189
        // If data provider need to check if it was "the chosen one".
190
        if ($plugin->isIsDataProvider()) {
191
            $selectedProvider = $this->dataProviderManager->getCompatibleProviderId(
192
                $plugin->getDataProviderName(),
193
                $title,
194
                $mode,
195
                $script,
196
                $map
197
            );
198
199
            if ($plugin->getPluginId() != $selectedProvider) {
200
                // This data provider wasn't the one selected and therefore the plugin isn't compatible.
201
                return false;
202
            }
203
        }
204
205
        return true;
206
    }
207
208
    /**
209
     * Enable a certain plugin.
210
     *
211
     * @param PluginDescription $plugin
212
     * @param $title
213
     * @param $mode
214
     * @param $script
215
     * @param Map $map
216
     *
217
     * @return mixed
218
     *
219
     * @throws \eXpansion\Framework\Core\Exceptions\DataProvider\UncompatibleException
220
     */
221
    protected function enablePlugin(PluginDescription $plugin, $title, $mode, $script, Map $map)
222
    {
223
        $notify = false;
224
        $plugin->setIsEnabled(true);
225
        $pluginService = $this->container->get($plugin->getPluginId());
226
227
        if (!isset($this->enabledPlugins[$plugin->getPluginId()])) {
228
            $notify = true;
229
        }
230
231
        foreach ($plugin->getDataProviders() as $provider) {
232
            $dataProviders = explode("|", $provider);
233
            foreach ($dataProviders as $dataProvider) {
234
                $this->dataProviderManager->registerPlugin($dataProvider, $plugin->getPluginId(), $title, $mode, $script, $map);
235
            }
236
        }
237
238
        $this->enabledPlugins[$plugin->getPluginId()] = $plugin;
239
240
        return $notify ? $pluginService : null;
241
    }
242
243
    /**
244
     * Disable a plugin
245
     *
246
     * @param PluginDescription $plugin
247
     *
248
     * @return mixed
249
     */
250
    protected function disablePlugin(PluginDescription $plugin)
251
    {
252
        $notify = false;
253
        $plugin->setIsEnabled(false);
254
        $pluginService = $this->container->get($plugin->getPluginId());
255
256
        foreach ($plugin->getDataProviders() as $provider) {
257
            $dataProviders = explode("|", $provider);
258
            foreach ($dataProviders as $dataProvider) {
259
                $this->dataProviderManager->deletePlugin($dataProvider, $plugin->getPluginId());
260
            }
261
        }
262
263
        if (isset($this->enabledPlugins[$plugin->getPluginId()])) {
264
            unset($this->enabledPlugins[$plugin->getPluginId()]);
265
266
            $notify = true;
267
        }
268
269
        return $notify ? $pluginService : null;
270
    }
271
272
    /**
273
     * Check if a plugin is enabled or not.
274
     *
275
     * @param $pluginId
276
     *
277
     * @return bool
278
     */
279
    public function isPluginEnabled($pluginId)
280
    {
281
        return isset($this->enabledPlugins[$pluginId]);
282
    }
283
284
    /**
285
     * Register a plugin.
286
     *
287
     * @param string $id The service id of the plugin to register.
288
     * @param string[] $dataProviders The data providers it needs to work.
289
     * @param string[] $parents The parent plugins.
290
     */
291 44
    public function registerPlugin($id, $dataProviders, $parents, $dataProviderName = null)
292
    {
293 44
        if (!isset($this->plugins[$id])) {
294 44
            $this->plugins[$id] = $this->pluginDescriptionFactory->create($id);
295
        }
296
297 44
        $this->plugins[$id]->setDataProviders($dataProviders);
298 44
        $this->plugins[$id]->setParents($parents);
299 44
        $this->plugins[$id]->setDataProviderName($dataProviderName);
300 44
    }
301
}
302