permissions = $permissions; } /** * Wire a LAZY resolver instead of the instance (see the class docblock for why eager injection * recurses). The engine is resolved on first authorize()/can(). */ public function setPermissionServiceResolver(\Closure $resolver): void { $this->permissionServiceResolver = $resolver; } /** Resolve the engine, preferring a directly-set instance (tests) then the lazy resolver. */ private function permissionService(): PermissionService { if ($this->permissions === null) { if ($this->permissionServiceResolver === null) { throw new \LogicException(static::class.' has no PermissionService: it was neither resolved through the container nor wired in a test.'); } $this->permissions = ($this->permissionServiceResolver)(); } return $this->permissions; } /** * Authorize the current user for a `domain.action` permission or throw. Replaces the * silent `return false` pattern — a denial becomes an * {@see \Leantime\Core\Exceptions\AuthorizationException} (403 web / RPC -32001). * * @throws \Leantime\Core\Exceptions\AuthorizationException */ protected function authorize(string $permission, ?int $projectId = null, ?bool $forceGlobal = null): void { $this->permissionService()->authorize($permission, $projectId, $forceGlobal); } /** Non-throwing capability check, for branching. */ protected function can(string $permission, ?int $projectId = null, ?bool $forceGlobal = null): bool { return $this->permissionService()->currentUserCan($permission, $projectId, $forceGlobal); } /** The authenticated user's id, or null when there is no session user. */ protected function currentUserId(): ?int { $id = session('userdata.id'); return ($id === null || $id === '') ? null : (int) $id; } /** * Validate input against Laravel rules, returning the validated (whitelisted) subset or * throwing a {@see ValidationException} (422 web / RPC -32602 with field errors). Works * identically whether input arrived via a controller or JSON-RPC. * * @param array $data * @param array $rules * @param array $messages * @return array * * @throws ValidationException */ protected function validate(array $data, array $rules, array $messages = []): array { return ValidationException::validate($data, $rules, $messages); } }