【问题标题】:Laravel load settings from databaseLaravel 从数据库加载设置
【发布时间】:2015-12-25 19:13:11
【问题描述】:

我正在寻找一种使用 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 中的存储库模式,但我还没有到那里。我认为在这种情况下这将是矫枉过正。我很想听听我的方法是否有意义。

【问题讨论】:

    标签: php database configuration laravel-5 settings


    【解决方案1】:

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

    【讨论】:

    • 您也应该在这里了解一下缓存。否则,每个请求都会命中设置表。
    【解决方案2】:

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

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

    【讨论】:

    • 这太好了,非常感谢。我当然是过度工程了。问题是我在自定义Setting 类中也有一个public function set($key, $value)。因此,总共需要更多代码和查询。但要回到你的功能。如果我为每个页面加载的不同设置多次调用它,它不会多次命中缓存吗?
    • 否,因为该值存储在静态变量中。我引用PHP Docs:静态变量只存在于局部函数作用域内,但当程序执行离开这个作用域时它不会失去它的价值
    • 如果没有找到键,添加第二个参数作为默认值是有意义的
    【解决方案3】:

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

    第一步:在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. 缓存所有设置(保存数据库调用)

    【讨论】:

    • 问题,执行 Settings::where('key', 'now')->update(['value' => $latesttime,]);如果下一行立即检索 $print = Helpers::settings('now');它将打印旧值。如何在不执行完整 Cache::flush() 的情况下立即清除和刷新此特定键; ?
    【解决方案4】:

    这是我在 Laravel 5.4 中解决它的方法。我有一个名为configurations 的数据库表,并为它创建了一个名为Configuration 的模型。 configurations 有一个 keyvalue 就像你提到的那样。当然,如果您愿意,可以将其更改为 Settings

    AppServiceProviderboot() 添加:

    // 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') 等在任何地方访问该值。

    【讨论】:

      【解决方案5】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-09-18
        • 1970-01-01
        • 2021-03-07
        • 2018-05-28
        • 1970-01-01
        • 1970-01-01
        • 2013-10-22
        • 1970-01-01
        相关资源
        最近更新 更多