Passed
Push — master ( 17ced4...e22d77 )
by Andreas
03:26
created

Setting::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
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
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
80 18
            case 'int':
81 18
            case 'integer':
82 3
                return intval($value);
83
                break;
84 15
            case 'bool':
85 15
            case 'boolean':
86 6
                if ($value === "false") {
87 6
                    return false;
88
                }
89 6
                return boolval($value);
90
                break;
91
            default:
92 9
                return trim($value, '"');
93
        }
94
    }
95
96
    /**
97
     * Get a type casted setting value
98
     *
99
     * @param  string $key
100
     * @param  mixed  $default is returned if value is empty (except boolean false)
101
     * @return mixed
102
     */
103 27
    public static function getValue(string $key, $default = null)
104
    {
105 27
        if (!self::has($key)) {
106 9
            throw new NoKeyIsFound();
107
        }
108
109 18
        if (self::hasValue($key)) {
110 18
            return \Ottosmops\Settings\Setting::allSettings()[$key]['value'];
111
        }
112
113 3
        return $default;
114
    }
115
116
    /**
117
    * Check if setting exists
118
    *
119
    * @param $key
120
    * @return bool
121
    */
122 39
    public static function has(string $key) : bool
123
    {
124 39
        return (boolean) isset(self::allSettings()[$key]);
125
    }
126
127
    /**
128
     * If a setting has a value (also boolean false, integer 0 and an empty string are values)
129
     *
130
     * @param  string  $key
131
     * @return boolean
132
     */
133 21
    public static function hasValue(string $key) : bool
134
    {
135 21
        if (self::has($key) && isset(Setting::allSettings()[$key]['value'])) {
136 21
            $value = Setting::allSettings()[$key]['value'];
137 21
            return !empty($value) || $value === false || $value === 0 || $value === '';
138
        }
139
140 6
        return false;
141
    }
142
143
    /**
144
     * Set a new value
145
     * @param string  $key
146
     * @param mixed  $value    // string, integer, boolean or array
147
     * @param boolean
148
     */
149 9
    public static function setValue(string $key, $value = null, $validate = true)
150
    {
151 9
        if (!self::has($key)) {
152
            throw new NoKeyIsFound();
153
        }
154
155 9
        $setting = self::find($key);
156
157 9
        if ($validate && !$setting->validateNewValue($value)) {
158 6
            throw new ValidationException(null);
159
        }
160
161 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...
162
163 3
        return $setting->save();
164
    }
165
166
167
    /**
168
     * Remove a setting
169
     *
170
     * @param $key
171
     * @return bool
172
     */
173 6
    public static function remove(string $key)
174
    {
175 6
        if (self::has($key)) {
176 3
            return self::find($key)->delete();
177
        }
178
179 3
        throw new NoKeyIsFound();
180
    }
181
182
    /**
183
     * Get all the settings
184
     *
185
     * @return mixed
186
     */
187 39
    public static function allSettings() : array
188
    {
189
        return Cache::rememberForever('settings.all', function () {
190 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...
191
192
            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...
193
                $array[$setting->key] = $setting->value;
194
            }
195
196
            return $array;
197 39
        });
198
    }
199
200
    /**
201
     * Helper function: Validate a value against its type and its rules.
202
     * @param  mixed $value
203
     * @return bool
204
     */
205 12
    public function validateNewValue($value) : bool
206
    {
207 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...
208
    }
209
210
    /**
211
     * Get the validation rules for setting fields
212
     *
213
     * @return array
214
     */
215 21
    public static function getValidationRules() : array
216
    {
217 21
        if ('mysql' === \DB::connection()->getPDO()->getAttribute(\PDO::ATTR_DRIVER_NAME)) {
218
            return Cache::rememberForever('settings.rules', function () {
219
                return Setting::select(\DB::raw('concat(rules, "|", $type) as rules, key'))
220
                            ->pluck('rules', 'key')
221
                            ->toArray();
222
            });
223
        }
224
225
226
        return Cache::rememberForever('settings.rules', function () {
227 21
            return Setting::select(\DB::raw("printf('%s|%s', rules, type) as rules, key"))
228 21
                            ->pluck('rules', 'key')
229 21
                            ->toArray();
230 21
        });
231
    }
232
233
    /**
234
     * Flush the cache
235
     */
236 48
    public static function flushCache()
237
    {
238 48
        Cache::forget('settings.all');
239 48
    }
240
241
    /**
242
     * The "booting" method of the model.
243
     *
244
     * @return void
245
     */
246 48
    protected static function boot()
247
    {
248 48
        parent::boot();
249
250
        static::deleted(function () {
251 3
            self::flushCache();
252 48
        });
253
        static::updated(function () {
254 9
            self::flushCache();
255 48
        });
256
        static::created(function () {
257 48
            self::flushCache();
258 48
        });
259 48
    }
260
}
261