First i want to explain how i arrived here so you know what i'm trying to do, maybe i'm doing things wrong so any advice, or pointing me to a better way to do things will be appericiated.
How i got here:
I was researching on how to best implement my User types and roles and landed on this structure
users table:
| id | emaill | password | name | ...|
user_roles table:
| id | user_id| role_type_id| role_table_id| ...|
and then I have a separate table for each role, role_table_id is the id of the user in that table. for example here is admins table:
| id | user_id| is_super_admin| ...|
then I created my models which includes: User, Admin, Doctor, Farm, UserRole
User.php model:
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable, MyUserRoles;
protected $table = 'users';
protected $with = ['roles'];
private $rolesPostProcessing;
public function __construct($attributes = [])
{
parent::__construct($attributes);
$this->rolesPostProcessing = [
'already_processed' => false,
'is_admin' => false,
'is_doctor' => false,
'is_farm' => false,
];
//TODO: is there a callback to know when $with is loaded to run this there?
// $this->processUserRoles();
}
public function adminDetails()
{
return $this->hasOne(Admin::class);
}
public function farmDetails()
{
return $this->hasOne(Farm::class);
}
public function doctorDetails()
{
return $this->hasOne(Doctor::class);
}
public function roles()
{
return $this->hasMany(UserRole::class);
}
//the rest of functions and vars
}
then i created a trait to do some postProcessing for me and add some helper functions
MyUserRoles.php trait:
trait MyUserRoles
{
public function isAdmin()
{
$this->processUserRoles();
return $this->rolesPostProcessing['is_admin'];
}
public function getAdminId()
{
$this->processUserRoles();
return $this->rolesPostProcessing['admin_id'];
}
public function isDoctor()
{
$this->processUserRoles();
return $this->rolesPostProcessing['is_doctor'];
}
public function getDoctorId()
{
$this->processUserRoles();
return $this->rolesPostProcessing['doctor_id'];
}
public function isFarm()
{
$this->processUserRoles();
return $this->rolesPostProcessing['is_farm'];
}
public function getFarmId()
{
$this->processUserRoles();
return $this->rolesPostProcessing['farm_id'];
}
public function dumpProcessedRoles()
{
$this->processUserRoles();
dump($this->rolesPostProcessing);
}
public function processUserRoles()
{
if ($this->rolesPostProcessing['already_processed'])
return;
foreach ($this->roles as $role) {
switch ($role['role_type_id']) {
case UserRole::Admin->value:
$this->rolesPostProcessing['is_admin'] = true;
$this->rolesPostProcessing['admin_id'] = $role['role_table_id'];
break;
case UserRole::Doctor->value:
$this->rolesPostProcessing['is_doctor'] = true;
$this->rolesPostProcessing['doctor_id'] = $role['role_table_id'];
break;
case UserRole::Farm->value:
$this->rolesPostProcessing['is_farm'] = true;
$this->rolesPostProcessing['farm_id'] = $role['role_table_id'];
break;
}
$this->rolesPostProcessing['role_table_id'] = $role['role_table_id'];
}
$this->rolesPostProcessing['already_processed'] = true;
}
public function loadAdminDetails()
{
$this->load("adminDetails")->get();
}
public function loadDoctorDetails()
{
$this->load("doctorDetails")->get();
}
public function loadFarmDetails()
{
$this->load("doctorDetails")->get();
}
}
The Question:
the code above works fine but if you did not notice im calling $this->processUserRoles()
at the start of evey function :D, so:
- is there any callback for
$with=['roles'] used in User.php model so i can run $this->processUserRoles() there once? i tried but could not figure it out.
- [bonus:] is what i have done generally fine? I can't shake of the feeling that i'm doing it terribly wrong :)
P.S: about roles the thing is a user can be a farm, a admin or a doctor it can also be all at the same time so it's not a 1:1 scenario