Completed
Push — master ( a40fc9...4580d0 )
by ARCANEDEV
03:02
created

DatabaseStore::setConstraint()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 8
rs 9.4286
c 1
b 0
f 0
ccs 0
cts 5
cp 0
cc 1
eloc 5
nc 1
nop 1
crap 2
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) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $segments 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...
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) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $insertData 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...
197 15
            $this->newQuery(true)
198 15
                ->insert($this->prepareInsertData($insertData));
199 15
        }
200
201 15
        if ($deleteKeys) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $deleteKeys 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...
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