Laravel load settings from database

16,392

Solution 1

IMHO it's a bit over engineered. You can do the same with the helper approach:

function settings($key)
{
    static $settings;

    if(is_null($settings))
    {
        $settings = Cache::remember('settings', 24*60, function() {
            return array_pluck(App\Setting::all()->toArray(), 'value', 'key');
        });
    }

    return (is_array($key)) ? array_only($settings, $key) : $settings[$key];
}

Less cumbersome. No loops. Max 1 DB hit per request. Max 1 Cache hit per request.

Solution 2

Here is an updated answer as of Laravel 5.5.

First, create a migration for your settings table:

Schema::create('settings', function (Blueprint $table) {
    $table->increments('id');
    $table->string('key');
    $table->text('value')->nullable();
    $table->timestamps();
});

Then create a Setting model:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Setting extends Model
{
    protected $fillable = ['key', 'value'];
}

Now, in AppServiceProvider, add the following to your boot() method:

if (Schema::hasTable('settings')) {
    foreach (Setting::all() as $setting) {
        Config::set('settings.'.$setting->key, $setting->value);
    }
}

This will create config('settings.*') for each setting in your database, where * is the key.

For example, insert/create the following setting:

Setting::create([
    'key' => 'example',
    'value' => 'Hello World',
]);

Now you can access config('settings.example'), which will give you Hello World.

Updating settings is as simple as doing:

Setting::where('key', 'example')->update([
    'value' => 'My New Value',
]);

Solution 3

My Laravel version is 6.0 (latest as of now) and i had to search for this problem and found a solution, compiling all the answers above lets start.

Step 1: Create a Helpers.php file in App directory

namespace App;

use Cache;

class Helpers
{
    /**
     * Fetch Cached settings from database
     *
     * @return string
     */
    public static function settings($key)
    {
        return Cache::get('settings')->where('key', $key)->first()->value;
    }
}

Step 2: Create a settings model with following

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Settings extends Model
{
    protected $fillable = ['key', 'value'];
}

Step 3: Create migrations for settings table & migrate

Schema::create('settings', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->string('key')->unique();;
    $table->text('value')->nullable();
    $table->timestamps();
});

Step 4: Add to App\Providers\ServiceProvider.php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Cache;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Cache::forever('settings', \App\Models\Settings::all());
    }
}

Step 5: Add a few settings using tinker or any other method

Step 6: Usage

  1. Add use App\Helpers; to your controller
  2. Try with dd(Helpers::settings('your_setting_name_here'));

Advantages:

  1. Easily accessible(just call your settings method with the required setting name)
  2. Caches all the settings (saving DB calls)

Solution 4

The OP led me down the path to develop this package, which saves key-pair values to a settings table and uses cache to reduce DB queries. If you're looking for your own solution, feel free to take a look at my code.

Solution 5

Here is how I solved it in Laravel 5.4. I have a database table called configurations and created a model for it called Configuration. The configurations have a key and value like you mentioned. Of course you can change this to Settings if you want.

In AppServiceProvider boot() add:

// cache configuration
Cache::forever('configuration', Configuration::all());

Create a helper function (I put this in App\Http\helpers.php which is in my composer autoload):

function configuration($key)
{
    return Cache::get('configuration')->where('key', $key)->first()->value;
}

Then you can access the value anywhere using configuration('key_name') etc.

Share:
16,392
JasonK
Author by

JasonK

Just another enthusiast!

Updated on July 21, 2022

Comments

  • JasonK
    JasonK almost 2 years

    I'm looking for an efficient way to load settings/configuration from the database with Laravel 5. Settings consist of a key and value column, the model class basically looks like this:

    <?php
    
    namespace App;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Setting extends Model
    {
        protected $table = 'settings';
        protected $fillable = ['key', 'value'];
        protected $primaryKey = 'key';
    }
    

    At first I made a simple helper function which does the job. The problem is, this would lead to multiple calls per page request. Which is getting slow.

    /**
     * Get the value for the given setting from the database.
     *
     * @param  string  $key
     * @return string
     */
    function setting($key)
    {
        $setting = Setting::whereKey($key)->firstOrFail();
    
        return $setting->value;
    }
    
    // $foo = setting('foo'); returns 'bar'
    

    In an attempt to improve this I creating a custom class called Setting within the App\Classes directory (and also created a Facade for it):

    <?php
    
    namespace App\Classes;
    
    use Cache;
    
    class Setting {
    
        /**
         * The array of settings
         *
         * @var array $settings
         */
        protected $settings = [];
    
        /**
         * Instantiate the class.
         */
        public function __construct()
        {
            $this->loadSettings();
        }
    
        /**
         * Pull the settings from the database and cache them.
         *
         * @return void;
         */
        protected function loadSettings()
        {
            $settings = Cache::remember('settings', 24*60, function() {
                return \App\Setting::all()->toArray();
            });
    
            $this->settings = array_pluck($settings, 'value', 'key');
        }
    
        /**
         * Get all settings.
         *
         * @return array;
         */
        public function all()
        {
            return $this->settings;
        }
    
        /**
         * Get a setting value by it's key.
         * An array of keys can be given to retrieve multiple key-value pair's.
         *
         * @param  string|array  $key;
         * @return string|array;
         */
        public function get($key)
        {
            if( is_array($key) ) {
                $keys = [];
    
                foreach($key as $k) {
                    $keys[$k] = $this->settings[$k];
                }
    
                return $keys;
            }
    
            return $this->settings[$key];
        }
    
    }
    
    // $foo = Setting::get('foo');
    

    And now for my question: is this the best way to tackle this problem? I'm now caching all the settings when the class gets constructed. And then retrieve setting values from the cache after that.

    I'm beginning to understand the Repository pattern in L5, but I'm not there yet. I thought that would be overkill in this case. I would love to hear if my approach makes any sence.

  • JasonK
    JasonK over 8 years
    This is great, thanks alot. I was certainly over engineering. The thing is I also had a public function set($key, $value) in the custom Setting class. So it's a bit more code in total and querying. But to get back to your function. If I call it multiple times for different settings per page load, would it not hit the Cache multiple times?
  • Javi Stolz
    Javi Stolz over 8 years
    No, since the value is stored in a static variable. I quote from PHP Docs: static variable exists only in a local function scope, but it does not lose its value when program execution leaves this scope
  • aknosis
    aknosis almost 6 years
    You should a bit about caching here too. Otherwise every request is hitting the settings table.
  • ymakux
    ymakux over 4 years
    Makes sense to add the second argument for a default value if a key isn't found
  • i need help
    i need help about 3 years
    question, after perform Settings::where('key', 'now')->update(['value' => $latesttime,]); if next line immediately retrieve $print = Helpers::settings('now'); it will print older value. How to instantly clear and refresh this particular key without doing full Cache::flush(); ?