Completed
Push — master ( 9af197...103743 )
by Leandro
01:33
created

Settings   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 247
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 94.5%

Importance

Changes 0
Metric Value
wmc 27
lcom 1
cbo 7
dl 0
loc 247
ccs 103
cts 109
cp 0.945
rs 10
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A getDb() 0 4 1
A exists() 0 17 3
B get() 0 30 7
A set() 0 28 3
A all() 0 21 2
A save() 0 6 2
A remove() 0 17 2
A removeAll() 0 12 2
A createQuery() 0 12 2
A beforeExecute() 0 6 1
A buildCacheKey() 0 7 2
1
<?php
2
3
namespace Soluto\Settings;
4
5
use Yii;
6
use yii\base\Component;
7
use yii\db\Connection;
8
use yii\db\Query;
9
use yii\base\Event;
10
use yii\helpers\Json;
11
12
class Settings extends Component
13
{
14
    /**
15
     * @event SettingsEvent an event that is triggered before execute command.
16
     */
17
    const EVENT_BEFORE_EXECUTE = 'beforeExecute';
18
19
    /*
20
     * @var array The settings cache
21
     */
22
    private $_data = [];
23
24
    /**
25
     * @var string Name of the table where configurations will be stored
26
     */
27
    public $tableName = '{{%setting}}';
28
29
    /**
30
     * @var string Name of column where keys will be stored
31
     */
32
    public $keyColumnName = 'key';
33
34
    /**
35
     * @var string Name of column where values will be stored
36
     */
37
    public $valueColumnName = 'value';
38
39
    /**
40
     * @return Connection the DB connection instance
41
     */
42 2
    protected function getDb()
43
    {
44 2
        return Yii::$app->getDb();
45
    }
46
47
    /**
48
     * Whether the setting exists in the database
49
     * @param string $name the setting name
50
     * @return bool
51
     */
52 2
    protected function exists($name)
53
    {
54 2
        $event = $this->beforeExecute();
55 2
        $key = $this->buildCacheKey($name, $event->data);
56
57 2
        if (isset($this->_data[$key])) {
58 1
            return true;
59
        }
60
61 2
        $query = $this->createQuery($name);
62
63 2
        if ($event->data) {
64 1
            $query->andWhere($event->data);
65 1
        }
66
67 2
        return $query->exists();
68
    }
69
70
    /**
71
     * Returns setting value from database
72
     * @param string $name setting name
73
     * @return mixed $defaultValue
74
     */
75 2
    public function get($name, $defaultValue = null)
76
    {
77 2
        $event = $this->beforeExecute();
78 2
        $key = $this->buildCacheKey($name, $event->data);
79
80 2
        if (isset($this->_data[$key])) {
81 2
            return $this->_data[$key];
82
        }
83
84 1
        $query = $this->createQuery($name);
85
86 1
        if ($event->data) {
87
            $query->andWhere($event->data);
88
        }
89
90 1
        $row = $query->one($this->getDb());
91
92 1
        $value = ($row) ? $row[$this->valueColumnName] : null;
93
94 1
        if (is_string($value) && trim($value) == '') {
95
            $value = null;
96
        }
97
98 1
        if ($value === null) {
99 1
            $value = $defaultValue;
100 1
        }
101
102 1
        $this->_data[$name] = $value;
103 1
        return $value;
104
    }
105
106
    /**
107
     * Store setting value to database
108
     * @param string $name
109
     * @param mixed $value
110
     */
111 2
    public function set($name, $value)
112
    {
113 2
        $db = $this->getDb();
114 2
        $event = $this->beforeExecute();
115
116 2
        $key = $this->buildCacheKey($name, $event->data);
117 2
        $values = [$this->valueColumnName => $value];
118 2
        $where = [$this->keyColumnName => $name];
119
120 2
        if ($event->data) {
121 1
            $values = array_merge($event->data, $values);
122 1
            $where = array_merge($event->data, $where);
123 1
        }
124
125 2
        if ($this->exists($name)) {
126 1
            $db->createCommand()
127 1
                ->update($this->tableName, $values, $where)
128 1
                ->execute();
129 1
        } else  {
130 2
            $values = array_merge($values, $where);
131
132 2
            $db->createCommand()
133 2
                ->insert($this->tableName, $values)
134 2
                ->execute();
135
        }
136
137 2
        $this->_data[$key] = $value;
138 2
    }
139
140
    /**
141
     * Retrieves all setting stored in database
142
     * @return array
143
     */
144 1
    public function all()
145
    {
146 1
        $result = [];
147 1
        $event = $this->beforeExecute();
148
149 1
        $query = $this->createQuery()
150 1
            ->addSelect($this->keyColumnName);
151
152 1
        $rows = $query->all($this->getDb());
153
154 1
        foreach ($rows as $row) {
155 1
            $value = $row[$this->valueColumnName];
156 1
            $name = $row[$this->keyColumnName];
157 1
            $key = $this->buildCacheKey($name, $event->data);
158
159 1
            $result[$name] = $value;
160 1
            $this->_data[$key] = $value;
161 1
        }
162
163 1
        return $result;
164
    }
165
166
    /**
167
     * Store all settings in database
168
     * @param array $names
169
     */
170 1
    public function save($names)
171
    {
172 1
        foreach ($names as $key => $value) {
173 1
            $this->set($key, $value) ;
174 1
        }
175 1
    }
176
177
    /**
178
     * Remove specified setting
179
     * @param array|string $name
180
     */
181 1
    public function remove($name)
182
    {
183 1
        $event = $this->beforeExecute();
184 1
        $key = $this->buildCacheKey($name, $event->data);
0 ignored issues
show
Bug introduced by
It seems like $name defined by parameter $name on line 181 can also be of type array; however, Soluto\Settings\Settings::buildCacheKey() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
185 1
        $where = [$this->keyColumnName => $name];
186
187 1
        if ($event->data) {
188
            $where = array_merge($event->data, $where);
189
        }
190
191 1
        $this->getDb()
192 1
            ->createCommand()
193 1
            ->delete($this->tableName, $where)
194 1
            ->execute();
195
196 1
        unset($this->_data[$key]);
197 1
    }
198
199
    /**
200
     * Removes all settings
201
     */
202 1
    public function removeAll()
203
    {
204 1
        $event = $this->beforeExecute();
205 1
        $where = $event->data ? $event->data : '';
206
207 1
        $this->getDb()
208 1
            ->createCommand()
209 1
            ->delete($this->tableName, $where)
210 1
            ->execute();
211
212 1
        $this->_data[] = [];
213 1
    }
214
215
    /**
216
     * Creates query to find settings value
217
     * @param string $name
218
     * @return \yii\db\Query
219
     */
220 2
    protected function createQuery($name = null)
221
    {
222 2
        $query = (new Query())
223 2
            ->select([$this->valueColumnName])
224 2
            ->from($this->tableName);
225
226 2
        if ($name) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $name of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
227 2
            $query->andWhere([$this->keyColumnName => $name]);
228 2
        }
229
230 2
        return $query;
231
    }
232
233
    /**
234
     * This method is called at the before execute db command
235
     * @return yii\base\Event
236
     */
237 2
    protected function beforeExecute()
238
    {
239 2
        $event = new Event();
240 2
        $this->trigger(self::EVENT_BEFORE_EXECUTE, $event);
241 2
        return $event;
242
    }
243
244
    /**
245
     * Builds the unique cache key
246
     * @param string $name
247
     * @param array $data
248
     * @return void
249
     */
250 2
    protected function buildCacheKey($name, $data)
251
    {
252 2
        if ($data) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $data of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
253 1
            return Json::encode($data) . $name;
254
        }
255 1
        return $name;
256
    }
257
258
}
259