Completed
Pull Request — master (#6)
by De Cramer
11:31
created

PluginManager::enablePlugin()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

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