darkghosthunter / laraconfig
Laravel 的按用户设置仓库系统
Requires
- php: >=8.0
- illuminate/cache: ^8.43
- illuminate/collections: ^8.43
- illuminate/config: ^8.43
- illuminate/database: ^8.43
- illuminate/support: ^8.43
- symfony/console: ^5.3
Requires (Dev)
- mockery/mockery: ^1.4.3
- orchestra/testbench: ^6.19
- phpunit/phpunit: ^9.5.4
README
该软件包已被存档。
抱歉大家,我承担了太多,目前没有使用这个软件包来证明其支持。
我可能在不久的将来重新考虑这一点。
Laraconfig
Laravel 的按用户设置仓库系统。
此软件包允许用户轻松快速地查询、更改和更新设置。
User::find(1)->settings->set('color', 'red');
要求
- Laravel 8.x
- PHP 8.0 或更高版本
工作原理
Laraconfig 通过扩展 Laravel 关系并包含迁移系统来管理它们。
每个设置只是一个值,它引用一个包含类型和名称等信息并链接到用户的父 "元数据"。
由于 Laraconfig 在幕后使用 Eloquent ORM,因此获取一个或所有设置的获取对开发者来说完全透明。
快速入门
您可以通过 composer 安装此软件包。
composer require darkghosthunter/laraconfig
首先,发布并运行迁移。这些将添加两个名为 user_settings 和 user_settings_metadata 的表。一个存储每个用户的值,另一个存储设置的元数据。
php artisan vendor:publish --provider="DarkGhostHunter\Laraconfig\LaraconfigServiceProvider" --tag="migrations"
php artisan migrate
迁移使用一个形态列来连接到用户。您可以在迁移之前更改它。
其次,将 HasConfig 特性添加到您希望具有设置的 User 模型中。
namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use DarkGhostHunter\Laraconfig\HasConfig; class User extends Authenticatable { use HasConfig; // ... }
最后,使用 settings:publish artisan 命令。这将创建一个位于项目根目录中的 settings 文件夹和一个 users.php 文件。
php artisan settings:publish
现在,让我们创建一些设置。
设置清单
Laraconfig 通过一种类似清单的 settings/users.php 文件来管理全局用户设置。您将看到已经编写的示例设置。
use DarkGhostHunter\Laraconfig\Facades\Setting; Setting::name('color')->string();
创建设置
要创建设置,请使用 Setting 门面。您可以从设置名称开始,该名称必须是唯一的,然后声明类型。
use DarkGhostHunter\Laraconfig\Facades\Setting; Setting::name('dark_mode')->boolean();
Laraconfig 与 7 种类型的设置兼容,反映了它们的 PHP 本地类型,以及 Collection 和 Datetime(Carbon)对象。
array()boolean()collection()datetime()float()integer()string()
数组和集合在数据库中作为 JSON 序列化。
默认值
所有设置都默认为 null,但您可以使用 default() 方法设置不同的初始值。
use DarkGhostHunter\Laraconfig\Facades\Setting; Setting::name('color')->string()->default('black');
您可以使用
setDefault()将值还原到默认值。
启用或禁用
默认情况下,所有设置都默认启用,但您可以使用disabled()来更改此设置。
Setting::name('color')->disabled();
启用或禁用是表示性的;禁用的设置仍然可以更新。您可以使用
setIfEnabled()来程序化地设置值。
分组设置
您可以为设置设置一个组名。当您希望在前端按顺序显示设置并通过分组来分离它们时,这可能很有用。
Setting::name('color')->group('theme');
包
当Laraconfig迁移新的设置时,这些设置会创建到所有模型中。您可以通过“包”来过滤一组设置。
默认情况下,所有设置都在users包下创建,但您可以使用bag()方法更改任何内容的默认包。
Setting::name('color')->group('theme')->bag('style'); Setting::name('notify_email')->boolean()->default(true)->bag('notifications'); Setting::name('notify_sms')->boolean()->default(false)->bag('notifications');
稍后,在您的模型中,您可以使用filterBags()过滤您想要与之交互的包。
迁移设置
创建完设置后,您应该使用settings:migrate让Laraconfig将设置元数据添加到您的数据库中。
php artisan settings:migrate
在幕后,Laraconfig会查看您的模型,以查找使用HasConfig特质的模型,并根据清单上的信息相应地填充设置。
迁移只执行正向。一旦执行完成,就无法回滚迁移。在生产环境中,删除设置需要确认。
添加新设置
只需创建一个新的设置并运行settings:migrate即可。现有的设置不会再次创建,因为Laraconfig会在执行之前检查它们的存在。
use DarkGhostHunter\Laraconfig\Facades\Setting; Setting::name('color')->string()->default('black'); // This new setting will be created Setting::name('notifications')->boolean()->default(true);
删除旧设置
要删除旧设置,只需删除它们的声明并运行settings:migrate。Laraconfig将比较声明的设置和数据库中创建的设置,并在迁移执行结束时删除那些在清单中不再存在的设置。
use DarkGhostHunter\Laraconfig\Facades\Setting; // Commenting this line will remove the "color" setting on migration. // Setting::name('color')->string()->default('black'); // This new setting will be created Setting::name('notifications')->boolean()->default(true);
由于此过程可能很危险,生产环境需要确认。
升级设置
您不需要直接进入数据库来更新设置。相反,只需在清单中直接更改设置属性。Laraconfig将相应地更新元数据。
假设我们有一个“颜色”设置,我们希望将其从字符串更新为颜色数组和默认值及组。
Setting::name('color')->string()->bag('theme'); // This is the new declaration. // Setting::name('color') // ->array() // ->default(['black']) // ->group('theme');
Laraconfig将检测到新更改,并更新元数据,同时保持用户的值不变。
// This is the old declaration. // Setting::name('color')->string()->bag('theme'); Setting::name('color') ->array() ->default(['black']) ->group('theme');
只有在迁移时间设置与之前不同时,才会执行更新。
完成操作后,我们可以使用settings:migrate将旧设置迁移到新设置。用户将保留他们之前相同的设置值,但如果…我们想要更改每个用户的值怎么办?我们可以使用using()方法将每个用户的设置传递到回调,该回调将返回新值。
Setting::name('color') ->array() ->default('black') ->group('theme') ->using(fn ($old) => $old->value ?? 'black'); // If the value is null, set it as "black".
只有当设置在迁移时间与之前不同时,
using()方法才会运行。
在幕后,Laraconfig 会查找 "color" 设置,更新元数据,然后使用一个 lazy() 查询 来通过回调更新值。
如果您有数十万条记录,建议直接在数据库上迁移,因为这个过程比直接 SQL 语句更安全但更慢。
迁移到新设置
在其他情况下,您可能希望将设置迁移到完全新的设置。在两种情况下,您都可以使用 from() 来获取要迁移的旧设置值,如果您还想更新每个用户的值,可以使用 using()。
以上述相同示例为例,我们将 "color" 设置迁移到简单的 "dark theme" 设置。
// This old declaration will be deleted after the migration ends. // Setting::name('color')->string()->bag('theme'); // This is a new setting. Setting::name('dark') ->boolean() ->default(false) ->group('theme') ->from('color') ->using(static fn ($old) => $old->value === 'black'); // If it's black, then it's dark.
只有当旧设置在迁移时存在时,
from和using才会执行。
在幕后,Laraconfig 首先创建新的 "theme" 设置,然后在数据库中查找旧的 "color" 设置以将旧值转换为新值。由于旧设置不在配置文件中,它将从数据库中删除。
管理设置
Laraconfig 以类似于任何 Eloquent Morph-Many Relationship 的方式处理设置,但功能更强大。
只需在您的模型上使用 settings 属性。这个属性就像您的正常 Eloquent Collection,因此您可以访问所有工具。
$user = User::find(1); echo "Your color is: {$user->settings->get('color')}.";
建议使用
settings,因为它只会加载一次设置。
初始化
默认情况下,HasConfig 特性会在通过 Eloquent ORM 成功创建用户后,在数据库中创建一个新的设置包,因此您不需要创建任何设置。
如果您想手动处理初始化,可以使用 shouldInitializeConfig() 方法并返回 false,这在程序化初始化设置时非常有用。
// app/Models/User.php /** * Check if the user should initialize settings automatically after creation. * * @return bool */ protected function shouldInitializeConfig(): bool { // Don't initialize the settings if the user is not verified from the start. // We will initialize them only once the email is properly verified. return null !== $this->email_verified_at; }
由于示例中的用户不会进行初始化,我们必须手动使用 initialize() 来执行它。
// Initialize if not initialized before. $user->settings()->initialize(); // Forcefully initialize, even if already initialized. $user->settings()->initialize(true);
检查设置初始化
您可以使用 isInitialized() 检查用户配置是否已初始化。
if ($user->settings()->isInitialized()) { return 'You have a config!'; }
检索设置
您可以使用名称轻松获取设置的值,这使得一切都变成了一个美丽的 单行代码。
return "Your favorite color is {$user->settings->color}";
由于这仅支持字母数字和下划线字符,您可以使用 value()。
return "Your favorite color is {$user->settings->value('color')}";
您还可以使用 get() 获取底层 Setting 模型。如果设置不存在,它将返回 null。
$setting = $user->settings->get('theme'); echo "You're using the [$setting->value] theme.";
由于 settings 是一个 collection,您可以访问所有的好处,如迭代。
foreach ($user->settings as $setting) { echo "The [$setting->name] has the [$setting->value] value."; }
您还可以使用 only() 方法通过名称返回设置集合,或使用 except() 获取除指定的设置之外的所有设置。
$user->settings->only('colors', 'is_dark'); $user->settings->except('dark_mode');
分组设置
由于设置列表是一个集合,您可以使用 groups() 方法按所属组的名称对它们进行分组。
$user->settings->groups(); // or ->groupBy('group')
请注意,设置默认情况下会被分组到
default组(没有双关语)。
设置值
通过发出设置名称和值,可以轻松设置值。
$user->settings->color = 'red';
由于此功能仅支持由字母数字和下划线组成的设置名称,因此您还可以通过发出设置名称来使用 set() 方法设置值。
$user->settings->set('color-default', 'red');
或者,您可以直接在模型本身中进入纯粹模式。
$setting = $user->settings->get('color'); $setting->value = 'red'; $setting->save();
当使用 set() 一次设置多个设置时,可以使用数组,这在处理 验证返回的数组 时非常有用。
$user->settings->set([ 'color' => 'red', 'dark_mode' => false, ]);
当 使用缓存 时,任何更改都会立即使缓存无效,并在垃圾回收之前排队生成。
但是,直接将设置更新到数据库中 不会重新生成缓存。
默认设置
您可以使用设置实例上的 setDefault() 或使用 settings 属性,将设置还原到默认值。
$setting = $user->settings->get('color'); $setting->setDefault(); $user->settings->setDefault('color');
如果设置没有默认值,则将使用
null。
检查是否为 null
使用 isNull() 和设置名称检查是否设置了 null 值。
if ($user->settings->isNull('color')) { return 'The color setting is not set.'; }
禁用/启用设置
出于展示目的,所有设置默认都是启用的。您可以使用 enable() 和 disable() 分别启用或禁用设置。要检查设置是否启用,请使用 isEnabled() 方法。
$user->settings->enable('color'); $user->settings->disable('color');
即使禁用设置也可以设置它。如果您只想在启用时设置值,请使用
setIfEnabled()。$user->settings->setIfEnabled('color', 'red');
设置包
Laraconfig 使用一个名为 default 的单一包。如果您在清单中声明了不同的包集 , 您可以使用 filterBags() 方法创建一个仅使用特定包集的模型,该方法应返回包名称(或名称)。
// app/Models/User.php
i
上述方法将在从数据库检索设置时应用筛选器。这使得在用户具有不同的角色或属性或以编程方式时轻松交换包。
所有 设置都为具有
HasConfig特性的所有模型创建,而不管模型使用的包是什么。
禁用包筛选器作用域
Laraconfig 对查询应用筛选器以排除不在模型包中的设置。虽然这简化了开发,但有时您将想要使用所有可用的设置集。
有两种方法可以禁用包筛选器。第一种方法相对简单:只需在查询时间使用 withoutGlobalScope() 即可,这将允许查询用户可用的所有设置。
use DarkGhostHunter\Laraconfig\Eloquent\Scopes\FilterBags; $allSettings = $user->settings()->withoutGlobalScope(FilterBags::class)->get();
如果您想要一个更 永久 的解决方案,只需在模型中使用 filterBags() 方法时返回空数组或 null,这将完全禁用作用域。
/** * Returns the bags this model uses for settings. * * @return array|string */ public function filterBags(): array|string|null { return null; }
缓存
每次请求都击中数据库以检索用户设置可能会产生负面影响,如果您预计会经常发生这种情况。为了避免这种情况,您可以激活一个缓存,每次设置更改时都会重新生成。
缓存实现避免了数据竞争。它只为最后更改的数据重新生成缓存,所以如果有两个或更多进程尝试将某些内容保存到缓存中,只有最新的数据会被持久化。
启用缓存
您可以使用将 LARACONFIG_CACHE 环境变量设置为 true 的方式轻松启用缓存,并使用非默认缓存存储(如 Redis)的 LARACONFIG_STORE。
LARACONFIG_CACHE=true
LARACONFIG_STORE=redis
或者,检查
laraconfig.php文件以自定义缓存 TTL 和前缀。
管理缓存
您可以使用 regenerate() 强制重新生成单个用户的缓存。这基本上是将现有的设置保存到缓存中。
$user->settings->regenerate();
您还可以使用 invalidate() 使缓存的设置失效,这将仅从缓存中删除条目。
$user->settings->invalidate();
最后,您可以将 regeneratesOnExit 设置为 true 以获得一丝安心,这样当设置被 PHP 进程垃圾回收时,将会重新生成缓存。
$user->settings->regeneratesOnExit = true;
您可以在配置文件中禁用自动重新生成。
迁移时重新生成缓存
如果 缓存已激活,迁移将在完成后为每个用户使设置缓存失效。
根据缓存系统,忘记每个缓存键可能会产生负面影响。相反,您可以使用 --flush-cache 命令来刷新 Laraconfig 所使用的缓存存储,而不是逐个删除每个键。
php artisan settings:migrate --flush-cache
由于这将删除缓存的所有数据,建议为 Laraconfig 使用专用的缓存存储,如单独的 Redis 数据库。
验证
设置值将被 强制转换为 类型,但不会进行验证。您应该在应用程序中验证您计划存储在设置中的每个值。
use App\Models\User; use Illuminate\Http\Request; public function store(Request $request, User $user) { $settings = $request->validate([ 'age' => 'required|numeric|min:14|max:100', 'color' => 'required|string|in:red,green,blue' ]); $user->settings->setIfEnabled($settings); // ... }
测试
最终,您将面临为每个创建的用户创建设置和元数据的问题。除非您已禁用 初始化,否则您可以在创建用户之前轻松地将元数据直接存储到数据库中。
public function test_user_has_settings(): void { Metadata::forceCreate([ 'name' => 'foo', 'type' => 'string', 'default' => 'bar', 'bag' => 'users', 'group' => 'default', ]); $user = User::create([ // ... ]); // ... }
安全性
如果您发现任何与安全相关的问题,请通过电子邮件发送至 darkghosthunter@gmail.com,而不是使用问题跟踪器。
许可
MIT 许可证 (MIT)。有关更多信息,请参阅 许可文件。