classIds($user); return QuestionBank::query() ->where('is_active', true) ->where(function (Builder $query) use ($user, $classIds): void { $query->where('visibility', 'public') ->orWhere('owner_id', $user->id) ->orWhereExists(function ($sub) use ($user): void { $sub->selectRaw('1') ->from('bank_shares') ->whereColumn('bank_shares.question_bank_id', 'question_banks.id') ->where('target_type', 'user') ->where('target_id', $user->id); }) ->orWhereExists(function ($sub) use ($classIds): void { $sub->selectRaw('1') ->from('bank_shares') ->whereColumn('bank_shares.question_bank_id', 'question_banks.id') ->where('target_type', 'class') ->whereIn('target_id', $classIds); }); }); } public function visiblePapersQuery(User $user): Builder { return Paper::query() ->where('is_active', true) ->where(function (Builder $query) use ($user): void { $query->where('owner_id', $user->id) ->orWhereIn('question_bank_id', $this->visibleBanksQuery($user)->select('id')); }); } public function canAccessBank(User $user, QuestionBank $bank): bool { return $this->visibleBanksQuery($user)->whereKey($bank->id)->exists(); } public function canAccessPaper(User $user, Paper $paper): bool { return $this->visiblePapersQuery($user)->whereKey($paper->id)->exists(); } private function classIds(User $user): Collection { return SchoolClass::query() ->whereHas('members', fn (Builder $query) => $query->where('users.id', $user->id)) ->pluck('id'); } }