Laravel: Loading the settings from the database (or file)

Because not everything can go to a .env file

Italo Baeza
Sep 7, 2018 · 3 min read
“close-up photography of black metal gears” by Isis França on Unsplash

For any project, an .env file is preferred over anything else. But this file is referred as “The Environment” for the whole application. When an app must be configurable by the end user, it’s better to hold the configuration in other parts of the Application, like on the database.

Okay, you may argue that using a static file located somewhere (and editing that instead) could be better for storing the application settings than the database, leaving this for the real data itself. SQLite could help here if you don’t want to with your main database, knowing current benchmarks of SQLite are not kick in the balls against other RDBMS.

For this example I will stick to the “same Database” solution, which is quite simple.

Settings? What settings?

Let’s say in our Podcast webapp we need to pull out a settings list about if we want to show a global alert in the site, for example, to warn about a maintenance time, a new show, etc.

We need to add a settings with the warn text. If the text is empty, then no warning will be shown, since there is no point in showing an empty alert.

For that reason I will create an Eloquent Model called “Setting”, with a migration, and then I will add columns “name” and “value”, the latter being .

php artisan make:model Setting --migration

After adding the columns in the migration file, I will add the settings that I want. In this case, the global alert. I did it inside one of my Database Seeders:

Setting::create([ ‘name’ => ‘global_alert’, ‘value’ => null ]);

Quite straightforward. Now, the magic.

Adding the settings to the global config

Laravel includes a handy function called config(), which holds a class with a lot of settings so every Service that your application boots, like Cache, Database, etc. can pull its own configuration data.

The neat thing about this function is that it works as a getter if you only input a string with dot notation or absolutely nothing, and as a setter if you input an array.

So, we are going to open AppServiceProvider and tell Laravel that, when the App boots, which is after all other Services are already registered, we are gonna add to the config array our own settings.

public function boot() 
{
config([
'global' => Setting:all([
'name','value'
])
->keyBy('name') // key every setting by its name
->transform(function ($setting) {
return $setting->value // return only the value
})
->toArray() // make it an array
])
// ...
}

Then the config will be added to the list, something you can check by dd(config()) after the boot method or anywhere.

That’s basically it. Of course, you could:

  • Use the DB facade directly to avoid the Eloquent Model overhead (unless you are storing arrays or json, which you will have to convert them manually, I’m sure).
  • Add a column named “group” which will allow you to group sub-settings using, and then use groupBy after retrieving all the items. Or play with dot notation.
  • Use SQLite with just using the “connection” property of the Eloquent Model or the “connection” method when using DB facade directly.
  • Make your own ServiceProvider to load the configs to be part of the booting process of your application.
  • Add a boolean column telling if it’s global, and query only those who are true, leaving the rest for later.

You can do a lot to put your own settings here inside the config. Or you can use the Fluent class for more advanced (and time-saving) things.

Bonus: Adding the warning

In your hypothetically present HomeController, I will check if the alert exists and if it’s empty before passing it to the view.

    /**
* Show the application dashboard.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$globalAlert = config('settings.global_alert');
return view('home', [
'globalAlert' => $globalAlert
]);
}

Then in some place high up the <body> I will add an if clause. PHP considers null as false, so if there is even a tiny dot on the value, it will considered as true.

@if($globalAlert)
<div class="alert alert-info small">
{{ $globalAlert }}
</div>
@endif

That’s pretty much it. Any other way, just it the comments.

Italo Baeza

Written by

Graphic Designer. Web Developer Full Stack. Retired Tech & Gaming Editor.