上一篇主要講系統配置 Form 表單如何自定義,以及配置的 Form 表單擴充套件的問題。雖然功能已經滿足使用,但也有其弊端:
- 系統配置是存在資料庫中,且配置內容改動次數較少,每次獲取仍需要查庫,在大量用到配置的場景下影響效能。
- 沒有統一的獲取配置資料的介面,後期維護麻煩。
針對以問題我們的對策是
- 將配置快取起來,使用 Redis 快取。(當然用檔案快取也是 ok 的,但 Redis 應用的場景更多!)
- 統一系統配置呼叫的介面。
首先看一下配置表的遷移檔案和資料
很簡單,除了主鍵外,只剩下 name 和 value 兩個有效欄位。
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateSystemConfigsTable extends Migration { public function up() { Schema::create('system_configs', function (Blueprint $table) { $table->id(); $table->string('name'); $table->text('value'); $table->timestamps(); }); } public function down() { Schema::dropIfExists('system_configs'); } }
資料庫表存入的記錄(現在只有兩行記錄,不過可以通過擴充套件 Tab 欄增加系統配置,就能增加表記錄行數)
看第一行
name = config_one
資料的value
欄位內容以及格式(json 格式)。
然後是 Redis 的配置
- .env 檔案的配置
REDIS_CLIENT=phpredis REDIS_HOST=127.0.0.1 REDIS_PASSWORD=null REDIS_PORT=6379
- databse.php 的配置
'cache' => [ 'url' => env('REDIS_URL'), 'host' => env('REDIS_HOST', '127.0.0.1'), 'password' => env('REDIS_PASSWORD', null), 'port' => env('REDIS_PORT', '6379'), 'database' => env('REDIS_CACHE_DB', '1'), ],
- redis 的呼叫方法
# get 方法: Redis::connection('cache')->get($cacheKey); # set 方法: Redis::connection('cache')->set($cacheKey, json_encode($data)); # del 方法: Redis::connection('cache')->del($cacheKey);
最後是系統配置的統一介面以及呼叫方法
系統配置的統一介面
<?php namespace App\Models; use Eloquent; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Carbon; use Exception; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Redis; class SystemConfig extends Model { use HasFactory; const CACHE_KEY_PREFIX = 'System-Config'; protected $table = 'system_configs'; protected $fillable = ['name', 'value']; // 獲取系統配置 public static function get($name, $key = null, $default = null) { if (empty($name)) { throw new Exception('配置名為空,請聯絡管理員'); } $cacheKey = self::CACHE_KEY_PREFIX; $jsonData = Redis::connection('cache')->get($cacheKey); $data = json_decode($jsonData, true); // 如果快取沒有資料 if (empty($data) || !is_array($data) || !Arr::exists($data, $name)) { $data = []; $config = self::query()->get()->toArray(); foreach ($config as $item) { $data[$item['name']] = json_decode($item['value'], true); } Redis::connection('cache')->set($cacheKey, json_encode($data)); } // 如果 name 不存在,直接返回 null if (!Arr::exists($data, $name)) { return null; } // 獲取 name 對應的配置 $value = Arr::get($data, $name, $default); // 如果 key 值不存在,直接返回 name 對應的配置 if (!$key) { return $value; } // 如果 key 值存在,返回 name 對應配置中的 key 鍵對應的值 return Arr::get(Arr::get($data, $name, $default), $key, $default); } }
系統配置的呼叫示例:
// 獲取整條配置資訊 SystemConfig::get('config_one'); // 獲取整條配置資訊中的一個配置項 SystemConfig::get('config_one', 'email'); // 獲取整條配置資訊中的一個配置項,如果沒有返回預設值 SystemConfig::get('config_one', 'email', 'mail.qq.com');
但是配置仍會改動,所以在必要時清除快取
- 一般系統配置沒有刪除操作,只有建立和更新,現在只針對更新刪除快取。我沒有用模型監聽事件,我採用的是模型事件的閉包,請參見 模型閉包的使用
/** * 使用模型的閉包刪除快取 */ protected static function booted() { // 資料更新後 - 刪除快取 static::updated(function ($config) { $cacheKey = self::CACHE_KEY_PREFIX; Redis::connection('cache')->del($cacheKey); }); }
- 這樣一來,在模型資料更新的時候,快取是被清理掉的。
結語
- 好了,本節內容已經講完,也不是很複雜,只用到了 Redis 的
String
資料結構,也沒有什麼高深的方法,簡單的get
、set
和del
方法就滿足了使用。 - 如果有更好的辦法,歡迎在評論區討論。
本作品採用《CC 協議》,轉載必須註明作者和本文連結