Oh Dear is the all-in-one monitoring tool for your entire website. We monitor uptime, SSL certificates, broken links, scheduled tasks and more. You'll get a notifications for us when something's wrong. All that paired with a developer friendly API and kick-ass documentation. O, and you'll also be able to create a public status page under a minute. Start monitoring using our free trial now.

Store strongly typed settings in a Laravel app

Original – by Freek Van der Herten – 4 minute read

We have released a new package, called spatie/laravel-settings, that allows you to strongly type settings in a Laravel app. In this blog post, I'd like to introduce the package to you.

Why we created this package

At Spatie, we're currently building a huge application. This application will be multi-tenant, and each tenant has literally hundreds of settings that can be configured to tweak behavior.

The app's admins can update the settings, so it's only logical to store these settings in the database. We could have created a table called settings with a name and a value column and call it a day. But we want to store different types of settings: strings, integers, booleans, and objects such as dates. And it would also be nice if we could easily fetch these settings from anywhere in our app and get them in the right type.

Because we think our solution might help others, we decided to package it up.

Introducing spatie/laravel-settings

The package is built around settings classes. They are responsible for storing the settings. They all have public properties that can be used to fetch settings values. Each settings class extends from Spatie\LaravelSettings\Settings. They have a static method group that should return a string uniquely grouping settings.

use Spatie\LaravelSettings\Settings;

class GeneralSettings extends Settings
{
    public string $site_name;
    
    public bool $site_active;
    
    public static function group(): string
    {
        return 'general';
    }
}

To set up a class's initial values, you can use a SettingMigration to ensure that settings are set up correctly.

use Spatie\LaravelSettings\SettingsMigration;

class CreateGeneralSettings extends SettingsMigration
{
    public function up(): void
    {
       $this->migrator->add('general.site_name', 'Spatie');
       $this->migrator->add('general.site_active', true);
    }
}

To retrieve settings, you can resolve your settings class from the container. Here's an example where we use method injection.

class IndexController
{
    public function __invoke(GeneralSettings $settings){
        return view('index', [
            'site_name' => $settings->site_name,
        ]);
    }
}

Updating the settings can be done by setting the public properties and calling save on the settings class.

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();
    }
}

Of course, you could also just instanciate the class using the container:

function getName(): string{
	return app(GeneralSettings::class)->site_name
}

Using casts

Let's take a look at how objects can be used as settings. Here's an example where we are going to use a date object in a setting. Notice that there is now a casts function that returns the casters for a setting's 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 ships with the package and can be used for properties with types like DateTime, DateTimeImmutable, Carbon and CarbonImmutable.

Writing your own casters is pretty easy. You just need to create a class that implement that Spatie\LaravelSettings\SettingsCasts\SettingsCast interface.

namespace Spatie\LaravelSettings\SettingsCasts;

interface SettingsCast
{
    /**
     * Will be used to when retrieving a value from the repository, and
     * inserting it into the settings class.
     */
    public function get($payload);

    /**
     * Will be used to when retrieving a value from the settings class, and
     * inserting it into the repository.
     */
    public function set($payload);
}

Here is an implementation of a caster that can be used with DTOs from the spatie/data-transfer-object package.

class DtoCast implements SettingsCast
{
    private string $type;

    public function __construct(?string $type)
    {
        $this->type = $type;
    }

    public function get($payload): DataTransferObject
    {
        return new $this->type($payload);
    }

    public function set($payload): array
    {
        return $payload->toArray();
    }
}

In closing

Using this package, we can safely use all of the configuration settings throughout our entire codebase. It's pretty nice that we also get autocompletion on the properties when a settings class is injected.

The package has many other features not mentioned in this blogpost: using Redis, encrypt properties,global casts, locking properties, ... and much more. To learn more about these features, head over to the readme of spatie/laravel-settings on GitHub.

This package has been coded up by my colleague Ruben, who, as always, did an excellent job.

Be sure also to take a look at our other packages and paid products as well. Pretty sure we got something for your next project.

Stay up to date with all things Laravel, PHP, and JavaScript.

You can follow me on these platforms:

On all these platforms, regularly share programming tips, and what I myself have learned in ongoing projects.

Every month I send out a newsletter containing lots of interesting stuff for the modern PHP developer.

Expect quick tips & tricks, interesting tutorials, opinions and packages. Because I work with Laravel every day there is an emphasis on that framework.

Rest assured that I will only use your email address to send you the newsletter and will not use it for any other purposes.

Comments

What are your thoughts on "Store strongly typed settings in a Laravel app"?

Comments powered by Laravel Comments
Want to join the conversation? Log in or create an account to post a comment.