Passed
Push — master ( 29b491...5f920d )
by Andreas
03:15
created

Setting::hasValue()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 4
c 1
b 0
f 0
nc 5
nop 1
dl 0
loc 8
ccs 5
cts 5
cp 1
crap 6
rs 9.2222
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 33
    protected function asJson($value)
33
    {
34 33
        return json_encode($value, JSON_UNESCAPED_UNICODE);
35
    }
36
37 54
    public function __construct(array $attributes = [])
38
    {
39 54
        $this->table = config('settings.table', 'settings');
40 54
        parent::__construct($attributes);
41 54
    }
42
43
    /**
44
     * Get the editable status
45
     *
46
     * @param  string  $value
47
     * @return bool
48
     */
49 54
    public function getEditableAttribute($value)
50
    {
51 54
        if (!isset($value)) {
52 51
            return true;
53
        }
54
55 6
        return (bool) $value;
56
    }
57
58
    /**
59
     * Check if setting is editable
60
     *
61
     * @param  string  $value
62
     * @return bool
63
     */
64 3
    public static function isEditable(string $key) : bool
65
    {
66 3
        return Setting::where('key', $key)->first()->editable;
67
    }
68
69
    /**
70
     * Cast a value to the expected type ($this->type)
71
     * Possible types: array, integer, boolean, string
72
     *
73
     * @param  mixed $value
74
     * @return mixed
75
     */
76 48
    public function getValueAttribute($value)
77
    {
78 48
        if ($value === null) {
79 36
            return null;
80
        }
81
82 30
        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...
83 30
            case 'arr':
84 30
            case 'array':
85 6
                return json_decode($value, true);
86 27
            case 'int':
87 27
            case 'integer':
88 6
                return intval($value);
89 24
            case 'bool':
90 21
            case 'boolean':
91 12
                if ($value === "false") {
92 6
                    return false;
93
                }
94 12
                return boolval($value);
95
            default:
96 12
                return trim($value, '"');
97
        }
98
    }
99
100
    /**
101
     * Get a type casted setting value
102
     *
103
     * @param  string $key
104
     * @param  mixed  $default is returned if value is empty (except boolean false)
105
     * @return mixed
106
     */
107 33
    public static function getValue(string $key, $default = null)
108
    {
109 33
        if (!self::has($key)) {
110 9
            throw new NoKeyIsFound();
111
        }
112
113 24
        if (self::hasValue($key)) {
114 24
            return \Ottosmops\Settings\Setting::allSettings()[$key]['value'];
115
        }
116
117 3
        return $default;
118
    }
119
120 3
    public static function getValueAsString(string $key, $default = null)
121
    {
122 3
        if (!self::has($key)) {
123
            throw new NoKeyIsFound();
124
        }
125
126 3
        if (self::hasValue($key)) {
127 3
            $value = \Ottosmops\Settings\Setting::allSettings()[$key]['value'];
128
129 3
            $type = gettype($value);
130
131 3
            switch ($type) {
132 3
                case 'array':
133 3
                case 'object':
134 3
                    return json_encode($value, JSON_UNESCAPED_UNICODE);
135 3
                case 'integer':
136 3
                    return (string) $value;
137 3
                case 'boolean':
138 3
                    if ($value === false) {
139
                        return "false";
140
                    }
141 3
                    return "true";
142
                default:
143
                    return (string) trim($value, '"');
144
            }
145
        }
146
147
        return $default;
148
    }
149
150
    /**
151
    * Check if setting exists
152
    *
153
    * @param $key
154
    * @return bool
155
    */
156 48
    public static function has(string $key) : bool
157
    {
158 48
        return (boolean) isset(self::allSettings()[$key]);
159
    }
160
161
    /**
162
     * If a setting has a value (also boolean false, integer 0 and an empty string are values)
163
     *
164
     * @param  string  $key
165
     * @return boolean
166
     */
167 30
    public static function hasValue(string $key) : bool
168
    {
169 30
        if (self::has($key) && isset(Setting::allSettings()[$key]['value'])) {
170 30
            $value = Setting::allSettings()[$key]['value'];
171 30
            return !empty($value) || $value === false || $value === 0 || $value === '';
172
        }
173
174 6
        return false;
175
    }
176
177
    /**
178
     * Set a new value
179
     * @param string  $key
180
     * @param mixed  $value    // string, integer, boolean or array
181
     * @param boolean
182
     */
183 18
    public static function setValue(string $key, $value = null, $validate = true)
184
    {
185 18
        if (!self::has($key)) {
186
            throw new NoKeyIsFound();
187
        }
188
189 18
        $setting = self::find($key);
190
191 18
        if ($validate && !$setting->validateNewValue($value)) {
192 6
            throw new ValidationException(null);
193
        }
194
195 12
        $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...
196
197 12
        return $setting->save();
198
    }
199
200
201
    /**
202
     * Remove a setting
203
     *
204
     * @param $key
205
     * @return bool
206
     */
207 6
    public static function remove(string $key)
208
    {
209 6
        if (self::has($key)) {
210 3
            return self::find($key)->delete();
211
        }
212
213 3
        throw new NoKeyIsFound();
214
    }
215
216
    /**
217
     * Get all the settings
218
     *
219
     * @return mixed
220
     */
221 48
    public static function allSettings() : array
222
    {
223
        return Cache::rememberForever('settings.all', function () {
224 48
            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...
225 48
        });
226
    }
227
228
    /**
229
     * Helper function: Validate a value against its type and its rules.
230
     * @param  mixed $value
231
     * @return bool
232
     */
233 18
    public function validateNewValue($value) : bool
234
    {
235 18
        $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...
236 18
        return !$validator->fails();
237
    }
238
239
    /**
240
     * Get the validation rules for setting fields
241
     *
242
     * @return array
243
     */
244 27
    public static function getValidationRules() : array
245
    {
246 27
        if ('mysql' === \DB::connection()->getPDO()->getAttribute(\PDO::ATTR_DRIVER_NAME)) {
247
            return Cache::rememberForever('settings.rules', function () {
248
                return Setting::select(\DB::raw('concat_ws("|", rules, type) as rules, `key`'))
249
                            ->pluck('rules', 'key')
250
                            ->toArray();
251
            });
252
        }
253
254
255
        return Cache::rememberForever('settings.rules', function () {
256 27
            return Setting::select(\DB::raw("printf('%s|%s', rules, type) as rules, `key`"))
257 27
                            ->pluck('rules', 'key')
258 27
                            ->toArray();
259 27
        });
260
    }
261
262
    /**
263
     * Flush the cache
264
     */
265 54
    public static function flushCache()
266
    {
267 54
        Cache::forget('settings.all');
268 54
        Cache::forget('settings.rules');
269 54
    }
270
271
    /**
272
     * The "booting" method of the model.
273
     *
274
     * @return void
275
     */
276 54
    protected static function boot()
277
    {
278 54
        parent::boot();
279
280
        static::deleted(function () {
281 3
            self::flushCache();
282 54
        });
283
        static::updated(function () {
284 18
            self::flushCache();
285 54
        });
286
        static::created(function () {
287 54
            self::flushCache();
288 54
        });
289 54
    }
290
}
291