Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel load settings from database

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.

like image 633
JasonK Avatar asked Sep 28 '15 13:09

JasonK


People also ask

How does Laravel connect to database?

Laravel makes connecting with databases and running queries extremely simple. The database configuration file is app/config/database. php . In this file you may define all of your database connections, as well as specify which connection should be used by default.

Where is .ENV file in Laravel?

In a fresh Laravel installation, the root directory of your application will contain a .env.example file that defines many common environment variables.

How can check DB connection in Laravel?

Echo the Laravel database name in Blade/PHP This will output the name of the database or return 'none' if there is no connection. If you view it in the browser, it gives you the name of the connected database. Checking whether the application is connected to a Laravel database.

Where is config file in Laravel?

All of the configuration files for the Laravel framework are stored in the app/config directory. Each option in every file is documented, so feel free to look through the files and get familiar with the options available to you.


2 Answers

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',
]);
like image 195
kjdion84 Avatar answered Sep 19 '22 13:09

kjdion84


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.

like image 43
Javi Stolz Avatar answered Sep 19 '22 13:09

Javi Stolz