从数据库加载Laravel设置


Laravel load settings from database

我正在寻找一种有效的方法来加载设置/配置从数据库与Laravel 5。设置由keyvalue列组成,模型类基本上是这样的:

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

首先,我做了一个简单的辅助函数来完成这项工作。问题是,这将导致每个页面请求调用多个调用。

/**
 * 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'

为了改进这一点,我在App'Classes目录中创建了一个名为Setting的自定义类(并为它创建了一个Facade):

<?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');

现在我的问题是:这是解决这个问题的最好方法吗?我现在在构造类时缓存所有设置。然后从缓存中检索设置值。

我开始理解L5中的储存库模式,但我还没有到那一步。我觉得这案子太过分了。我很想知道我的方法是否有意义。

这是Laravel 5.5的最新答案。

首先,为settings表创建一个迁移:

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

然后创建Setting模型:

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

现在,在AppServiceProvider中,将以下内容添加到boot()方法中:

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

这将为数据库中的每个设置创建config('settings.*'),其中*是键。

例如,插入/创建如下设置:

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

现在你可以访问config('settings.example'),它会给你Hello World

更新设置就像这样简单:

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

我认为这有点过于设计了。您可以使用helper方法执行相同的操作:

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];
}

少麻烦。没有循环。每个请求最多1个DB。每个请求最多1次缓存命中

我的Laravel版本是6.0(最新的),我不得不搜索这个问题,并找到了一个解决方案,编译上面所有的答案,让我们开始。

步骤1:在App目录

创建一个Helpers.php文件
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;
    }
}

步骤2:创建一个设置模型,如下所示

namespace App'Models;
use Illuminate'Database'Eloquent'Model;
class Settings extends Model
{
    protected $fillable = ['key', 'value'];
}

步骤3:创建迁移设置表&

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

步骤4:添加到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());
    }
}

步骤5:使用tinker或任何其他方法添加一些设置

步骤6:用法

  1. use App'Helpers;添加到控制器
  2. 试试dd(Helpers::settings('your_setting_name_here'));

优点:

  1. 易于访问(只需调用您的设置方法与所需的设置名称)
  2. 缓存所有设置(保存DB调用)

我是如何在Laravel 5.4中解决这个问题的。我有一个名为configurations的数据库表,并为它创建了一个名为Configuration的模型。configurationskeyvalue,就像你提到的。当然,如果你愿意,你也可以把它改成Settings

AppServiceProvider boot()添加:

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

创建一个辅助函数(我把它放在App'Http'helpers.php中,这是在我的composer自动加载):

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

然后你可以使用configuration('key_name')等访问任何地方的值

OP引导我开发这个包,它将键对值保存到设置表中,并使用缓存来减少DB查询。如果您正在寻找自己的解决方案,请随意查看我的代码。