Completed
Pull Request — master (#393)
by De Cramer
02:39
created

ConfigManager   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 229
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 17.65%

Importance

Changes 0
Metric Value
wmc 22
lcom 1
cbo 7
dl 0
loc 229
ccs 15
cts 85
cp 0.1765
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 1
B set() 0 48 6
A get() 0 17 3
A registerConfig() 0 7 1
A loadConfigValues() 0 32 4
A saveConfigValues() 0 19 2
A getConfigDefinitionTree() 0 4 1
A getAllConfigs() 0 14 4
1
<?php
2
3
namespace eXpansion\Framework\Config\Services;
4
5
use eXpansion\Framework\Config\Exception\UnhandledConfigurationException;
6
use eXpansion\Framework\Config\Model\ConfigInterface;
7
use eXpansion\Framework\Config\Ui\UiInterface;
8
use eXpansion\Framework\Core\Services\Application\DispatcherInterface;
9
10
use eXpansion\Framework\Core\Storage\GameDataStorage;
11
use League\Flysystem\File;
12
use League\Flysystem\Filesystem;
13
use oliverde8\AssociativeArraySimplified\AssociativeArray;
14
use Psr\Log\LoggerInterface;
15
16
/**
17
 * Class ConfigManager
18
 *
19
 * @author    de Cramer Oliver<[email protected]>
20
 * @copyright 2018 eXpansion
21
 * @package eXpansion\Framework\Config\Services
22
 */
23
class ConfigManager implements ConfigManagerInterface
24
{
25
    /** @var DispatcherInterface */
26
    protected $dispatcher;
27
28
    /** @var GameDataStorage */
29
    protected $gameDataStorage;
30
31
    /** @var Filesystem */
32
    protected $filesystem;
33
34
    /** @var LoggerInterface */
35
    protected $logger;
36
37
    /** @var ConfigInterface */
38
    protected $configurationDefinitions = [];
39
40
    /** @var string[] */
41
    protected $configurationIds = [];
42
43
    /** @var AssociativeArray */
44
    protected $configTree;
45
46
    /** @var AssociativeArray */
47
    protected $globalConfigurations;
48
49
    /** @var AssociativeArray */
50
    protected $keyConfigurations;
51
52
    /** @var AssociativeArray */
53
    protected $serverConfigurations;
54
55
    /** @var bool  */
56
    protected $disableDispatch = false;
57
58
    /**
59
     * ConfigManager constructor.
60
     *
61
     * @param DispatcherInterface $dispatcher
62
     * @param GameDataStorage     $gameDataStorage
63
     * @param Filesystem          $filesystem
64
     * @param LoggerInterface     $logger
65
     */
66 2
    public function __construct(
67
        DispatcherInterface $dispatcher,
68
        GameDataStorage $gameDataStorage,
69
        Filesystem $filesystem,
70
        LoggerInterface $logger
71
    ) {
72 2
        $this->dispatcher = $dispatcher;
73 2
        $this->gameDataStorage = $gameDataStorage;
74 2
        $this->filesystem = $filesystem;
75 2
        $this->logger = $logger;
76
77 2
        $this->configTree = new AssociativeArray();
78 2
    }
79
80
    /**
81
     * @inheritdoc
82
     */
83
    public function set($path, $value) : bool
84
    {
85
        /** @var ConfigInterface $configDefinition */
86
        $configDefinition = $this->configTree->get($path);
87
        if (is_null($configDefinition)) {
88
            throw new UnhandledConfigurationException("'{$path}' is not handled by the config manager!");
89
        }
90
91
        // Fetch old value for event.
92
        $oldValue = $this->get($path);
93
        // Put new value.
94
        $configs = $this->getAllConfigs($configDefinition->getScope());
95
96
        // If value is default value better not to store it.
97
        if ($value == $configDefinition->getDefaultValue()) {
98
            // This is a temporary work around as AssociativeArray don't support unsetting elements at the moment.
99
            $cpath = implode('/', array_slice(explode('/', $path), 0,-1));
100
            $data = $configs->get($cpath);
101
            $lapth = implode('/', array_slice(explode('/', $path), -1));
102
            if(isset($data[$lapth])) {
103
                unset($data[$lapth]);
104
                $configs->set($cpath, $data);
105
            }
106
        } else {
107
            $configs->set($path, $value);
108
        }
109
110
        // Dispatch and save changes.
111
        if ($this->disableDispatch || $oldValue === $value) {
112
            $this->logger->debug(
113
                'New config was set, but no changes, save and dispatch are canceled!',
114
                ['path' => $path]
115
            );
116
            return true;
117
        }
118
119
        $this->saveConfigValues();
120
        $this->dispatcher->dispatch(
121
            'expansion.config.change',
122
            [
123
                'config' => $configDefinition,
124
                'id' => $this->configurationIds[spl_object_hash($configDefinition)],
125
                'oldValue' => $oldValue
126
            ]
127
        );
128
129
        return true;
130
    }
131
132
    /**
133
     * @inheritdoc
134
     */
135
    public function get($path)
136
    {
137
        /** @var ConfigInterface $configDefinition */
138
        $configDefinition = $this->configTree->get($path);
139
        if (is_null($configDefinition)) {
140
            throw new UnhandledConfigurationException("'{$path}' is not handled by the config manager!");
141
        }
142
143
        $configs = $this->getAllConfigs($configDefinition->getScope());
144
        $value = $configs->get($path);
145
146
        if (is_null($value)) {
147
            return $configDefinition->getDefaultValue();
148
        }
149
150
        return $value;
151
    }
152
153
    /**
154
     * @inheritdoc
155
     */
156
    public function getAllConfigs($scope) : AssociativeArray
157
    {
158
        $this->loadConfigValues();
159
160
        switch ($scope) {
161
            case ConfigInterface::SCOPE_SERVER:
162
                return $this->serverConfigurations;
163
            case ConfigInterface::SCOPE_KEY:
164
                return $this->keyConfigurations;
165
            case ConfigInterface::SCOPE_GLOBAL:
166
            default:
167
                return $this->globalConfigurations;
168
        }
169
    }
170
171
    /**
172
     * Register a config to be handled by the config manager.
173
     *
174
     * @param ConfigInterface $config
175
     * @param $id
176
     */
177 2
    public function registerConfig(ConfigInterface $config, $id)
178
    {
179 2
        $this->configurationDefinitions[spl_object_hash($config)] = $config;
180 2
        $this->configurationIds[spl_object_hash($config)] = $id;
181 2
        $this->configTree->set($config->getPath(), $config);
182 2
        $config->setConfigManager($this);
183 2
    }
184
185
    /**
186
     * @inheritdoc
187
     */
188
    public function loadConfigValues()
189
    {
190
        if (!is_null($this->globalConfigurations)) {
191
            return;
192
        }
193
194
        $this->globalConfigurations = new AssociativeArray();
195
        $this->keyConfigurations = new AssociativeArray();
196
        $this->serverConfigurations = new AssociativeArray();
197
198
        /** @var AssociativeArray[] $configs */
199
        $configs = [
200
            'global' => $this->globalConfigurations,
201
            'key' => $this->keyConfigurations,
202
            'server-' . $this->gameDataStorage->getSystemInfo()->serverLogin => $this->serverConfigurations,
203
        ];
204
205
        foreach ($configs as $filekey => $config) {
206
            $this->logger->debug(
207
                'Loading config file',
208
                ['file' => "config-$filekey.json"]
209
            );
210
211
            /** @var File $file */
212
            if ($this->filesystem->has("config-$filekey.json")) {
213
                $file = $this->filesystem->get("config-$filekey.json");
214
215
                $values = json_decode($file->read(), true);
216
                $config->setData($values);
217
            }
218
        }
219
    }
220
221
    /**
222
     * @inheritdoc
223
     */
224
    public function saveConfigValues()
225
    {
226
        /** @var AssociativeArray[] $configs */
227
        $configs = [
228
            'global' => $this->globalConfigurations,
229
            'key' => $this->keyConfigurations,
230
            'server-' . $this->gameDataStorage->getSystemInfo()->serverLogin => $this->serverConfigurations,
231
        ];
232
233
        foreach ($configs as $filekey => $config) {
234
            $this->logger->debug(
235
                'Saving config file',
236
                ['file' => "config-$filekey.json"]
237
            );
238
239
            $encoded = json_encode($config->getArray(), JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT);
240
            $this->filesystem->put("config-$filekey.json", $encoded);
241
        }
242
    }
243
244
    /**
245
     * @inheritdoc
246
     */
247 2
    public function getConfigDefinitionTree(): AssociativeArray
248
    {
249 2
        return $this->configTree;
250
    }
251
}
252