Completed
Push — master ( 052401...b48953 )
by De Cramer
03:27
created

PluginManager::disablePlugin()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 16
Code Lines 9

Duplication

Lines 7
Ratio 43.75 %

Code Coverage

Tests 0
CRAP Score 20

Importance

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