I am building an application that is using lighthouse-php. Because I have constantly set various policies for different users, I constantly query for user model with a role relationship in different parts applications, and for this reason, would want to store the users in the Redis database and query from there instead.
I read couple of articles that I found on the internet such as: laravel-cache-authuser; creating-a-caching-user-provider-for-laravel/; caching-the-laravel-user-provider-with-a-decorator/, reviewed code in here laravel-auth-user, and kind of understood the concept but struggling to understand laravel deep enough to find a suitable solution…
For example, I am struggling to understand how to store User
with Role
relationship inside event method in UserObserver, it’s clear how to do it with one Model but not with a relationship attached.
I had a sense that I should do something like that:
class UserObserver
{
/**
* @param User $user
*/
public function saved(User $user)
{
$user->load('role');
Cache::put("user.$user->id", $user, 60);
}
}
But this way I make 2 calls to the DB, rather than having the relationship pre-loaded. How could I preload the relationship in the events arguments. I tried to add protected $with = ['role']
so that child model/relationship always loaded. But no matter what I make more calls to DB either to retrieve Role or to retrieve User and Role.
He is some simplified code samples from my project lighthouse-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
}
User Model with role relationship:
class User extends Authenticatabl {
public function role(): BelongsTo
{
return $this->belongsTo(Role::class);
}
}
User Policy that is used on some of the graphql type fields:
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 custom Query Class for resolving fields via methods.
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;
}
}
If I make graphql query that looks something like this (please see below) it causes role relationship to be loaded from db, instead of cache.
query {
user {
id
name
role {
id
name
}
}
}
Please help.
3
Answers
you can store your auth user with your relation using Session.
example :
May it help you
You could cache the relationship by creating a custom
accessor
for therole
attribute on theUser
model. An example could be :Alternatively, you can use the
rememberForever()
function to cache it forever. Be aware that you would have to write an implementation to either remove / update the caching manually, as it will hold the value forever. You could create a function that clears the caching like so:Your code in the observer can be updated to the following:
Create a file named "user.php" under "AppConfig" path. File should look like this
Now you can set a config
Then you can read from any file whenever you need this data
This is my solution and i set this config value in middleware, works flawless.