mralston / laraconfig
Laravel的按用户设置仓库系统
Requires
- php: >=8.0
- illuminate/cache: ^8.43|^9.0|^10.0|^11.0
- illuminate/collections: ^8.43|^9.0|^10.0|^11.0
- illuminate/config: ^8.43|^9.0|^10.0|^11.0
- illuminate/database: ^8.43|^9.0|^10.0|^11.0
- illuminate/support: ^8.43|^9.0|^10.0|^11.0
- symfony/console: ^6.0|^7.0
Requires (Dev)
- mockery/mockery: ^1.4.3
- orchestra/testbench: ^7.24
- phpunit/phpunit: ^9.5.4
README
Laraconfig
Laravel的按用户设置仓库系统。
此包允许用户拥有可以查询、更改甚至更新的设置,轻松且快速。
User::find(1)->settings->set('color', 'red');
要求
- Laravel 8.x -> 10.x
- PHP 8.0或更高版本
工作原理
Laraconfig通过扩展Laravel关系工作,并包括一个迁移系统来轻松管理。
每个设置只是一个值,它引用一个包含类型和名称等信息并链接到用户的父"元数据"。
由于Laraconfig在幕后使用Eloquent ORM,因此获取一个或所有设置对开发者来说是完全透明的。
快速入门
您可以通过composer安装此包。
composer require mralston/laraconfig
首先,发布并运行迁移。这些将添加两个名为user_settings
和user_settings_metadata
的表。一个存储每个用户的值,另一个存储设置的元数据。
php artisan vendor:publish --provider="Mralston\Laraconfig\LaraconfigServiceProvider" --tag="migrations"
php artisan migrate
迁移使用形态列来连接到用户。您可以在迁移之前更改它。
其次,将HasConfig
特性添加到您想要具有设置的User模型中。
namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use Mralston\Laraconfig\HasConfig; class User extends Authenticatable { use HasConfig; // ... }
最后,使用settings:publish
artisan命令。这将创建一个位于项目根目录的settings
文件夹和一个users.php
文件。
php artisan settings:publish
现在,让我们创建一些设置。
设置清单
Laraconfig通过一种类似清单的方式管理用户设置,使用settings/users.php
文件。您将看到一个已编写的示例设置。
use Mralston\Laraconfig\Facades\Setting; Setting::name('color')->string();
创建设置
要创建设置,请使用Setting
外观。您可以开始设置名称,该名称必须是唯一的,然后声明类型。
use Mralston\Laraconfig\Facades\Setting; Setting::name('dark_mode')->boolean();
Laraconfig与7种类型的设置兼容,这些类型与PHP原生类型相同,包括集合和DateTime(Carbon)对象。
array()
boolean()
collection()
datetime()
float()
integer()
string()
数组和集合在数据库中以JSON序列化。
默认值
所有设置都有一个默认值null
,但您可以使用default()
方法设置不同的初始值。
use Mralston\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 Mralston\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 Mralston\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 将相应地更新元数据。
假设我们有一个我们希望从字符串更新为包含默认值和组的颜色数组的 "color" 设置。
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" 设置迁移到简单的 "深色主题" 设置。
// 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 关系 一样,但更加强大。
只需简单地使用模型上的settings
属性。这个属性就像你正常的Eloquent Collection,因此你可以访问所有其工具。
$user = User::find(1); echo "Your color is: {$user->settings->get('color')}.";
使用
settings
是首选的,因为它只会加载一次设置。
初始化
默认情况下,通过Eloquent ORM成功创建用户后,HasConfig
特性将在数据库中创建一个新的设置包,因此你不需要创建任何设置。
如果你想要手动处理初始化,可以使用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()
来获取底层的设置模型。如果设置不存在,它将返回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 Mralston\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)。有关更多信息,请参阅许可证文件。