Completed
Pull Request — master (#1)
by ARCANEDEV
02:03
created

DatabaseStore   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 265
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 86.05%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 27
c 4
b 0
f 0
lcom 1
cbo 3
dl 0
loc 265
ccs 74
cts 86
cp 0.8605
rs 10

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 2
A setConnection() 0 6 1
A setTable() 0 6 1
A setConstraint() 0 8 1
A setExtraColumns() 0 6 1
A forget() 0 22 3
A read() 0 11 2
A write() 0 8 1
A prepareData() 0 17 3
A updateSettings() 0 6 2
A insertSettings() 0 15 4
A deleteSettings() 0 8 2
A model() 0 18 4
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\Models\Setting;
6
use Arcanedev\Settings\Utilities\Arr;
7
use Closure;
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
    /** @var  \Arcanedev\Settings\Models\Setting */
22
    protected $model;
23
24
    /**
25
     * Any query constraints that should be applied.
26
     *
27
     * @var Closure|null
28
     */
29
    protected $queryConstraint;
30
31
    /**
32
     * Any extra columns that should be added to the rows.
33
     *
34
     * @var array
35
     */
36
    protected $extraColumns = [];
37
38
    /* ------------------------------------------------------------------------------------------------
39
     |  Constructor
40
     | ------------------------------------------------------------------------------------------------
41
     */
42
    /**
43
     * Make the Database store instance.
44
     *
45
     * @param  string  $connection
46
     * @param  string  $table
47
     */
48 24
    public function __construct($connection, $table = null)
49
    {
50 24
        $this->model = new Setting;
51 24
        $this->setConnection($connection);
52 24
        $this->setTable($table ?: 'settings');
53 24
    }
54
55
    /* ------------------------------------------------------------------------------------------------
56
     |  Getters & Setters
57
     | ------------------------------------------------------------------------------------------------
58
     */
59
    /**
60
     * Set the database connection.
61
     *
62
     * @param  string  $connection
63
     *
64
     * @return self
65
     */
66 24
    public function setConnection($connection)
67
    {
68 24
        $this->model->setConnection($connection);
69
70 24
        return $this;
71
    }
72
73
    /**
74
     * Set the table to query from.
75
     *
76
     * @param  string  $table
77
     *
78
     * @return self
79
     */
80 24
    public function setTable($table)
81
    {
82 24
        $this->model->setTable($table);
83
84 24
        return $this;
85
    }
86
87
    /**
88
     * Set the query constraint.
89
     *
90
     * @param  \Closure  $callback
91
     *
92
     * @return self
93
     */
94
    public function setConstraint(Closure $callback)
95
    {
96
        $this->data            = [];
97
        $this->loaded          = false;
98
        $this->queryConstraint = $callback;
99
100
        return $this;
101
    }
102
103
    /**
104
     * Set extra columns to be added to the rows.
105
     *
106
     * @param  array  $columns
107
     *
108
     * @return self
109
     */
110
    public function setExtraColumns(array $columns)
111
    {
112
        $this->extraColumns = $columns;
113
114
        return $this;
115
    }
116
117
    /* ------------------------------------------------------------------------------------------------
118
     |  Main Functions
119
     | ------------------------------------------------------------------------------------------------
120
     */
121
    /**
122
     * {@inheritdoc}
123
     */
124 6
    public function forget($key)
125
    {
126 6
        parent::forget($key);
127
128
        // because the database store cannot store empty arrays, remove empty
129
        // arrays to keep data consistent before and after saving
130 6
        $segments = explode('.', $key);
131 6
        array_pop($segments);
132
133 6
        while ( ! empty($segments)) {
134 3
            $segment = implode('.', $segments);
135
136
            // non-empty array - exit out of the loop
137 3
            if ($this->get($segment)) {
138 3
                break;
139
            }
140
141
            // remove the empty array and move on to the next segment
142 3
            $this->forget($segment);
143 3
            array_pop($segments);
144 3
        }
145 6
    }
146
147
    /* ------------------------------------------------------------------------------------------------
148
     |  Other Functions
149
     | ------------------------------------------------------------------------------------------------
150
     */
151
    /**
152
     * {@inheritdoc}
153
     */
154 21
    protected function read()
155
    {
156 21
        $results  = [];
157
158 21
        foreach ($this->model->all() as $setting) {
159
            /** @var Setting $setting */
160 15
            Arr::set($results, $setting->key, $setting->value);
161 21
        }
162
163 21
        return $results;
164
    }
165
166
    /**
167
     * {@inheritdoc}
168
     */
169 15
    protected function write(array $data)
170
    {
171 15
        list($inserts, $updates, $deletes) = $this->prepareData($data);
172
173 15
        $this->updateSettings($updates);
174 15
        $this->insertSettings($inserts);
175 15
        $this->deleteSettings($deletes);
176 15
    }
177
178
    /* ------------------------------------------------------------------------------------------------
179
     |  CRUD Functions
180
     | ------------------------------------------------------------------------------------------------
181
     */
182
    /**
183
     * Prepare settings data.
184
     *
185
     * @param  array  $data
186
     *
187
     * @return array
188
     */
189 15
    private function prepareData(array $data)
190
    {
191 15
        $inserts = array_dot($data);
192 15
        $updates = [];
193 15
        $deletes = [];
194
195 15
        foreach ($this->model()->lists('key') as $key) {
0 ignored issues
show
Documentation Bug introduced by
The method lists does not exist on object<Arcanedev\Settings\Models\Setting>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
196 9
            if (isset($inserts[$key]))
197 9
                $updates[$key] = $inserts[$key];
198
            else
199 9
                $deletes[]     = $key;
200
201 9
            unset($inserts[$key]);
202 15
        }
203
204 15
        return [$inserts, $updates, $deletes];
205
    }
206
207
    /**
208
     * Update settings data.
209
     *
210
     * @param  array $updates
211
     */
212 15
    private function updateSettings($updates)
213
    {
214 15
        foreach ($updates as $key => $value) {
215 6
            $this->model()->where('key', $key)->update(compact('value'));
0 ignored issues
show
Documentation Bug introduced by
The method where does not exist on object<Arcanedev\Settings\Models\Setting>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
216 15
        }
217 15
    }
218
219
    /**
220
     * Insert settings data.
221
     *
222
     * @param  array $inserts
223
     */
224 15
    private function insertSettings(array $inserts)
225
    {
226 15
        if (empty($inserts)) {
227 9
            return;
228
        }
229
230 15
        $dbData = [];
231
232 15
        foreach ($inserts as $key => $value) {
233 15
            $data     = compact('key', 'value');
234 15
            $dbData[] = empty($this->extraColumns) ? $data : array_merge($this->extraColumns, $data);
235 15
        }
236
237 15
        $this->model(true)->insert($dbData);
0 ignored issues
show
Bug introduced by
The method insert() does not exist on Arcanedev\Settings\Models\Setting. Did you maybe mean insertAndSetId()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
238 15
    }
239
240
    /**
241
     * Delete settings data.
242
     *
243
     * @param  array  $deletes
244
     */
245 15
    private function deleteSettings(array $deletes)
246
    {
247 15
        if (empty($deletes)) {
248 15
            return;
249
        }
250
251 9
        $this->model()->whereIn('key', $deletes)->delete();
0 ignored issues
show
Documentation Bug introduced by
The method whereIn does not exist on object<Arcanedev\Settings\Models\Setting>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
252 9
    }
253
254
    /**
255
     * Create a new query builder instance.
256
     *
257
     * @param  $insert  bool  Whether the query is an insert or not.
258
     *
259
     * @return \Illuminate\Database\Query\Builder
260
     */
261 15
    private function model($insert = false)
262
    {
263 15
        $model = $this->model;
264
265 15
        if ($insert === false) {
266 15
            foreach ($this->extraColumns as $key => $value) {
267
                $model->where($key, $value);
0 ignored issues
show
Documentation Bug introduced by
The method where does not exist on object<Arcanedev\Settings\Models\Setting>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
268 15
            }
269 15
        }
270
271 15
        if ( ! is_null($this->queryConstraint)) {
272
            /** @var  Closure  $callback */
273
            $callback = $this->queryConstraint;
274
            $callback($model, $insert);
275
        }
276
277 15
        return $model;
278
    }
279
}
280