*/ use HasFactory, Notifiable; /** * Get the attributes that should be cast. * * @return array */ protected function casts(): array { return [ 'email_verified_at' => 'datetime', 'password' => 'hashed', 'extra_permissions' => 'array', 'excluded_permissions' => 'array', ]; } public function roleTemplate() { return $this->belongsTo(RoleTemplate::class); } /** * Tính toán effective permissions từ role template + extra - excluded. * Cache trong session (1 lần/login). */ public function getEffectivePermissions(): array { $cacheKey = "user.{$this->id}.permissions"; if (session()->has($cacheKey)) { return session()->get($cacheKey); } $permissions = $this->calculateEffectivePermissions(); session()->put($cacheKey, $permissions); return $permissions; } public function hasEffectivePermission(string $permission): bool { return in_array($permission, $this->getEffectivePermissions()); } public function clearPermissionCache(): void { session()->forget("user.{$this->id}.permissions"); } protected function calculateEffectivePermissions(): array { $templatePerms = []; if ($this->roleTemplate) { $templatePerms = $this->roleTemplate->permissions ?? []; } // Flatten template permissions từ {"contracts":["view","create"]} thành ["contracts.view","contracts.create"] $templateFlat = []; foreach ($templatePerms as $module => $actions) { foreach ($actions as $action) { $templateFlat[] = "{$module}.{$action}"; } } $extra = $this->extra_permissions ?? []; $excluded = $this->excluded_permissions ?? []; return array_values(array_diff( array_unique(array_merge($templateFlat, $extra)), $excluded )); } /** * Override can() để tích hợp với Laravel Authorization. * Nếu ability là dạng "contracts.view" → dùng effective permissions. * Ngược lại fallback về parent. */ public function can($abilities, $arguments = []): bool { if (is_string($abilities) && str_contains($abilities, '.')) { return $this->hasEffectivePermission($abilities); } return parent::can($abilities, $arguments); } public function canAccessPanel(Panel $panel): bool { return true; } }