Completed
Push — dev ( 8eacd8...04be10 )
by De Cramer
02:44
created

PluginManager::reset()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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