Passed
Push — master ( 5f920d...1f0263 )
by Andreas
04:59
created

Setting::allSettings()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 2
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Ottosmops\Settings;
4
5
use Illuminate\Database\Eloquent\Model;
6
use Illuminate\Support\Facades\Cache;
7
use Illuminate\Support\Facades\Validator;
8
use Illuminate\Validation\ValidationException;
9
10
use Ottosmops\Settings\Exceptions\NoKeyIsFound;
11
12
class Setting extends Model
13
{
14
    protected $keyType = 'string';
15
16
    protected $guarded = [];
17
18
    public $timestamps = false;
19
20
    public $incrementing = false;
21
22
    protected $primaryKey = 'key';
23
24
    protected $table;
25
26
    protected $casts = [
27
        'editable' => 'boolean',
28
        'value' => 'array',
29
        'default' => 'array'
30
    ];
31
32 36
    protected function asJson($value)
33
    {
34 36
        if (is_string($value)) {
35 18
            $value = str_replace('\\', 'ç€π', $value);
36
        }
37 36
        return json_encode($value, JSON_UNESCAPED_UNICODE);
38
    }
39
40 57
    public function __construct(array $attributes = [])
41
    {
42 57
        $this->table = config('settings.table', 'settings');
43 57
        parent::__construct($attributes);
44 57
    }
45
46
    /**
47
     * Get the editable status
48
     *
49
     * @param  string  $value
50
     * @return bool
51
     */
52 57
    public function getEditableAttribute($value)
53
    {
54 57
        if (!isset($value)) {
55 54
            return true;
56
        }
57
58 6
        return (bool) $value;
59
    }
60
61
    /**
62
     * Check if setting is editable
63
     *
64
     * @param  string  $value
65
     * @return bool
66
     */
67 3
    public static function isEditable(string $key) : bool
68
    {
69 3
        return Setting::where('key', $key)->first()->editable;
70
    }
71
72
    /**
73
     * Cast a value to the expected type ($this->type)
74
     * Possible types: array, integer, boolean, string
75
     *
76
     * @param  mixed $value
77
     * @return mixed
78
     */
79 51
    public function getValueAttribute($value)
80
    {
81 51
        if ($value === null) {
82 39
            return null;
83
        }
84
85 33
        switch ($this->type) {
0 ignored issues
show
Bug introduced by
The property type does not seem to exist on Ottosmops\Settings\Setting. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
86 33
            case 'arr':
87 33
            case 'array':
88 6
                return json_decode($value, true);
89 30
            case 'int':
90 30
            case 'integer':
91 6
                return intval($value);
92 27
            case 'bool':
93 24
            case 'boolean':
94 12
                if ($value === "false") {
95 6
                    return false;
96
                }
97 12
                return boolval($value);
98 15
            case 'string':
99 15
                $value = str_replace('ç€π', '\\', $value);
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment if this fall-through is intended.
Loading history...
100
            default:
101 15
                return trim($value, '"');
102
        }
103
    }
104
105
    /**
106
     * Get a type casted setting value
107
     *
108
     * @param  string $key
109
     * @param  mixed  $default is returned if value is empty (except boolean false)
110
     * @return mixed
111
     */
112 36
    public static function getValue(string $key, $default = null)
113
    {
114 36
        if (!self::has($key)) {
115 9
            throw new NoKeyIsFound();
116
        }
117
118 27
        if (self::hasValue($key)) {
119 27
            return \Ottosmops\Settings\Setting::allSettings()[$key]['value'];
120
        }
121
122 3
        return $default;
123
    }
124
125 3
    public static function getValueAsString(string $key, $default = null)
126
    {
127 3
        if (!self::has($key)) {
128
            throw new NoKeyIsFound();
129
        }
130
131 3
        if (self::hasValue($key)) {
132 3
            $value = \Ottosmops\Settings\Setting::allSettings()[$key]['value'];
133
134 3
            $type = gettype($value);
135
136 3
            switch ($type) {
137 3
                case 'array':
138 3
                case 'object':
139 3
                    return json_encode($value, JSON_UNESCAPED_UNICODE);
140 3
                case 'integer':
141 3
                    return (string) $value;
142 3
                case 'boolean':
143 3
                    if ($value === false) {
144
                        return "false";
145
                    }
146 3
                    return "true";
147
                case 'string':
148
                    $value = str_replace('ç€π', '\\', $value);
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment if this fall-through is intended.
Loading history...
149
                default:
150
                    return (string) trim($value, '"');
151
            }
152
        }
153
154
        return $default;
155
    }
156
157
    /**
158
    * Check if setting exists
159
    *
160
    * @param $key
161
    * @return bool
162
    */
163 51
    public static function has(string $key) : bool
164
    {
165 51
        return (boolean) isset(self::allSettings()[$key]);
166
    }
167
168
    /**
169
     * If a setting has a value (also boolean false, integer 0 and an empty string are values)
170
     *
171
     * @param  string  $key
172
     * @return boolean
173
     */
174 33
    public static function hasValue(string $key) : bool
175
    {
176 33
        if (self::has($key) && isset(Setting::allSettings()[$key]['value'])) {
177 33
            $value = Setting::allSettings()[$key]['value'];
178 33
            return !empty($value) || $value === false || $value === 0 || $value === '';
179
        }
180
181 6
        return false;
182
    }
183
184
    /**
185
     * Set a new value
186
     * @param string  $key
187
     * @param mixed  $value    // string, integer, boolean or array
188
     * @param boolean
189
     */
190 21
    public static function setValue(string $key, $value = null, $validate = true)
191
    {
192 21
        if (!self::has($key)) {
193
            throw new NoKeyIsFound();
194
        }
195
196 21
        $setting = self::find($key);
197
198 21
        if ($validate && !$setting->validateNewValue($value)) {
199 6
            throw new ValidationException(null);
200
        }
201
202 15
        $setting->value = $value;
0 ignored issues
show
Bug introduced by
The property value does not seem to exist on Ottosmops\Settings\Setting. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
203
204 15
        return $setting->save();
205
    }
206
207
208
    /**
209
     * Remove a setting
210
     *
211
     * @param $key
212
     * @return bool
213
     */
214 6
    public static function remove(string $key)
215
    {
216 6
        if (self::has($key)) {
217 3
            return self::find($key)->delete();
218
        }
219
220 3
        throw new NoKeyIsFound();
221
    }
222
223
    /**
224
     * Get all the settings
225
     *
226
     * @return mixed
227
     */
228 51
    public static function allSettings() : array
229
    {
230
        return Cache::rememberForever('settings.all', function () {
231 51
            return $settings = self::all()->keyBy('key')->toArray();
0 ignored issues
show
Unused Code introduced by
The assignment to $settings is dead and can be removed.
Loading history...
232 51
        });
233
    }
234
235
    /**
236
     * Helper function: Validate a value against its type and its rules.
237
     * @param  mixed $value
238
     * @return bool
239
     */
240 21
    public function validateNewValue($value) : bool
241
    {
242 21
        $validator = Validator::make([$this->key => $value], self::getValidationRules());
0 ignored issues
show
Bug introduced by
The property key does not seem to exist on Ottosmops\Settings\Setting. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
243 21
        return !$validator->fails();
244
    }
245
246
    /**
247
     * Get the validation rules for setting fields
248
     *
249
     * @return array
250
     */
251 30
    public static function getValidationRules() : array
252
    {
253 30
        if ('mysql' === \DB::connection()->getPDO()->getAttribute(\PDO::ATTR_DRIVER_NAME)) {
254
            return Cache::rememberForever('settings.rules', function () {
255
                return Setting::select(\DB::raw('concat_ws("|", rules, type) as rules, `key`'))
256
                            ->pluck('rules', 'key')
257
                            ->toArray();
258
            });
259
        }
260
261
262
        return Cache::rememberForever('settings.rules', function () {
263 30
            return Setting::select(\DB::raw("printf('%s|%s', rules, type) as rules, `key`"))
264 30
                            ->pluck('rules', 'key')
265 30
                            ->toArray();
266 30
        });
267
    }
268
269
    /**
270
     * Flush the cache
271
     */
272 57
    public static function flushCache()
273
    {
274 57
        Cache::forget('settings.all');
275 57
        Cache::forget('settings.rules');
276 57
    }
277
278
    /**
279
     * The "booting" method of the model.
280
     *
281
     * @return void
282
     */
283 57
    protected static function boot()
284
    {
285 57
        parent::boot();
286
287
        static::deleted(function () {
288 3
            self::flushCache();
289 57
        });
290
        static::updated(function () {
291 21
            self::flushCache();
292 57
        });
293
        static::created(function () {
294 57
            self::flushCache();
295 57
        });
296 57
    }
297
}
298