composer require bogdankharchenko/typed-laravel-settings
namespace App\Models\User;
use Illuminate\Database\Eloquent\Model;
use BogdanKharchenko\Settings\Models\HasSettings;
class User extends Model
{
use HasSettings;
}
This class represents a group of available settings for a given model. Public properties and their values will automatically be serialized into a json column, and serve as defaults.
use BogdanKharchenko\Settings\BaseSettings;
class UserSettings extends BaseSettings
{
public string $favoriteColor = 'red';
}
Changing the values will persist them into the database. When updating settings, cache will automatically be flushed.
$user = User::first();
$user->setSettings(function(UserSettings $settings){
$settings->favoriteColor = 'blue';
});
// Updating Multiple Settings
$user->setSettings(function(UserSettings $settings, EmailPreferences $emailPreferences){
$settings->favoriteColor = 'blue';
$emailPreferences->marketing = false;
});
// Using the `setSettings()` Closure is a wrapper around the code example below.
$settings = new UserSettings($user);
$settings->favoriteColor = 'pink';
$settings->saveSettings();
Creating a helper function on your allows us to access strongly typed settings. When a setting is retrieved from the database, it will overwrite the default setting on the class.
class User extends Model
{
public function config(): UserSettings
{
return new UserSettings($this);
}
}
$user->config()->favoriteColor // returns blue
// Alternatively you can use docblocks to assist in typing
/** @var UserSettings $settings */
$settings = $user->getSettings(UserSettings::class);
$settings->favoriteColor // returns blue
You may decide to encrypt/decrypt sensitive settings such as secrets. You should specify a protected array $encrypted
with a list of properties to encrypt/decrypt. Data will be encrypted into the database, and decrypted when retrieved.
use BogdanKharchenko\Settings\BaseSettings;
class UserSettings extends BaseSettings
{
protected array $encrypted = [
'secret',
'list',
];
public ?string $secret = null;
public array $list = [
'a',
'b',
'c',
];
}
The default encrypter is BogdanKharchenko\Settings\Repository\Encrypter
but you may choose to implement your own encryption strategy by implementing BogdanKharchenko\Settings\Contracts\EncrypterInterface
and changing the config.
You can define validation rules in your custom Settings
class, in the same way as you would in FormRequests
using the rules()
and messages()
methods. These rules will be triggered immediately before attempting to persist the data into the database.
class SimpleSettingWithRule extends BaseSettings
{
public string $favoriteColor = 'red';
// Optional
public function rules()
{
return [
'favoriteColor' => ['required', Rule::in(['red', 'green'])],
// Or
$this->toName()->favoriteColor => ['required', Rule::in(['red', 'green'])],
];
}
// Optional
public function messages()
{
return [
'favoriteColor.in' => 'color does not match',
];
}
}
Validation is optional, as you may choose to do this in other parts of your app. You can also customize the validator by implementing the BogdanKharchenko\Settings\Contracts\ValidatorInterface
and changing the validator
config.
Similarly to morph map for Eloquent, it is a good idea to allow your Setting be more flexible to restructuring without touching your database.
// config/typed-settings.php
return [
'morph'=>[
'user-settings'=> UserSettings::class,
],
'cache' => [
'enabled' => true,
'store' => 'redis',
'seconds' => 600,
],
'encrypter' => \BogdanKharchenko\Settings\Repository\Encrypter::class,
'validator' => \BogdanKharchenko\Settings\Repository\Validator::class,
];
Sometimes you may need to check a setting on a database level, there is a helper scope available.
$users = User::query()
->whereSettings(UserSettings::class, 'favoriteColor', 'blue')
->get();