Passed
Push — master ( 7708b9...2558e3 )
by Andreas
03:37
created

Setting   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 247
Duplicated Lines 0 %

Test Coverage

Coverage 93.59%

Importance

Changes 5
Bugs 0 Features 0
Metric Value
wmc 36
eloc 78
c 5
b 0
f 0
dl 0
loc 247
ccs 73
cts 78
cp 0.9359
rs 9.52

14 Methods

Rating   Name   Duplication   Size   Complexity  
A isEditable() 0 3 1
A setValue() 0 15 4
A __construct() 0 4 1
A allSettings() 0 10 2
A getValue() 0 11 3
A remove() 0 7 2
A hasValue() 0 8 6
A has() 0 3 1
A getEditableAttribute() 0 7 2
B getValueAttribute() 0 21 9
A flushCache() 0 4 1
A validateNewValue() 0 4 1
A getValidationRules() 0 15 2
A boot() 0 12 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 51
    public function __construct(array $attributes = [])
33
    {
34 51
        $this->table = config('settings.table', 'settings');
35 51
        parent::__construct($attributes);
36 51
    }
37
38
    /**
39
     * Get the editable status
40
     *
41
     * @param  string  $value
42
     * @return bool
43
     */
44 51
    public function getEditableAttribute($value)
45
    {
46 51
        if (!isset($value)) {
47 48
            return true;
48
        }
49
50 6
        return (bool) $value;
51
    }
52
53
    /**
54
     * Check if setting is editable
55
     *
56
     * @param  string  $value
57
     * @return bool
58
     */
59 3
    public static function isEditable(string $key) : bool
60
    {
61 3
        return Setting::where('key', $key)->first()->editable;
62
    }
63
64
    /**
65
     * Cast a value to the expected type ($this->type)
66
     * Possible types: array, integer, boolean, string
67
     *
68
     * @param  mixed $value
69
     * @return mixed
70
     */
71 45
    public function getValueAttribute($value)
72
    {
73 45
        if ($value === null) {
74 33
            return null;
75
        }
76
77 27
        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...
78 27
            case 'arr':
79 27
            case 'array':
80 3
                return json_decode($value, true);
81 24
            case 'int':
82 24
            case 'integer':
83 3
                return intval($value);
84 21
            case 'bool':
85 21
            case 'boolean':
86 9
                if ($value === "false") {
87 6
                    return false;
88
                }
89 9
                return boolval($value);
90
            default:
91 12
                return trim($value, '"');
92
        }
93
    }
94
95
    /**
96
     * Get a type casted setting value
97
     *
98
     * @param  string $key
99
     * @param  mixed  $default is returned if value is empty (except boolean false)
100
     * @return mixed
101
     */
102 33
    public static function getValue(string $key, $default = null)
103
    {
104 33
        if (!self::has($key)) {
105 9
            throw new NoKeyIsFound();
106
        }
107
108 24
        if (self::hasValue($key)) {
109 24
            return \Ottosmops\Settings\Setting::allSettings()[$key]['value'];
110
        }
111
112 3
        return $default;
113
    }
114
115
    /**
116
    * Check if setting exists
117
    *
118
    * @param $key
119
    * @return bool
120
    */
121 45
    public static function has(string $key) : bool
122
    {
123 45
        return (boolean) isset(self::allSettings()[$key]);
124
    }
125
126
    /**
127
     * If a setting has a value (also boolean false, integer 0 and an empty string are values)
128
     *
129
     * @param  string  $key
130
     * @return boolean
131
     */
132 27
    public static function hasValue(string $key) : bool
133
    {
134 27
        if (self::has($key) && isset(Setting::allSettings()[$key]['value'])) {
135 27
            $value = Setting::allSettings()[$key]['value'];
136 27
            return !empty($value) || $value === false || $value === 0 || $value === '';
137
        }
138
139 6
        return false;
140
    }
141
142
    /**
143
     * Set a new value
144
     * @param string  $key
145
     * @param mixed  $value    // string, integer, boolean or array
146
     * @param boolean
147
     */
148 15
    public static function setValue(string $key, $value = null, $validate = true)
149
    {
150 15
        if (!self::has($key)) {
151
            throw new NoKeyIsFound();
152
        }
153
154 15
        $setting = self::find($key);
155
156 15
        if ($validate && !$setting->validateNewValue($value)) {
157 6
            throw new ValidationException(null);
158
        }
159
160 9
        $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...
161
162 9
        return $setting->save();
163
    }
164
165
166
    /**
167
     * Remove a setting
168
     *
169
     * @param $key
170
     * @return bool
171
     */
172 6
    public static function remove(string $key)
173
    {
174 6
        if (self::has($key)) {
175 3
            return self::find($key)->delete();
176
        }
177
178 3
        throw new NoKeyIsFound();
179
    }
180
181
    /**
182
     * Get all the settings
183
     *
184
     * @return mixed
185
     */
186 45
    public static function allSettings() : array
187
    {
188
        return Cache::rememberForever('settings.all', function () {
189 45
            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...
190
191
            foreach ($settings as $setting) {
0 ignored issues
show
Unused Code introduced by
ForeachNode is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
192
                $array[$setting->key] = $setting->value;
193
            }
194
195
            return $array;
196 45
        });
197
    }
198
199
    /**
200
     * Helper function: Validate a value against its type and its rules.
201
     * @param  mixed $value
202
     * @return bool
203
     */
204 15
    public function validateNewValue($value) : bool
205
    {
206 15
        $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...
207 15
        return !$validator->fails();
208
    }
209
210
    /**
211
     * Get the validation rules for setting fields
212
     *
213
     * @return array
214
     */
215 24
    public static function getValidationRules() : array
216
    {
217 24
        if ('mysql' === \DB::connection()->getPDO()->getAttribute(\PDO::ATTR_DRIVER_NAME)) {
218
            return Cache::rememberForever('settings.rules', function () {
219
                return Setting::select(\DB::raw('concat_ws("|", rules, type) as rules, `key`'))
220
                            ->pluck('rules', 'key')
221
                            ->toArray();
222
            });
223
        }
224
225
226
        return Cache::rememberForever('settings.rules', function () {
227 24
            return Setting::select(\DB::raw("printf('%s|%s', rules, type) as rules, `key`"))
228 24
                            ->pluck('rules', 'key')
229 24
                            ->toArray();
230 24
        });
231
    }
232
233
    /**
234
     * Flush the cache
235
     */
236 51
    public static function flushCache()
237
    {
238 51
        Cache::forget('settings.all');
239 51
        Cache::forget('settings.rules');
240 51
    }
241
242
    /**
243
     * The "booting" method of the model.
244
     *
245
     * @return void
246
     */
247 51
    protected static function boot()
248
    {
249 51
        parent::boot();
250
251
        static::deleted(function () {
252 3
            self::flushCache();
253 51
        });
254
        static::updated(function () {
255 15
            self::flushCache();
256 51
        });
257
        static::created(function () {
258 51
            self::flushCache();
259 51
        });
260 51
    }
261
}
262