Passed
Push — master ( 71ffc2...410338 )
by Andreas
04:46 queued 13s
created

Setting::getValueAsStringAttribute()   B

Complexity

Conditions 9
Paths 8

Size

Total Lines 22
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 9.4453

Importance

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