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( |
|
|
|
|
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) { |
|
|
|
|
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) { |
|
|
|
|
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
|
|
|
|
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.