, class-string> */ protected const RESOURCES = [ Page::class => PageResource::class, Project::class => ProjectResource::class, Service::class => ServiceResource::class, ]; public static function url(Model $record): string { $resource = self::RESOURCES[$record::class] ?? null; return $resource ? $resource::getUrl('edit', ['record' => $record]) : url('/admin'); } /** * The permission that decides who can answer a review of this record. * * Derived from the table name, which matches the permission prefix for * every model that has a `publish` ability — the catalogue in * `Permissions::RESOURCES` is keyed the same way, and the unit test over * it is what keeps that true. */ public static function permission(Model $record): string { return $record->getTable().'.publish'; } /** * How many of these are waiting for the person reading the sidebar. * * Cached for a minute because Filament asks every resource for its badge * on every page render, and three counting queries to draw three numbers * would make the whole panel slower — the same reason the health badge is * cached. A minute is well inside the time it takes somebody to notice. * * @param class-string $model */ public static function waitingFor(string $model, ?User $user): ?int { if ($user === null || $user->cannot((new $model)->getTable().'.publish')) { return null; } $count = Cache::remember( "reviews:waiting:{$model}:{$user->getAuthIdentifier()}", now()->addMinute(), fn () => $model::query()->awaitingReviewBy($user)->count(), ); return $count > 0 ? $count : null; } }