Passed
Push — master ( b1ae9b...a69512 )
by Charlotte
02:28
created

PlasmaProvider::destroy()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Livia
4
 * Copyright 2017-2018 Charlotte Dunois, All Rights Reserved
5
 *
6
 * Website: https://charuru.moe
7
 * License: https://github.com/CharlotteDunois/Livia/blob/master/LICENSE
8
*/
9
10
namespace CharlotteDunois\Livia\Providers;
11
12
/**
13
 * Loads and stores settings associated with guilds in a database using Plasma. Requires the composer package `plasma/core` **and** a driver of your choice.
14
 */
15
class PlasmaProvider extends SettingProvider {
16
    /**
17
     * The DB connection.
18
     * @var \Plasma\ClientInterface
19
     */
20
    protected $db;
21
    
22
    /**
23
     * A collection of a guild's settings, mapped by guild ID.
24
     * @var \CharlotteDunois\Collect\Collection
25
     */
26
    protected $settings;
27
    
28
    /**
29
     * Constructs a new instance.
30
     * @param \Plasma\ClientInterface  $db
31
     */
32
    function __construct(\Plasma\ClientInterface $db) {
33
        $this->db = $db;
34
        $this->providerState = \CharlotteDunois\Livia\Providers\SettingProvider::STATE_READY;
35
        
36
        $this->settings = new \CharlotteDunois\Collect\Collection();
37
    }
38
    
39
    /**
40
     * Resets the state.
41
     * @return void
42
     * @internal
43
     */
44
    function __sleep() {
45
        $this->providerState = \CharlotteDunois\Livia\Providers\SettingProvider::STATE_IDLE;
46
    }
47
    
48
    /**
49
     * Returns the Plasma client.
50
     * @return \Plasma\ClientInterface
51
     */
52
    function getClient() {
53
        return $this->db;
54
    }
55
    
56
    /**
57
     * {@inheritdoc}
58
     * @return \React\Promise\ExtendedPromiseInterface
59
     */
60
    function destroy() {
61
        $this->removeListeners();
62
        
63
        return $this->db->close();
64
    }
65
    
66
    /**
67
     * {@inheritdoc}
68
     * @return \React\Promise\ExtendedPromiseInterface
69
     */
70
    function init(\CharlotteDunois\Livia\LiviaClient $client): \React\Promise\ExtendedPromiseInterface {
71
        $this->client = $client;
72
        $this->attachListeners();
73
        
74
        return $this->db->execute('CREATE TABLE IF NOT EXISTS settings (guild VARCHAR(20) NOT NULL, settings TEXT NOT NULL, PRIMARY KEY (guild))')
75
            ->then(function () {
76
                return $this->db->execute('SELECT * FROM settings')->then(function (\Plasma\StreamQueryResultInterface $result) {
77
                    return $result->all()->then(function (\Plasma\QueryResultInterface $result) {
78
                        $rows = $result->getRows();
79
                        
80
                        foreach($rows as $row) {
81
                            $this->loadRow($row);
82
                        }
83
                        
84
                        if($this->settings->has('global')) {
85
                            return null;
86
                        }
87
                        
88
                        return $this->create('global')->then(function () {
89
                            return null;
90
                        });
91
                    });
92
                });
93
            });
94
    }
95
    
96
    /**
97
     * Creates a new table row in the db for the guild, if it doesn't exist already - otherwise loads the row.
98
     * @param string|\CharlotteDunois\Yasmin\Models\Guild  $guild
99
     * @param array|\ArrayObject                           $settings
100
     * @return \React\Promise\ExtendedPromiseInterface
101
     * @throws \InvalidArgumentException
102
     */
103
    function create($guild, &$settings = array()): \React\Promise\ExtendedPromiseInterface {
104
        $guild = $this->getGuildID($guild);
105
        
106
        return $this->db->execute('SELECT * FROM settings WHERE guild = ?', array($guild))
107
            ->then(function ($result) use ($guild, &$settings) {
108
                return $result->all()->then(function (\Plasma\QueryResultInterface $result) use ($guild, &$settings) {
109
                    $rows = $result->getRows();
110
                    
111
                    if(empty($rows)) {
112
                        $this->settings->set($guild, $settings);
113
                        
114
                        return $this->db->execute(
115
                            'INSERT INTO settings (guild, settings) VALUES (?, ?)',
116
                            array($guild, \json_encode($settings))
117
                        );
118
                    } else {
119
                        $this->loadRow($rows[0]);
120
                    }
121
                });
122
            });
123
    }
124
    
125
    /**
126
     * {@inheritdoc}
127
     * @return mixed
128
     */
129
    function get($guild, string $key, $defaultValue = null) {
130
        $guild = $this->getGuildID($guild);
131
        
132
        if($this->settings->get($guild) === null) {
133
            $this->client->emit('warn', 'Settings of specified guild is not loaded - loading row - returning default value');
134
            
135
            $this->create($guild);
136
            return $defaultValue;
137
        }
138
        
139
        $settings = $this->settings->get($guild);
140
        if(\array_key_exists($key, $settings)) {
141
            return $settings[$key];
142
        }
143
        
144
        return $defaultValue;
145
    }
146
    
147
    /**
148
     * {@inheritdoc}
149
     * @return \React\Promise\ExtendedPromiseInterface
150
     */
151
    function set($guild, string $key, $value) {
152
        $guild = $this->getGuildID($guild);
153
        
154
        if($this->settings->get($guild) === null) {
155
            return $this->create($guild)->then(function () use ($guild, $key, $value) {
156
                $settings = $this->settings->get($guild);
157
                $settings[$key] = $value;
158
            
159
                return $this->db->execute('UPDATE settings SET settings = ? WHERE guild = ?', array(\json_encode($settings), $guild));
160
            });
161
        }
162
        
163
        $settings = $this->settings->get($guild);
164
        $settings[$key] = $value;
165
        
166
        return $this->db->execute('UPDATE settings SET settings = ? WHERE guild = ?', array(\json_encode($settings), $guild));
167
    }
168
    
169
    /**
170
     * {@inheritdoc}
171
     * @return \React\Promise\ExtendedPromiseInterface
172
     */
173
    function remove($guild, string $key) {
174
        $guild = $this->getGuildID($guild);
175
        
176
        if($this->settings->get($guild) === null) {
177
            $this->client->emit('warn', 'Settings of specified guild is not loaded - loading row');
178
            
179
            return $this->create($guild)->then(function () use ($guild, $key) {
180
                $settings = $this->settings->get($guild);
181
                unset($settings[$key]);
182
            
183
                return $this->db->execute('UPDATE settings SET settings = ? WHERE guild = ?', array(\json_encode($settings), $guild));
184
            });
185
        }
186
        
187
        $settings = $this->settings->get($guild);
188
        unset($settings[$key]);
189
        
190
        return $this->db->execute('UPDATE settings SET settings = ? WHERE guild = ?', array(\json_encode($settings), $guild));
191
    }
192
    
193
    /**
194
     * {@inheritdoc}
195
     * @return \React\Promise\ExtendedPromiseInterface
196
     */
197
    function clear($guild) {
198
        $guild = $this->getGuildID($guild);
199
        
200
        $this->settings->delete($guild);
201
        return $this->db->execute('DELETE FROM settings WHERE guild = ?', array($guild));
202
    }
203
    
204
    /**
205
     * Processes a database row.
206
     * @param array  $row
207
     * @return void
208
     */
209
    protected function loadRow(array $row) {
210
        $settings = \json_decode($row['settings'], true);
211
        if($settings === null) {
212
            $this->client->emit('warn', 'PlasmaProvider couldn\'t parse the settings stored for guild "'.$row['guild'].'". Error: '.\json_last_error_msg());
213
            return;
214
        }
215
        
216
        $settings = new \ArrayObject($settings, \ArrayObject::ARRAY_AS_PROPS);
217
        $this->settings->set($row['guild'], $settings);
218
        
219
        try {
220
            $this->setupGuild($row['guild']);
221
        } catch (\InvalidArgumentException $e) {
222
            $this->settings->delete($row['guild']);
223
            
224
            $this->db->execute('DELETE FROM settings WHERE guild = ?', array($row['guild']))
225
                ->done(null, array($this->client, 'handlePromiseRejection'));
226
        }
227
    }
228
}
229