Completed
Push — dev ( ade326...e1b211 )
by
unknown
03:23
created

PluginManager::init()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 0
cts 3
cp 0
cc 1
eloc 2
nc 1
nop 0
crap 2
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 Symfony\Component\DependencyInjection\ContainerInterface;
10
11
/**
12
 * Class PluginManager handles all the plugins.
13
 *
14
 * @TODO handle gamemode change.
15
 *
16
 * @package eXpansion\Framework\Core\Services
17
 */
18
class PluginManager
19
{
20
    /** @var PluginDescription[] List of all the plugins adescriptions. */
21
    protected $plugins = [];
22
23
    /** @var PluginDescription[] Current List of enabled plugins */
24
    protected $enabledPlugins = [];
25
26
    /** @var PluginDescriptionFactory */
27
    protected $pluginDescriptionFactory;
28
29
    /** @var ContainerInterface */
30
    protected $container;
31
32
    /** @var DataProviderManager */
33
    protected $dataProviderManager;
34
35
    /** @var GameDataStorage */
36
    protected $gameDataStorage;
37
38
    /** @var Console */
39
    protected $console;
40
41
    /**
42
     * PluginManager constructor.
43
     *
44
     * @param ContainerInterface $container
45
     * @param PluginDescriptionFactory $pluginDescriptionFactory
46
     * @param DataProviderManager $dataProviderManager
47
     * @param GameDataStorage $gameDataStorage
48
     * @param Console $console
49
     */
50 48
    public function __construct(
51
        ContainerInterface $container,
52
        PluginDescriptionFactory $pluginDescriptionFactory,
53
        DataProviderManager $dataProviderManager,
54
        GameDataStorage $gameDataStorage,
55
        Console $console
56
    ) {
57 48
        $this->container = $container;
58 48
        $this->pluginDescriptionFactory = $pluginDescriptionFactory;
59 48
        $this->dataProviderManager = $dataProviderManager;
60 48
        $this->gameDataStorage = $gameDataStorage;
61 48
        $this->console = $console;
62 48
    }
63
64
    /**
65
     * Initialize plugins.
66
     */
67
    public function init()
68
    {
69
        $this->reset();
70
    }
71
72
    /**
73
     * Do a reset
74
     */
75
    public function reset()
76
    {
77
        $title = $this->gameDataStorage->getTitle();
78
        $mode = $this->gameDataStorage->getGameModeCode();
79
        $script = $this->gameDataStorage->getGameInfos()->scriptName;
80
81
        $this->enableDisablePlugins($title, $mode, $script);
82
    }
83
84
    /**
85
     * Enable all possible plugins.
86
     *
87
     * @param string $title
88
     * @param string $mode
89
     * @param string $script
90
     */
91
    protected function enableDisablePlugins($title, $mode, $script)
92
    {
93
        $pluginsToEnable = [];
94
        $pluginsToProcess = $this->plugins;
95
96
        do {
97
            $lastEnabledPluginCount = count($pluginsToEnable);
98
            $pluginsToProcessNew = [];
99
100
            foreach ($pluginsToProcess as $pluginId => $plugin) {
101
                if ($this->isPluginCompatible($plugin, $pluginsToEnable, $title, $mode, $script)) {
102
                    $pluginsToEnable[$pluginId] = $plugin;
103
                } else {
104
                    $pluginsToProcessNew[$pluginId] = $plugin;
105
                }
106
            }
107
108
            $pluginsToProcess = $pluginsToProcessNew;
109
        } while ($lastEnabledPluginCount != count($pluginsToEnable) && !empty($pluginsToProcess));
110
111
        foreach ($pluginsToEnable as $plugin) {
112
            $this->enablePlugin($plugin, $title, $mode, $script);
113
        }
114
115
        foreach ($pluginsToProcess as $plugin) {
116
            $this->disablePlugin($plugin);
117
        }
118
    }
119
120
    /**
121
     * Check if a plugin is compatible or not.
122
     *
123
     * @param PluginDescription $plugin
124
     * @param $enabledPlugins
125
     * @param $title
126
     * @param $mode
127
     * @param $script
128
     *
129
     * @return bool
130
     */
131
    protected function isPluginCompatible(PluginDescription $plugin, $enabledPlugins, $title, $mode, $script)
132
    {
133
134
        // first check for other plugins.
135
        foreach ($plugin->getParents() as $parentPluginId) {
136
            if (!isset($enabledPlugins[$parentPluginId])) {
137
                // A parent plugin is missing. Can't enable plugin.
138
                return false;
139
            }
140
        }
141
142
        // Now check for data providers.
143
        foreach ($plugin->getDataProviders() as $dataProvider) {
144
            $providerId = $this->dataProviderManager->getCompatibleProviderId($dataProvider, $title, $mode, $script);
145
146
            if (is_null($providerId) || !isset($enabledPlugins[$providerId])) {
147
                // Either there are no data providers compatible or the only one compatible
148
                return false;
149
            }
150
        }
151
152
        // If data provider need to check if it was "the chosen one".
153
        if ($plugin->isIsDataProvider()) {
154
            $selectedProvider = $this->dataProviderManager->getCompatibleProviderId($plugin->getDataProviderName(),
155
                $title, $mode, $script);
156
157
            if ($plugin->getPluginId() != $selectedProvider) {
158
                // This data provider wasn't the one selected and therefore the plugin isn't compatible.
159
                return false;
160
            }
161
        }
162
163
        return true;
164
    }
165
166
167
    /**
168
     * Enable a plugin for a certain game mode.
169
     *
170
     * @param PluginDescription $plugin
171
     * @param $title
172
     * @param $mode
173
     * @param $script
174
     */
175
    protected function enablePlugin(PluginDescription $plugin, $title, $mode, $script)
176
    {
177
        $plugin->setIsEnabled(true);
178
        $pluginService = $this->container->get($plugin->getPluginId());
179
180 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...
181
            $pluginService->setStatus(true);
182
        }
183
184
        $this->console->getConsoleOutput()
185
            ->writeln("<info>Plugin <comment>'{$plugin->getPluginId()}'</comment> is enabled with providers :</info>");
186
        foreach ($plugin->getDataProviders() as $provider) {
187
            $this->dataProviderManager->registerPlugin($provider, $plugin->getPluginId(), $title, $mode, $script);
188
        }
189
190
        $this->enabledPlugins[$plugin->getPluginId()] = $plugin;
191
    }
192
193
    /**
194
     * Disable a plugin.
195
     *
196
     * @param PluginDescription $plugin
197
     *
198
     */
199
    protected function disablePlugin(PluginDescription $plugin)
200
    {
201
        $plugin->setIsEnabled(false);
202
        $pluginService = $this->container->get($plugin->getPluginId());
203
204
        foreach ($plugin->getDataProviders() as $provider) {
205
            $this->dataProviderManager->deletePlugin($provider, $plugin->getPluginId());
206
        }
207
208 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...
209
            unset($this->enabledPlugins[$plugin->getPluginId()]);
210
211
            if ($pluginService instanceof StatusAwarePluginInterface) {
212
                $pluginService->setStatus(true);
213
            }
214
        }
215
    }
216
217
    /**
218
     * Check if a plugin is enabled or not.
219
     *
220
     * @param $pluginId
221
     *
222
     * @return bool
223
     */
224
    public function isPluginEnabled($pluginId)
225
    {
226
        return isset($this->enabledPlugins[$pluginId]);
227
    }
228
229
    /**
230
     * Register a plugin.
231
     *
232
     * @param string $id The service id of the plugin to register.
233
     * @param string[] $dataProviders The data providers it needs to work.
234
     * @param string[] $parents The parent plugins.
235
     */
236 48
    public function registerPlugin($id, $dataProviders, $parents, $dataProviderName = null)
237
    {
238 48
        if (!isset($this->plugins[$id])) {
239 48
            $this->plugins[$id] = $this->pluginDescriptionFactory->create($id);
240
        }
241
242 48
        $this->plugins[$id]->setDataProviders($dataProviders);
243 48
        $this->plugins[$id]->setParents($parents);
244 48
        $this->plugins[$id]->setDataProviderName($dataProviderName);
245 48
    }
246
}
247