1
|
|
|
<?php namespace Arcanedev\Settings\Stores; |
2
|
|
|
|
3
|
|
|
use Arcanedev\Settings\Bases\Store; |
4
|
|
|
use Arcanedev\Settings\Contracts\Store as StoreContract; |
5
|
|
|
use Arcanedev\Settings\Utilities\Arr; |
6
|
|
|
use Closure; |
7
|
|
|
use Illuminate\Database\Connection; |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* Class DatabaseStore |
11
|
|
|
* |
12
|
|
|
* @package Arcanedev\Settings\Stores |
13
|
|
|
* @author ARCANEDEV <[email protected]> |
14
|
|
|
*/ |
15
|
|
|
class DatabaseStore extends Store implements StoreContract |
16
|
|
|
{ |
17
|
|
|
/* ------------------------------------------------------------------------------------------------ |
18
|
|
|
| Properties |
19
|
|
|
| ------------------------------------------------------------------------------------------------ |
20
|
|
|
*/ |
21
|
|
|
/** |
22
|
|
|
* The database connection instance. |
23
|
|
|
* |
24
|
|
|
* @var \Illuminate\Database\Connection |
25
|
|
|
*/ |
26
|
|
|
protected $connection; |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* The table to query from. |
30
|
|
|
* |
31
|
|
|
* @var string |
32
|
|
|
*/ |
33
|
|
|
protected $table; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* Any query constraints that should be applied. |
37
|
|
|
* |
38
|
|
|
* @var Closure|null |
39
|
|
|
*/ |
40
|
|
|
protected $queryConstraint; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* Any extra columns that should be added to the rows. |
44
|
|
|
* |
45
|
|
|
* @var array |
46
|
|
|
*/ |
47
|
|
|
protected $extraColumns = []; |
48
|
|
|
|
49
|
|
|
/* ------------------------------------------------------------------------------------------------ |
50
|
|
|
| Constructor |
51
|
|
|
| ------------------------------------------------------------------------------------------------ |
52
|
|
|
*/ |
53
|
|
|
/** |
54
|
|
|
* Make the Database store instance. |
55
|
|
|
* |
56
|
|
|
* @param \Illuminate\Database\Connection $connection |
57
|
|
|
* @param string $table |
58
|
|
|
*/ |
59
|
24 |
|
public function __construct(Connection $connection, $table = null) |
60
|
|
|
{ |
61
|
24 |
|
$this->setConnection($connection); |
62
|
24 |
|
$this->setTable($table ?: 'settings'); |
63
|
24 |
|
} |
64
|
|
|
|
65
|
|
|
/* ------------------------------------------------------------------------------------------------ |
66
|
|
|
| Getters & Setters |
67
|
|
|
| ------------------------------------------------------------------------------------------------ |
68
|
|
|
*/ |
69
|
|
|
/** |
70
|
|
|
* Set the database connection. |
71
|
|
|
* |
72
|
|
|
* @param \Illuminate\Database\Connection $connection |
73
|
|
|
* |
74
|
|
|
* @return self |
75
|
|
|
*/ |
76
|
24 |
|
public function setConnection(Connection $connection) |
77
|
|
|
{ |
78
|
24 |
|
$this->connection = $connection; |
79
|
|
|
|
80
|
24 |
|
return $this; |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Set the table to query from. |
85
|
|
|
* |
86
|
|
|
* @param string $table |
87
|
|
|
* |
88
|
|
|
* @return self |
89
|
|
|
*/ |
90
|
24 |
|
public function setTable($table) |
91
|
|
|
{ |
92
|
24 |
|
$this->table = $table; |
93
|
|
|
|
94
|
24 |
|
return $this; |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* Set the query constraint. |
99
|
|
|
* |
100
|
|
|
* @param \Closure $callback |
101
|
|
|
* |
102
|
|
|
* @return self |
103
|
|
|
*/ |
104
|
|
|
public function setConstraint(Closure $callback) |
105
|
|
|
{ |
106
|
|
|
$this->data = []; |
107
|
|
|
$this->loaded = false; |
108
|
|
|
$this->queryConstraint = $callback; |
109
|
|
|
|
110
|
|
|
return $this; |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* Set extra columns to be added to the rows. |
115
|
|
|
* |
116
|
|
|
* @param array $columns |
117
|
|
|
* |
118
|
|
|
* @return self |
119
|
|
|
*/ |
120
|
|
|
public function setExtraColumns(array $columns) |
121
|
|
|
{ |
122
|
|
|
$this->extraColumns = $columns; |
123
|
|
|
|
124
|
|
|
return $this; |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
/* ------------------------------------------------------------------------------------------------ |
128
|
|
|
| Main Functions |
129
|
|
|
| ------------------------------------------------------------------------------------------------ |
130
|
|
|
*/ |
131
|
|
|
/** |
132
|
|
|
* {@inheritdoc} |
133
|
|
|
*/ |
134
|
6 |
|
public function forget($key) |
135
|
|
|
{ |
136
|
6 |
|
parent::forget($key); |
137
|
|
|
|
138
|
|
|
// because the database store cannot store empty arrays, remove empty |
139
|
|
|
// arrays to keep data consistent before and after saving |
140
|
6 |
|
$segments = explode('.', $key); |
141
|
6 |
|
array_pop($segments); |
142
|
|
|
|
143
|
6 |
|
while ($segments) { |
|
|
|
|
144
|
3 |
|
$segment = implode('.', $segments); |
145
|
|
|
|
146
|
|
|
// non-empty array - exit out of the loop |
147
|
3 |
|
if ($this->get($segment)) { |
148
|
3 |
|
break; |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
// remove the empty array and move on to the next segment |
152
|
3 |
|
$this->forget($segment); |
153
|
3 |
|
array_pop($segments); |
154
|
3 |
|
} |
155
|
6 |
|
} |
156
|
|
|
|
157
|
|
|
/* ------------------------------------------------------------------------------------------------ |
158
|
|
|
| Other Functions |
159
|
|
|
| ------------------------------------------------------------------------------------------------ |
160
|
|
|
*/ |
161
|
|
|
/** |
162
|
|
|
* {@inheritdoc} |
163
|
|
|
*/ |
164
|
21 |
|
protected function read() |
165
|
|
|
{ |
166
|
21 |
|
return $this->parseReadData($this->newQuery()->get()); |
167
|
|
|
} |
168
|
|
|
|
169
|
|
|
/** |
170
|
|
|
* {@inheritdoc} |
171
|
|
|
*/ |
172
|
15 |
|
protected function write(array $data) |
173
|
|
|
{ |
174
|
15 |
|
$keys = $this->newQuery()->lists('key'); |
175
|
15 |
|
$insertData = array_dot($data); |
176
|
15 |
|
$updateData = []; |
177
|
15 |
|
$deleteKeys = []; |
178
|
|
|
|
179
|
15 |
|
foreach ($keys as $key) { |
180
|
9 |
|
if (isset($insertData[$key])) { |
181
|
6 |
|
$updateData[$key] = $insertData[$key]; |
182
|
6 |
|
} |
183
|
|
|
else { |
184
|
9 |
|
$deleteKeys[] = $key; |
185
|
|
|
} |
186
|
|
|
|
187
|
9 |
|
unset($insertData[$key]); |
188
|
15 |
|
} |
189
|
|
|
|
190
|
15 |
|
foreach ($updateData as $key => $value) { |
191
|
6 |
|
$this->newQuery() |
192
|
6 |
|
->where('key', '=', $key) |
193
|
6 |
|
->update(array('value' => $value)); |
194
|
15 |
|
} |
195
|
|
|
|
196
|
15 |
|
if ($insertData) { |
|
|
|
|
197
|
15 |
|
$this->newQuery(true) |
198
|
15 |
|
->insert($this->prepareInsertData($insertData)); |
199
|
15 |
|
} |
200
|
|
|
|
201
|
15 |
|
if ($deleteKeys) { |
|
|
|
|
202
|
9 |
|
$this->newQuery() |
203
|
9 |
|
->whereIn('key', $deleteKeys) |
204
|
9 |
|
->delete(); |
205
|
9 |
|
} |
206
|
15 |
|
} |
207
|
|
|
|
208
|
|
|
/** |
209
|
|
|
* Parse data coming from the database. |
210
|
|
|
* |
211
|
|
|
* @param array $data |
212
|
|
|
* |
213
|
|
|
* @return array |
214
|
|
|
*/ |
215
|
21 |
|
protected function parseReadData($data) |
216
|
|
|
{ |
217
|
21 |
|
$results = []; |
218
|
|
|
|
219
|
21 |
|
foreach ($data as $row) { |
220
|
15 |
|
if (is_array($row)) { |
221
|
|
|
$key = $row['key']; |
222
|
|
|
$value = $row['value']; |
223
|
|
|
} |
224
|
15 |
|
elseif (is_object($row)) { |
225
|
15 |
|
$key = $row->key; |
226
|
15 |
|
$value = $row->value; |
227
|
15 |
|
} |
228
|
|
|
else { |
229
|
|
|
throw new \UnexpectedValueException( |
230
|
|
|
'Expected array or object, got ' . gettype($row) |
231
|
|
|
); |
232
|
|
|
} |
233
|
|
|
|
234
|
15 |
|
Arr::set($results, $key, $value); |
235
|
21 |
|
} |
236
|
|
|
|
237
|
21 |
|
return $results; |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
/** |
241
|
|
|
* Transforms settings data into an array ready to be insterted into the |
242
|
|
|
* database. Call array_dot on a multidimensional array before passing it |
243
|
|
|
* into this method! |
244
|
|
|
* |
245
|
|
|
* @param array $data Call array_dot on a multidimensional array before passing it into this method! |
246
|
|
|
* |
247
|
|
|
* @return array |
248
|
|
|
*/ |
249
|
15 |
|
protected function prepareInsertData(array $data) |
250
|
|
|
{ |
251
|
15 |
|
$dbData = []; |
252
|
|
|
|
253
|
15 |
|
foreach ($data as $key => $value) { |
254
|
15 |
|
$dbData[] = empty($this->extraColumns) |
255
|
15 |
|
? compact('key', 'value') |
256
|
15 |
|
: array_merge($this->extraColumns, compact('key', 'value')); |
257
|
15 |
|
} |
258
|
|
|
|
259
|
15 |
|
return $dbData; |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
/** |
263
|
|
|
* Create a new query builder instance. |
264
|
|
|
* |
265
|
|
|
* @param $insert boolean Whether the query is an insert or not. |
266
|
|
|
* |
267
|
|
|
* @return \Illuminate\Database\Query\Builder |
268
|
|
|
*/ |
269
|
21 |
|
protected function newQuery($insert = false) |
270
|
|
|
{ |
271
|
21 |
|
$query = $this->connection->table($this->table); |
272
|
|
|
|
273
|
21 |
|
if ( ! $insert) { |
274
|
21 |
|
foreach ($this->extraColumns as $key => $value) { |
275
|
|
|
$query->where($key, '=', $value); |
276
|
21 |
|
} |
277
|
21 |
|
} |
278
|
|
|
|
279
|
21 |
|
if ($this->queryConstraint !== null) { |
280
|
|
|
/** @var Closure $callback */ |
281
|
|
|
$callback = $this->queryConstraint; |
282
|
|
|
$callback($query, $insert); |
283
|
|
|
} |
284
|
|
|
|
285
|
21 |
|
return $query; |
286
|
|
|
} |
287
|
|
|
} |
288
|
|
|
|
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.