Laravel从数据库加载设置

时间:2015-09-28 13:52:12

标签: php database configuration laravel-5 settings

我正在寻找一种使用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'

为了改进这一点,我在Setting目录中创建了一个名为App\Classes的自定义类(并为它创建了一个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中的Repository模式,但我还没有。我认为在这种情况下会有点矫枉过正。如果我的方法有任何意义,我很想知道。

5 个答案:

答案 0 :(得分:14)

以下是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',
]);

答案 1 :(得分:5)

恕我直言,它有点过度设计。您可以使用辅助方法执行相同的操作:

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次缓存命中。

答案 2 :(得分:1)

OP引导了我开发此package的过程,该过程将密钥对值保存到设置表中,并使用缓存来减少数据库查询。如果您正在寻找自己的解决方案,请随时查看我的code

答案 3 :(得分: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步:使用修补程序或任何其他方法添加一些设置

第6步:用法

  1. use App\Helpers;添加到您的控制器
  2. 尝试使用dd(Helpers::settings('your_setting_name_here'));

优势:

  1. 易于访问(只需使用所需的设置名称调用设置方法)
  2. 缓存所有设置(保存数据库调用)

答案 4 :(得分:0)

以下是我在Laravel 5.4中解决它的方法。我有一个名为configurations的数据库表,并为其创建了一个名为Configuration的模型。正如您所提到的,configurationskeyvalue。当然,如果需要,您可以将其更改为Settings

AppServiceProvider boot()添加:

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

创建一个帮助函数(我把它放在我的作曲家自动加载中的App \ Http \ helpers.php中):

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

然后,您可以使用configuration('key_name')等在任何地方访问该值。