Completed
Pull Request — master (#22)
by De Cramer
02:18
created

PluginManager::enableDisablePlugins()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 20
ccs 0
cts 10
cp 0
rs 8.8571
c 1
b 0
f 0
cc 6
eloc 10
nc 5
nop 5
crap 42
1
<?php
2
3
namespace eXpansion\Core\Services;
4
5
use eXpansion\Core\Model\Plugin\PluginDescription;
6
use eXpansion\Core\Model\Plugin\PluginDescriptionFactory;
7
use eXpansion\Core\Plugins\StatusAwarePluginInterface;
8
use Symfony\Component\DependencyInjection\ContainerInterface;
9
10
/**
11
 * Class PluginManager handles all the plugins.
12
 *
13
 * @TODO handle gamemode change.
14
 *
15
 * @package eXpansion\Core\Services
16
 */
17
class PluginManager
18
{
19
    /** @var PluginDescription[] List of all the plugins adescriptions. */
20
    protected $plugins = [];
21
22
    /** @var PluginDescription[] List of all the root plugins. Plugin that depends of no plugins */
23
    protected $pluginsTree = [];
24
25
    /** @var PluginDescriptionFactory  */
26
    protected $pluginDescriptionFactory;
27
28
    /** @var ContainerInterface  */
29
    protected $container;
30
31
    /** @var DataProviderManager  */
32
    protected $dataProviderManager;
33
34
    /**
35
     * PluginManager constructor.
36
     *
37
     * @param ContainerInterface $container
38
     * @param DataProviderManager $dataProviderManager
39
     */
40 7
    public function __construct(
41
        ContainerInterface $container,
42
        PluginDescriptionFactory $pluginDescriptionFactory,
43
        DataProviderManager $dataProviderManager
44
    )
45
    {
46 7
        $this->container = $container;
47 7
        $this->pluginDescriptionFactory = $pluginDescriptionFactory;
48 7
        $this->dataProviderManager = $dataProviderManager;
49 7
    }
50
51
    /**
52
     * Initialize plugins.
53
     */
54
    public function init() {
55
        // TODO get this data from the dedicated!
56
        $title = 'TMStadium@nadeo';
57
        $mode = 'script';
58
        $script = 'TimeAttack.script.txt';
59
60
        $this->createPluginTree();
61
        $this->enableDisablePlugins($this->pluginsTree, $title, $mode, $script);
62
    }
63
64
    /**
65
     * Recursively enable disable plugins taking into account dependencies.
66
     *
67
     * @param PluginDescription[] $pluginsTree
68
     * @param $title
69
     * @param $mode
70
     * @param $script
71
     * @param bool $isCompatible
72
     *
73
     */
74
    protected function enableDisablePlugins($pluginsTree, $title, $mode, $script, $isCompatible = true)
75
    {
76
        foreach ($pluginsTree as $plugin) {
77
            // If parent product isn't compatible then this plugin needs disabling.
78
            // if not check all children plugins to see which ones needs enabling.
79
            if ($isCompatible && $this->isPluginCompatible($plugin, $title, $mode, $script)) {
80
                $this->enablePlugin($plugin, $title, $mode, $script);
81
82
                if (!empty($plugin->getChildrens())) {
83
                    $this->enableDisablePlugins($plugin->getChildrens(), $title, $mode, $script, true);
84
                }
85
            } else {
86
                $this->disablePlugin($plugin);
87
88
                if (!empty($plugin->getChildrens())) {
89
                    $this->enableDisablePlugins($plugin->getChildrens(), $title, $mode, $script, false);
90
                }
91
            }
92
        }
93
    }
94
95
    /**
96
     * Check if a plugin is compatible.
97
     *
98
     * @param PluginDescription $plugin
99
     * @param $title
100
     * @param $mode
101
     * @param $script
102
     *
103
     * @return bool
104
     */
105
    protected function isPluginCompatible(PluginDescription $plugin, $title, $mode, $script)
106
    {
107
        foreach ($plugin->getDataProviders() as $provider) {
108
            if (!$this->dataProviderManager->isProviderCompatible($provider, $title, $mode, $script)) {
109
                return false;
110
            }
111
        }
112
113
        return true;
114
    }
115
116
    /**
117
     * Enable a plugin for a certain game mode.
118
     *
119
     * @param PluginDescription $plugin
120
     * @param $title
121
     * @param $mode
122
     * @param $script
123
     */
124
    protected function enablePlugin(PluginDescription $plugin, $title, $mode, $script) {
125
        $plugin->setIsEnabled(true);
126
        $pluginService = $this->container->get($plugin->getPluginId());
127
128
        if ($pluginService instanceof StatusAwarePluginInterface) {
129
            $pluginService->setStatus(true);
130
        }
131
132
        foreach ($plugin->getDataProviders() as $provider) {
133
            $this->dataProviderManager->registerPlugin($provider, $plugin->getPluginId(), $title, $mode, $script);
134
        }
135
    }
136
137
    /**
138
     * Disable a plugin.
139
     *
140
     * @param PluginDescription $plugin
141
     *
142
     */
143
    protected function disablePlugin(PluginDescription $plugin) {
144
        $plugin->setIsEnabled(false);
145
146
        foreach ($plugin->getDataProviders() as $provider) {
147
            $this->dataProviderManager->deletePlugin($provider, $plugin->getPluginId());
148
        }
149
    }
150
151
    /**
152
     * Create a plugin tree to handle plugin dependencies.
153
     */
154
    protected function createPluginTree()
155
    {
156
        // Inverse order so that we have get childrends from the plugins.
157
        $toRemove = [];
158
        foreach ($this->plugins as $plugin) {
159
            if (!empty($plugin->getParents())) {
160
                foreach ($plugin->getParents() as $parentId) {
161
                    if ($this->plugins[$parentId]) {
162
                        $this->plugins[$parentId]->addChildren($plugin);
163
                    } else {
164
                        $toRemove[] = $plugin->getPluginId();
165
                        break;
166
                    }
167
                }
168
            }
169
        }
170
        // TODO handle removed plugin, those plugins aren't just not compatible they are broken.
171
172
        // For now own we will hand plugins recusively.
173
        foreach ($this->plugins as $plugin) {
174
            if (empty($plugin->getParents())) {
175
                $this->pluginsTree[] = $plugin;
176
            }
177
        }
178
    }
179
180
    /**
181
     * Register a plugin.
182
     *
183
     * @param string $id The service id of the plugin to register.
184
     * @param string[] $dataProviders The data providers it needs to work.
185
     * @param string[] $parents The parent plugins.
186
     */
187 7
    public function registerPlugin($id, $dataProviders, $parents) {
188 7
        if (!isset($this->plugins[$id])) {
189 7
            $this->plugins[$id] = $this->pluginDescriptionFactory->create($id);
190
        }
191
192 7
        $this->plugins[$id]->setDataProviders($dataProviders);
193 7
        $this->plugins[$id]->setParents($parents);
194 7
    }
195
}
196