我正在构建一个使用灯塔php的应用程序。因为我经常为不同的用户设置各种策略,所以我经常在不同的部分应用程序中查询具有角色关系的用户模型,因此,我想将用户存储在Redis数据库中,然后从那里进行查询。我在网上读了几篇文章,比如:laravel缓存authuser;creating-a-caching-user-provider-for-laravel/;caching-the-laravel-user-provider-with-a-decorator/,在这里查看了laravel-auth-user中的代码,有点理解这个概念,但很难深入理解laravel以找到合适的解决方案。。。
例如,我很难理解如何在UserObserver的事件方法中存储具有Role
关系的User
,很清楚如何使用一个Model而不使用附加的关系。
我有一种感觉,我应该做这样的事情:
class UserObserver
{
/**
* @param User $user
*/
public function saved(User $user)
{
$user->load('role');
Cache::put("user.$user->id", $user, 60);
}
}
但通过这种方式,我对DB进行了两次调用,而不是预先加载关系。我如何在events参数中预加载关系。我尝试添加protected $with = ['role']
,以便始终加载子模型/关系。但无论怎样,我都会对DB进行更多的调用,以检索Role或检索User和Role。
他是我的灯塔php项目中的一些简化代码示例。
schema.graphql:
type SomeType {
someMethod(args: [String!]): [Model!] @method @can(ability: "isAdmin", model: "App\Models\User")
}
type User {
id: ID
name: String
role: Role @belongsTo
}
type Role {
id: ID!
name: String!
label: String!
users: [User!] @hasMany
}
具有角色关系的用户模型:
class User extends Authenticatabl {
public function role(): BelongsTo
{
return $this->belongsTo(Role::class);
}
}
在一些graphql类型字段上使用的用户策略:
class UserPolicy
{
use HandlesAuthorization;
public function isAdmin(): Response
{
$user = auth()->user();
return $user->role->name === 'admin'
? $this->allow()
: $this->deny('permission denied');
}
public function isManager(): Response
{
$user = auth()->user();
$this->allow();
return $user->role->name === 'manager' || $user->role->name === 'admin'
? $this->allow()
: $this->deny('Permission Denied');
}
}
Lighouse自定义查询类,用于通过方法解析字段。
class SomeType {
public function someMethod(): string
{
// this triggers db call rather than receiving `role->name` from redis along with user
return auth()->user()->role->name;
}
}
如果我创建的graphql查询看起来像这样(请参阅下面(,它会导致从数据库而不是缓存加载角色关系。
query {
user {
id
name
role {
id
name
}
}
}
Please help.
您可以通过为User
模型上的role
属性创建自定义accessor
来缓存关系。例如:
<?php
use IlluminateSupportFacadesCache;
class User extends Authenticatabl {
public function role(): BelongsTo
{
return $this->belongsTo(Role::class);
}
public static function getRoleCacheKey(User $user): string
{
return sprintf('user-%d-role', $user->id);
}
// Define accessor for caching purposes
public function getRoleAttribute(): Collection
{
if ($this->relationLoaded('role')) {
return $this->getRelationValue('role');
}
// Replace 3600 for the amount of seconds you would like to cache
$role = Cache::remember(User::getRoleCacheKey($this), 3600, function () {
return $this->getRelationValue('role');
});
$this->setRelation('role', $role);
return $role;
}
}
或者,您可以使用rememberForever()
函数永久缓存它。请注意,您必须编写一个实现来手动删除/更新缓存,因为它将永远保持该值。您可以创建一个清除缓存的函数,如下所示:
// In User model
public static function forgetRoleCaching(User $user): bool
{
return Cache::forget(sprintf(User::getRoleCacheKey($user));
}
您在观察者中的代码可以更新为以下内容:
class UserObserver
{
/**
* @param User $user
*/
public function saved(User $user)
{
// in case user role is cached forever
User::forgetRoleCaching($user);
$user->load('role'); // will trigger the accessor an should cache again
Cache::put("user.$user->id", $user, 60);
}
}
您可以使用Session存储您的身份验证用户和您的关系。
示例:
$auth = Auth::User();
Session::put('user',$auth);
Session::put('relation',$auth->relation);
希望它能帮助你
创建一个名为"user.php";在";App\Config"路径文件应该像这个
<?php
return [
'role' => ''
];
现在你可以设置一个配置
config(['user.role' => $example_role]);
然后你可以从任何文件中读取,只要你需要这个数据
config('user.role');
这是我的解决方案,我在中间件中设置了这个配置值,工作完美。