Completed
Push — master ( f31586...66eb65 )
by De Cramer
04:28
created

PluginManager::isPluginCompatible()   C

Complexity

Conditions 8
Paths 15

Size

Total Lines 39
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 72

Importance

Changes 0
Metric Value
dl 0
loc 39
rs 5.3846
c 0
b 0
f 0
ccs 0
cts 18
cp 0
cc 8
eloc 18
nc 15
nop 6
crap 72
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 138
    public function __construct(
50
        ContainerInterface $container,
51
        PluginDescriptionFactory $pluginDescriptionFactory,
52
        DataProviderManager $dataProviderManager,
53
        GameDataStorage $gameDataStorage,
54
        Console $console
55
    ) {
56 138
        $this->container = $container;
57 138
        $this->pluginDescriptionFactory = $pluginDescriptionFactory;
58 138
        $this->dataProviderManager = $dataProviderManager;
59 138
        $this->gameDataStorage = $gameDataStorage;
60 138
        $this->console = $console;
61 138
    }
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 = $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 $plugin) {
120
            $enableNotify[] = $this->enablePlugin($plugin, $title, $mode, $script, $map);
121
        }
122
123
        $disableNotify = [];
124
        foreach ($pluginsToProcess as $plugin) {
125
            $disableNotify[] = $this->disablePlugin($plugin);
126
        }
127
128
        /* Once all is connected send status update */
129
        foreach ($enableNotify as $plugin) {
130
            if (!is_null($plugin)) {
131
                $plugin->setStatus(true);
132
            }
133
        }
134
        foreach ($disableNotify as $plugin) {
135
            if (!is_null($plugin)) {
136
                $plugin->setStatus(false);
137
            }
138
        }
139
    }
140
141
    /**
142
     * Check if a plugin is compatible or not.
143
     *
144
     * @param PluginDescription $plugin
145
     * @param $enabledPlugins
146
     * @param $title
147
     * @param $mode
148
     * @param $script
149
     * @param $map
150
     *
151
     * @return bool
152
     */
153
    protected function isPluginCompatible(PluginDescription $plugin, $enabledPlugins, $title, $mode, $script, Map $map)
154
    {
155
156
        // first check for other plugins.
157
        foreach ($plugin->getParents() as $parentPluginId) {
158
            if (!isset($enabledPlugins[$parentPluginId])) {
159
                // A parent plugin is missing. Can't enable plugin.
160
                return false;
161
            }
162
        }
163
164
        // Now check for data providers.
165
        foreach ($plugin->getDataProviders() as $dataProvider) {
166
            $providerId = $this->dataProviderManager->getCompatibleProviderId($dataProvider, $title, $mode, $script, $map);
167
168
            if (is_null($providerId) || !isset($enabledPlugins[$providerId])) {
169
                // Either there are no data providers compatible or the only one compatible
170
                return false;
171
            }
172
        }
173
174
        // If data provider need to check if it was "the chosen one".
175
        if ($plugin->isIsDataProvider()) {
176
            $selectedProvider = $this->dataProviderManager->getCompatibleProviderId(
177
                $plugin->getDataProviderName(),
178
                $title,
179
                $mode,
180
                $script,
181
                $map
182
            );
183
184
            if ($plugin->getPluginId() != $selectedProvider) {
185
                // This data provider wasn't the one selected and therefore the plugin isn't compatible.
186
                return false;
187
            }
188
        }
189
190
        return true;
191
    }
192
193
    /**
194
     * Enable a certain plugin.
195
     *
196
     * @param PluginDescription $plugin
197
     * @param $title
198
     * @param $mode
199
     * @param $script
200
     * @param Map $map
201
     *
202
     * @return StatusAwarePluginInterface|null
203
     *
204
     * @throws \eXpansion\Framework\Core\Exceptions\DataProvider\UncompatibleException
205
     */
206
    protected function enablePlugin(PluginDescription $plugin, $title, $mode, $script, Map $map)
207
    {
208
        $notify = false;
209
        $plugin->setIsEnabled(true);
210
        $pluginService = $this->container->get($plugin->getPluginId());
211
212 View Code Duplication
        if ($pluginService instanceof StatusAwarePluginInterface && !isset($this->enabledPlugins[$plugin->getPluginId()])) {
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...
213
            $notify = true;
214
        }
215
216
        $this->console->getConsoleOutput()
217
            ->writeln("<info>Plugin <comment>'{$plugin->getPluginId()}'</comment> is enabled with providers :</info>");
218
        foreach ($plugin->getDataProviders() as $provider) {
219
            $this->dataProviderManager->registerPlugin($provider, $plugin->getPluginId(), $title, $mode, $script, $map);
220
        }
221
222
        $this->enabledPlugins[$plugin->getPluginId()] = $plugin;
223
224
        return $notify ? $pluginService : null;
225
    }
226
227
    /**
228
     * Disable a plugin
229
     *
230
     * @param PluginDescription $plugin
231
     *
232
     * @return StatusAwarePluginInterface|null
233
     */
234
    protected function disablePlugin(PluginDescription $plugin)
235
    {
236
        $notify = false;
237
        $plugin->setIsEnabled(false);
238
        $pluginService = $this->container->get($plugin->getPluginId());
239
240
        foreach ($plugin->getDataProviders() as $provider) {
241
            $this->dataProviderManager->deletePlugin($provider, $plugin->getPluginId());
242
        }
243
244 View Code Duplication
        if (isset($this->enabledPlugins[$plugin->getPluginId()])) {
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...
245
            unset($this->enabledPlugins[$plugin->getPluginId()]);
246
247
            if ($pluginService instanceof StatusAwarePluginInterface) {
248
                $notify = true;
249
            }
250
        }
251
252
        return $notify ? $pluginService : null;
253
    }
254
255
    /**
256
     * Check if a plugin is enabled or not.
257
     *
258
     * @param $pluginId
259
     *
260
     * @return bool
261
     */
262
    public function isPluginEnabled($pluginId)
263
    {
264
        return isset($this->enabledPlugins[$pluginId]);
265
    }
266
267
    /**
268
     * Register a plugin.
269
     *
270
     * @param string $id The service id of the plugin to register.
271
     * @param string[] $dataProviders The data providers it needs to work.
272
     * @param string[] $parents The parent plugins.
273
     */
274 138
    public function registerPlugin($id, $dataProviders, $parents, $dataProviderName = null)
275
    {
276 138
        if (!isset($this->plugins[$id])) {
277 138
            $this->plugins[$id] = $this->pluginDescriptionFactory->create($id);
278
        }
279
280 138
        $this->plugins[$id]->setDataProviders($dataProviders);
281 138
        $this->plugins[$id]->setParents($parents);
282 138
        $this->plugins[$id]->setDataProviderName($dataProviderName);
283 138
    }
284
}
285