Completed
Pull Request — master (#233)
by De Cramer
08:53
created

ConfigManager::set()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 49
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 49
c 0
b 0
f 0
rs 8.5906
cc 6
eloc 27
nc 7
nop 2
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
     */
63
    public function __construct(
64
        DispatcherInterface $dispatcher,
65
        GameDataStorage $gameDataStorage,
66
        Filesystem $filesystem,
67
        LoggerInterface $logger
68
    ) {
69
        $this->dispatcher = $dispatcher;
70
        $this->gameDataStorage = $gameDataStorage;
71
        $this->filesystem = $filesystem;
72
        $this->logger = $logger;
73
74
        $this->configTree = new AssociativeArray();
75
    }
76
77
    /**
78
     * @inheritdoc
79
     */
80
    public function set($path, $value) : bool
81
    {
82
        /** @var ConfigInterface $configDefinition */
83
        $configDefinition = $this->configTree->get($path);
84
        if (is_null($configDefinition)) {
85
            throw new UnhandledConfigurationException("'{$path}' is not handled by the config manager!");
86
        }
87
88
        // Fetch old value for event.
89
        $oldValue = $this->get($path);
90
91
        // Put new value.
92
        $configs = $this->getAllConfigs($configDefinition->getScope());
93
94
        // If value is default value better not to store it.
95
        if ($value == $configDefinition->getDefaultValue()) {
96
            // This is a temporary work around as AssociativeArray don't support unsetting elements at the moment.
97
            $cpath = implode('/', array_slice(explode('/', $path), 0,-1));
98
            $data = $configs->get($cpath);
99
            $lapth = implode('/', array_slice(explode('/', $path), -1));
100
            if(isset($data[$lapth])) {
101
                unset($data[$lapth]);
102
                $configs->set($cpath, $data);
103
            }
104
        } else {
105
            $configs->set($path, $value);
106
        }
107
108
        // Dispatch and save changes.
109
        if ($this->disableDispatch || $oldValue === $value) {
110
            $this->logger->debug(
111
                'New conig was set, but no changes, save and dispatch are canceled!',
112
                ['path' => $path]
113
            );
114
            return true;
115
        }
116
117
        $this->saveConfigValues();
118
        $this->dispatcher->dispatch(
119
            'expansion.config.change',
120
            [
121
                'config' => $configDefinition,
122
                'id' => $this->configurationIds[spl_object_hash($configDefinition)],
123
                'oldValue' => $oldValue
124
            ]
125
        );
126
127
        return true;
128
    }
129
130
    /**
131
     * @inheritdoc
132
     */
133
    public function get($path)
134
    {
135
        /** @var ConfigInterface $configDefinition */
136
        $configDefinition = $this->configTree->get($path);
137
        if (is_null($configDefinition)) {
138
            throw new UnhandledConfigurationException("'{$path}' is not handled by the config manager!");
139
        }
140
141
        $configs = $this->getAllConfigs($configDefinition->getScope());
142
        $value = $configs->get($path);
143
144
        if (is_null($value)) {
145
            return $configDefinition->getDefaultValue();
146
        }
147
148
        return $value;
149
    }
150
151
    /**
152
     * @inheritdoc
153
     */
154
    public function getAllConfigs($scope) : AssociativeArray
155
    {
156
        $this->loadConfigValues();
157
158
        switch ($scope) {
159
            case ConfigInterface::SCOPE_SERVER:
160
                return $this->serverConfigurations;
161
            case ConfigInterface::SCOPE_KEY:
162
                return $this->keyConfigurations;
163
            case ConfigInterface::SCOPE_GLOBAL:
164
            default:
165
                return $this->globalConfigurations;
166
        }
167
    }
168
169
    /**
170
     * Register a config to be handled by the config manager.
171
     *
172
     * @param ConfigInterface $config
173
     * @param $id
174
     */
175
    public function registerConfig(ConfigInterface $config, $id)
176
    {
177
        $this->configurationDefinitions[spl_object_hash($config)] = $config;
178
        $this->configurationIds[spl_object_hash($config)] = $id;
179
        $this->configTree->set($config->getPath(), $config);
180
    }
181
182
    /**
183
     * @inheritdoc
184
     */
185
    public function loadConfigValues()
186
    {
187
        if (!is_null($this->globalConfigurations)) {
188
            return;
189
        }
190
191
        $this->globalConfigurations = new AssociativeArray();
192
        $this->keyConfigurations = new AssociativeArray();
193
        $this->serverConfigurations = new AssociativeArray();
194
195
        /** @var AssociativeArray[] $configs */
196
        $configs = [
197
            'global' => $this->globalConfigurations,
198
            'key' => $this->keyConfigurations,
199
            'server-' . $this->gameDataStorage->getSystemInfo()->serverLogin => $this->serverConfigurations,
200
        ];
201
202
        foreach ($configs as $filekey => $config) {
203
            $this->logger->debug(
204
                'Loading config file',
205
                ['file' => "config-$filekey.json"]
206
            );
207
208
            /** @var File $file */
209
            if ($this->filesystem->has("config-$filekey.json")) {
210
                $file = $this->filesystem->get("config-$filekey.json");
211
212
                $values = json_decode($file->read(), true);
213
                $config->setData($values);
214
            }
215
        }
216
    }
217
218
    /**
219
     * @inheritdoc
220
     */
221
    public function saveConfigValues()
222
    {
223
        /** @var AssociativeArray[] $configs */
224
        $configs = [
225
            'global' => $this->globalConfigurations,
226
            'key' => $this->keyConfigurations,
227
            'server-' . $this->gameDataStorage->getSystemInfo()->serverLogin => $this->serverConfigurations,
228
        ];
229
230
        foreach ($configs as $filekey => $config) {
231
            $this->logger->debug(
232
                'Saving config file',
233
                ['file' => "config-$filekey.json"]
234
            );
235
236
            $encoded = json_encode($config->getArray(), JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT);
237
            $this->filesystem->put("config-$filekey.json", $encoded);
238
        }
239
    }
240
241
    /**
242
     * @inheritdoc
243
     */
244
    public function getConfigDefinitionTree(): AssociativeArray
245
    {
246
        return $this->configTree;
247
    }
248
}
249