Store strongly typed application settings
This package allows you to store settings in a repository (database, Redis, ...) and use them through an application without hassle. You can create a settings class as such:
class GeneralSettings extends Settings
{
public string $site_name;
public bool $site_active;
public static function group(): string
{
return 'general';
}
}
If you want to use these settings somewhere in your application, you can inject them, since we register them in the Laravel Container. For example, in a controller:
class GeneralSettingsController
{
public function show(GeneralSettings $settings){
return view('settings.show', [
'site_name' => $settings->site_name,
'site_active' => $settings->site_active
]);
}
}
You can update the settings as such:
class GeneralSettingsController
{
public function update(
GeneralSettingsRequest $request,
GeneralSettings $settings
){
$settings->site_name = $request->input('site_name');
$settings->site_active = $request->input('site_active');
$settings->save();
return redirect()->back();
}
}
Let's take a look at how to create your own settings classes.
We invest a lot of resources into creating best in class open source packages. You can support us by buying one of our paid products.
We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on our contact page. We publish all received postcards on our virtual postcard wall.
You can install the package via composer:
composer require spatie/laravel-settings
You can publish and run the migrations with:
php artisan vendor:publish --provider="Spatie\LaravelSettings\LaravelSettingsServiceProvider" --tag="migrations"
php artisan migrate
You can publish the config file with:
php artisan vendor:publish --provider="Spatie\LaravelSettings\LaravelSettingsServiceProvider" --tag="config"
This is the contents of the published config file:
…
The package is built around settings classes, which are classes with public properties that extend from Settings. They also have a static method group that should return a string.
You can create multiple groups of settings, each with their settings class. You could, for example, have GeneralSettings with the general group and BlogSettings with the blog group. It's up to you how to structure these groups.
Although it is possible to use the same group for different settings classes, we advise you not to use the same group for multiple settings classes.
use Spatie\LaravelSettings\Settings;
class GeneralSettings extends Settings
{
public string $site_name;
public bool $site_active;
public static function group(): string
{
return 'general';
}
}
You can generate a new settings class using this artisan command. Before you do, please check if the setting_class_path is correctly set. You can also specify a path option, which is optional.
php artisan make:setting SettingName --group=groupName
Now, you will have to add this settings class to the settings.php config file in the settings array, so it can be loaded by Laravel:
/*
* Each settings class used in your application must be registered, you can
* add them (manually) here.
*/
'settings' => [
GeneralSettings::class
],
Each property in a settings class needs a default value that should be set in its migration. You can create a migration as such:
php artisan make:settings-migration CreateGeneralSettings
This command will create a new file in database/settings where you can add the properties and their default values:
use Spatie\LaravelSettings\Migrations\SettingsMigration;
return new class extends SettingsMigration
{
public function up(): void
{
$this->migrator->add('general.site_name', 'Spatie');
$this->migrator->add('general.site_active', true);
}
}
We add the properties site_name and site_active here to the general group with values Spatie and true. More on migrations later.
You should migrate your database to add the properties:
php artisan migrate
Now, when you want to use the site_name property of the GeneralSettings settings class, you can inject it into your application:
class IndexController
{
public function __invoke(GeneralSettings $settings){
return view('index', [
'site_name' => $settings->site_name,
]);
}
}
Or use it to load it somewhere in your application as such:
function getName(): string{
return app(GeneralSettings::class)->site_name;
}
Updating the settings can be done as such:
class SettingsController
{
public function __invoke(GeneralSettings $settings, GeneralSettingsRequest $request){
$settings->site_name = $request->input('site_name');
$settings->site_active = $request->boolean('site_active');
$settings->save();
return redirect()->back();
}
}
Settings will be stored and loaded from the repository. There are two types of repositories database and redis. And it is possible to create multiple repositories for these types. For example, you could have two database repositories, one that goes to a settings table in your database and another that goes to a global_settings table.
You can explicitly set the repository of a settings class by implementing the repository method:
class GeneralSettings extends Settings
{
public string $site_name;
public bool $site_active;
public static function group(): string
{
return 'general';
}
public static function repository(): ?string
{
return 'global_settings';
}
}
When a repository is not set for a settings class, the default_repository in the settings.php config file will be used.
Before you can load/update settings, you will have to migrate them. Though this might sound a bit strange at the beginning, it is quite logical. You want to have some default settings to start with when you're creating a new application. And what would happen if we change a property of a settings class? Our code would change, but our data doesn't.
That's why the package requires migrations each time you're changing/creating your settings classes' structure. These migrations will run next to the regular Laravel database migrations, and we've added some tooling to write them as quickly as possible.
Creating a settings migration works just like you would create a regular database migration. You can run the following command:
php artisan make:settings-migration CreateGeneralSettings
This will add a migration to the application/database/settings directory:
use Spatie\LaravelSettings\Migrations\SettingsMigration;
class CreateGeneralSettings extends SettingsMigration
{
public function up(): void
{
}
}
We haven't added a down method, but this can be added if desired. In the up method, you can change the settings data in the repository when migrating. There are a few default operations supported:
You can add a property to a settings group as such:
public function up(): void
{
$this->migrator->add('general.timezone', 'Europe/Brussels');
}
We've added a timezone property to the general group, which is being used by GeneralSettings. You should always give a default value for a newly created setting. In this case, this is the Europe/Brussels timezone.
If the property in the settings class is nullable, it's possible to give null as a default value.
It is possible to rename a property:
public function up(): void
{
$this->migrator->rename('general.timezone', 'general.local_timezone');
}
You can also move a property to another group:
public function up(): void
{
$this->migrator->rename('general.timezone', 'country.timezone');
}
It is possible to update the contents of a property:
public function up(): void
{
$this->migrator->update(
'general.timezone',
fn(string $timezone) => return 'America/New_York'
);
}
As you can see, this method takes a closure as an argument, which makes it possible to update a value based upon its old value.
public function up(): void
{
$this->migrator->delete('general.timezone');
}
There might be times when you want to check if a property exists in the database. This can be done as such:
public function up(): void
{
if ($this->migrator->exists('general.timezone')) {
// do something
}
}
When you're working on a big settings class with many properties, it can be a bit cumbersome always to have to prepend the settings group. That's why you can also perform operations within a settings group:
public function up(): void
{
$this->migrator->inGroup('general', function (SettingsBlueprint $blueprint): void {
$blueprint->add('timezone', 'Europe/Brussels');
$blueprint->rename('timezone', 'local_timezone');
$blueprint->update('timezone', fn(string $timezone) => return 'America/New_York');
$blueprint->delete('timezone');
});
}
You can specify a different repository for migration operations:
public function up(): void
{
$this->migrator->repository('redis');
$this->migrator->add('general.site_active', true);
}
It is possible to create a settings class with regular PHP types:
class RegularTypeSettings extends Settings
{
public string $a_string;
public bool $a_bool;
public int $an_int;
public float $a_float;
public array $an_array;
public static function group(): string
{
return 'regular_type';
}
}
Internally the package will convert these types to JSON and save them as such in the repository. But what about types like DateTime and Carbon or your own created types? Although these types can be converted to JSON, building them back up again from JSON isn't supported.
That's why you can specify casts within this package. There are two ways to define these casts: locally or globally.
Local casts work on one specific settings class and should be defined for each property:
class DateSettings extends Settings
{
public DateTime $birth_date;
public static function group(): string
{
return 'date';
}
public static function casts(): array
{
return [
'birth_date' => DateTimeInterfaceCast::class
];
}
}
The DateTimeInterfaceCast can be used for properties with types like DateTime, DateTimeImmutable, Carbon and CarbonImmutable. You can also use an already constructed cast. It becomes handy when you need to pass some extra arguments to the cast:
class DateSettings extends Settings
{
public $birth_date;
public static function group(): string
{
return 'date';
}
public static function casts(): array
{
return [
'birt
No open issues yet, or sync has not completed.