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.
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.
IMHO it's a bit over engineered. You can do the same with the helper approach:
Less cumbersome. No loops. Max 1 DB hit per request. Max 1 Cache hit per request.
Here is an updated answer as of Laravel 5.5.
First, create a migration for your
settings
table:Then create a
Setting
model:Now, in
AppServiceProvider
, add the following to yourboot()
method:This will create
config('settings.*')
for each setting in your database, where*
is the key.For example, insert/create the following setting:
Now you can access
config('settings.example')
, which will give youHello World
.Updating settings is as simple as doing:
Here is how I solved it in Laravel 5.4. I have a database table called
configurations
and created a model for it calledConfiguration
. Theconfigurations
have akey
andvalue
like you mentioned. Of course you can change this toSettings
if you want.In
AppServiceProvider
boot()
add:Create a helper function (I put this in App\Http\helpers.php which is in my composer autoload):
Then you can access the value anywhere using
configuration('key_name')
etc.