Completed
Push — master ( 18d0b0...233041 )
by ARCANEDEV
07:10
created

DatabaseStore::getChanges()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 12
nc 3
nop 1
dl 0
loc 19
ccs 12
cts 12
cp 1
crap 3
rs 9.4285
c 0
b 0
f 0
1
<?php namespace Arcanedev\LaravelSettings\Stores;
2
3
use Arcanedev\LaravelSettings\Models\Setting as SettingModel;
4
use Arcanedev\LaravelSettings\Utilities\Arr;
5
use Closure;
6
7
/**
8
 * Class     DatabaseStore
9
 *
10
 * @package  Arcanedev\LaravelSettings\Stores
11
 * @author   ARCANEDEV <[email protected]>
12
 */
13
class DatabaseStore extends AbstractStore
14
{
15
    /* -----------------------------------------------------------------
16
     |  Properties
17
     | -----------------------------------------------------------------
18
     */
19
20
    /**
21
     * The eloquent model.
22
     *
23
     * @var \Illuminate\Database\Eloquent\Model
24
     */
25
    protected $model;
26
27
    /**
28
     * The key column name to query from.
29
     *
30
     * @var string
31
     */
32
    protected $keyColumn;
33
34
    /**
35
     * The value column name to query from.
36
     *
37
     * @var string
38
     */
39
    protected $valueColumn;
40
41
    /**
42
     * Any query constraints that should be applied.
43
     *
44
     * @var \Closure|null
45
     */
46
    protected $queryConstraint;
47
48
    /**
49
     * Any extra columns that should be added to the rows.
50
     *
51
     * @var array
52
     */
53
    protected $extraColumns = [];
54
55
    /* -----------------------------------------------------------------
56
     |  Post-Constructor
57
     | -----------------------------------------------------------------
58
     */
59
60
    /**
61
     * Fire the post options to customize the store.
62
     *
63
     * @param  array  $options
64
     */
65 36
    protected function postOptions(array $options)
66
    {
67 36
        $this->model = $this->app->make(
68 36
            Arr::get($options, 'model', SettingModel::class)
69 12
        );
70 36
        $this->setConnection(Arr::get($options, 'connection', null));
71 36
        $this->setTable(Arr::get($options, 'table', 'settings'));
72 36
        $this->setKeyColumn(Arr::get($options, 'columns.key', 'key'));
73 36
        $this->setValueColumn(Arr::get($options, 'columns.value', 'value'));
74 36
    }
75
76
    /* -----------------------------------------------------------------
77
     |  Getters & Setters
78
     | -----------------------------------------------------------------
79
     */
80
81
    /**
82
     * Set the db connection to query from.
83
     *
84
     * @param  string  $name
85
     *
86
     * @return self
87
     */
88 36
    public function setConnection($name)
89
    {
90 36
        $this->model->setConnection($name);
91
92 36
        return $this;
93
    }
94
95
    /**
96
     * Set the table to query from.
97
     *
98
     * @param  string  $name
99
     *
100
     * @return self
101
     */
102 36
    public function setTable($name)
103
    {
104 36
        $this->model->setTable($name);
105
106 36
        return $this;
107
    }
108
109
    /**
110
     * Set the key column name to query from.
111
     *
112
     * @param  string  $name
113
     *
114
     * @return self
115
     */
116 36
    public function setKeyColumn($name)
117
    {
118 36
        $this->keyColumn = $name;
119
120 36
        return $this;
121
    }
122
123
    /**
124
     * Set the value column name to query from.
125
     *
126
     * @param  string  $name
127
     *
128
     * @return self
129
     */
130 36
    public function setValueColumn($name)
131
    {
132 36
        $this->valueColumn = $name;
133
134 36
        return $this;
135
    }
136
137
    /**
138
     * Set the query constraint.
139
     *
140
     * @param  \Closure  $callback
141
     *
142
     * @return self
143
     */
144 3
    public function setConstraint(Closure $callback)
145
    {
146 3
        $this->resetLoaded();
147
148 3
        $this->queryConstraint = $callback;
149
150 3
        return $this;
151
    }
152
153
    /**
154
     * Set extra columns to be added to the rows.
155
     *
156
     * @param  array  $columns
157
     *
158
     * @return self
159
     */
160 3
    public function setExtraColumns(array $columns)
161
    {
162 3
        $this->resetLoaded();
163
164 3
        $this->extraColumns = $columns;
165
166 3
        return $this;
167
    }
168
169
    /* -----------------------------------------------------------------
170
     |  Main Methods
171
     | -----------------------------------------------------------------
172
     */
173
174
    /**
175
     * Unset a key in the settings data.
176
     *
177
     * @param  string  $key
178
     *
179
     * @return self
180
     */
181 6
    public function forget($key)
182
    {
183 6
        parent::forget($key);
184
185
        // because the database store cannot store empty arrays, remove empty
186
        // arrays to keep data consistent before and after saving
187 6
        $segments = explode('.', $key);
188 6
        array_pop($segments);
189
190 6
        while ( ! empty($segments)) {
191 3
            $segment = implode('.', $segments);
192
193
            // non-empty array - exit out of the loop
194 3
            if ($this->get($segment)) break;
195
196
            // remove the empty array and move on to the next segment
197 3
            $this->forget($segment);
198 3
            array_pop($segments);
199 1
        }
200
201 6
        return $this;
202
    }
203
204
    /**
205
     * Read the data from the store.
206
     *
207
     * @return array
208
     */
209 30
    protected function read()
210
    {
211 30
        return $this->newQuery()
212 30
            ->pluck($this->valueColumn, $this->keyColumn)
213 30
            ->toArray();
214
    }
215
216
    /**
217
     * Write the data into the store.
218
     *
219
     * @param  array  $data
220
     */
221 24
    protected function write(array $data)
222
    {
223 24
        $changes = $this->getChanges($data);
224
225 24
        $this->syncUpdated($changes['updated']);
226 24
        $this->syncInserted($changes['inserted']);
227 24
        $this->syncDeleted($changes['deleted']);
228 24
    }
229
230
    /* -----------------------------------------------------------------
231
     |  Other Methods
232
     | -----------------------------------------------------------------
233
     */
234
235
    /**
236
     * Create a new query builder instance.
237
     *
238
     * @param  $insert  bool
239
     *
240
     * @return \Illuminate\Database\Query\Builder
241
     */
242 30
    protected function newQuery($insert = false)
243
    {
244 30
        $query = $this->model->newQuery();
245
246 30
        if ( ! $insert) {
247 30
            foreach ($this->extraColumns as $key => $value) {
248 3
                $query->where($key, '=', $value);
249 10
            }
250 10
        }
251
252 30
        if ($this->hasQueryConstraint()) {
253 3
            $callback = $this->queryConstraint;
254 3
            $callback($query, $insert);
255 1
        }
256
257 30
        return $query;
258
    }
259
260
    /**
261
     * Transforms settings data into an array ready to be inserted into the database.
262
     * Call array_dot on a multidimensional array before passing it into this method!
263
     *
264
     * @param  array  $data
265
     *
266
     * @return array
267
     */
268 24
    protected function prepareInsertData(array $data)
269
    {
270 24
        $dbData       = [];
271 24
        $extraColumns = $this->extraColumns ? $this->extraColumns : [];
272
273 24
        foreach ($data as $key => $value) {
274 24
            $dbData[] = array_merge($extraColumns, [
275 24
                $this->keyColumn   => $key,
276 24
                $this->valueColumn => $value,
277 8
            ]);
278 8
        }
279
280 24
        return $dbData;
281
    }
282
283
    /**
284
     * Check if the query constraint exists.
285
     *
286
     * @return bool
287
     */
288 30
    protected function hasQueryConstraint()
289
    {
290 30
        return ! is_null($this->queryConstraint) && is_callable($this->queryConstraint);
291
    }
292
293
    /**
294
     * Get the changed settings data.
295
     *
296
     * @param  array  $data
297
     *
298
     * @return array
299
     */
300 24
    private function getChanges(array $data)
301
    {
302
        $changes = [
303 24
            'inserted' => Arr::dot($data),
304 8
            'updated'  => [],
305 8
            'deleted'  => [],
306 8
        ];
307
308 24
        foreach ($this->newQuery()->pluck($this->keyColumn) as $key) {
309 9
            if (Arr::has($changes['inserted'], $key))
310 7
                $changes['updated'][$key] = $changes['inserted'][$key];
311
            else
312 9
                $changes['deleted'][] = $key;
313
314 9
            Arr::forget($changes['inserted'], $key);
315 8
        }
316
317 24
        return $changes;
318
    }
319
320
    /**
321
     * Sync the updated records.
322
     *
323
     * @param  array  $updated
324
     */
325 24
    private function syncUpdated(array $updated)
326
    {
327 24
        foreach ($updated as $key => $value) {
328 6
            $this->newQuery()
329 6
                 ->where($this->keyColumn, '=', $key)
330 6
                 ->update([$this->valueColumn => $value]);
331 8
        }
332 24
    }
333
334
    /**
335
     * Sync the inserted records.
336
     *
337
     * @param  array  $inserted
338
     */
339 24
    private function syncInserted(array $inserted)
340
    {
341 24
        if ( ! empty($inserted)) {
342 24
            $this->newQuery(true)->insert(
343 24
                $this->prepareInsertData($inserted)
344 8
            );
345 8
        }
346 24
    }
347
348
    /**
349
     * Sync the deleted records.
350
     *
351
     * @param  array  $deleted
352
     */
353 24
    private function syncDeleted(array $deleted)
354
    {
355 24
        if ( ! empty($deleted)) {
356 9
            $this->newQuery()->whereIn($this->keyColumn, $deleted)->delete();
357 3
        }
358 24
    }
359
}
360