2015-09-28 6 views
1

Я ищу эффективный способ для загрузки настроек/конфигурации из базы данных с Laravel 5. Настройки состоят из столбца key и value класса модели в основном выглядит следующим образом:настройки Laravel загрузки из базы данных

<?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 (а также создал фасад для него):

<?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, но я еще не там. Я думал, что в этом случае это будет излишним. Мне бы очень хотелось услышать, если мой подход делает любой смысл.

ответ

4

ИМХО, это немного более спроектировано. Вы можете сделать то же самое со вспомогательным подходом:

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 БД за каждый запрос. Макс. 1 кэш за каждый запрос.

+0

Это замечательно, спасибо большое. Я, безусловно, над инженерной. Дело в том, что у меня также был «открытый набор функций ($ key, $ value)» в пользовательском классе «Настройка». Так что это всего лишь несколько кодов и запросов. Но вернемся к вашей функции. Если я назову его несколько раз для разных настроек загрузки на страницу, не будет ли он несколько раз ударять кеш? – JasonK

+0

Нет, поскольку значение хранится в статической переменной. Я цитирую [PHP Docs] (http://php.net/manual/en/language.variables.scope.php#language.variables.scope.static): статическая переменная существует только в области локальных функций, но она делает не теряют свою ценность, когда выполнение программы покидает эту область –

0

Вот как я решил это в Laravel 5.4. У меня есть таблица базы данных с именем configurations и создана модель для нее под названием Configuration. configurations имеют key и value, как вы упомянули. Конечно, вы можете изменить это на 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') и т. д.

+0

, как вы обновляете значение? Можете ли вы поделиться этой частью? – Shiro

2

Вот обновленный ответ от 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', 
]); 
Смежные вопросы