Global Application Settings
Published on by timacdonald
In applications it is often useful to have a way to store some global settings. These settings are not related to a specific model, such as a user, but to the system as a whole. You can achieve this with Eloquent, of course, but I never felt that was the right approach given you are saving non-relational data in a relational system. I found Spatie’s Valuestore package to be the perfect fit for creating a settings repository for an application.
The package will take your settings and store them as a JSON file on the local filesystem. Let’s use the example of having a banner notification at the top of your application. The banner notification is visible on every page and an admin can update the text it contains.
To get started you will want to install the package.
composer require spatie/valuestore
Now you can create a Valuestore by specifying the path on disk you would like the settings to be read from, and written to. I want my settings file to be at storage/app/settings.json
, so in my controller I will instantiate the Valuestore with the static make($path)
method and put some values into it.
public function update(Request $request){ $settings = Valuestore::make(storage_path('app/settings.json')); $settings->put('banner_notification', $request->banner_notification); return redirect()->back()->with(['notice' => 'Settings updated']);}
As you can see in this snippet we are adding the request input banner_notification
to the Valuestore. Under the hood the Valustore package is JSON encoding the values and storing them on the filesystem in our settings.json
. The package will manage this file for us, so if it doesn’t exist it will create it, and if we remove all the values it will delete the file to cleanup after itself.
The API shares many of the same methods as Laravel’s cache repository, so it should feel familiar to work with.
You are now able to access these settings in other places of your app. To do so you will need to instantiate the Valuestore with the same path we specified previously.
// The controller... public function __invoke(){ $settings = Valuestore::make(storage_path('app/settings.json')); return view('homepage', ['settings' => $settings]);} // The view... @if($settings->has('banner_notification')) <div class="banner-notification"> {{ $settings->get('banner_notification') }} </div>@endif
The Valuestore is a really nice way to store some loose values that don’t need to be persisted to the database. No migrations, no models, just a JSON file containing your settings. The perfect fit for some basic key / value pairs. Just make sure you put your settings file in a location that is not publicly accessible.
The package also has a bunch of other really handy methods for working with your persisted data that you should checkout.
Although that is all you need to get started, I’ve also found the following tips handy when working with a Valuestore.
Binding to the container
In the previous example you can see that we had to create the Valuestore a few times and we are re-writing the instantiation logic in a few places, so instead why don’t we bind our settings to the container so we can have the instantiation logic specified in one place. This will also give us the ability to inject the Valuestore into our controllers.
First we will create our own Settings
class that extends the Valuestore.
<?php namespace App; use Spatie\Valuestore\Valuestore; class Settings extends Valuestore{ //}
Next we will want to bind an instance of Settings
to the container as a singleton within a Service Provider.
// AppServiceProvider... public function register(){ $this->app->singleton(Settings::class, function () { return Settings::make(storage_path('app/settings.json')); });}
Now we can inject our settings into a controller with Dependency Injection.
public function update(Request $request, Settings $settings){ $settings->put('banner_notification', $request->banner_notification); return redirect()->back()->with(['notice' => 'Settings updated']);}
Global helper
I find adding a global settings()
helper also very useful when you want to access the settings in your views. Although you could achieve this with view composers or by passing through the controller as previously shown, I find the global helper is a simpler approach.
// helpers.php function settings($key = null, $default = null) { if ($key === null) { return app(App\Settings::class); } return app(App\Settings::class)->get($key, $default);}
In your views you can now retrieve settings via the global helper. This is especially handy when a setting, such as the banner notification, is needed on every single page.
// The view... <div class="banner-notification"> {{ settings()->get('banner_notification') }} {{-- or --}} {{ settings('banner_notification') }} </div>
I really like the simplicity this package introduces to enable you to store some loose values. I’ve always felt storing this kind of data in the database with some sort of key / value pair setup was never quite right. If you ever need some globally available application settings, I definitely recommend checking out Spatie’s Valuestore package. Thanks Spatie!
Developing engaging and performant web applications with a focus on TDD. Specialising in PHP / Laravel projects. ❤️ building for the web.