Passed
Push — master ( 04f11b...fe97cf )
by Andreas
02:53
created

Setting   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 244
Duplicated Lines 0 %

Test Coverage

Coverage 93.51%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 76
c 4
b 0
f 0
dl 0
loc 244
ccs 72
cts 77
cp 0.9351
rs 9.52
wmc 36

14 Methods

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