PromptVault/app/Services/PromptCatalog.php

67 lines
2.2 KiB
PHP
Raw Permalink Normal View History

2026-10-26 20:12:16 +00:00
<?php
namespace App\Services;
use App\Actions\Prompts\ListPrompts;
use App\Models\Prompt;
use App\Models\Tag;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
/**
* Read side of the prompt domain (queries).
*/
class PromptCatalog
{
public const PER_PAGE = 10;
/**
* Paginated prompt list with search, tag/favorite filters, and
* whitelisted sorting. `last_used_at` keeps NULLs last.
*/
public function list(ListPrompts $query): LengthAwarePaginator
{
$sort = $query->normalizedSort();
$direction = $query->normalizedDirection();
$like = '%' . $query->search . '%';
return Prompt::query()
->with('tags')
->when(
$query->search !== null && $query->search !== '',
fn (Builder $q) => $q->where(
fn (Builder $w) => $w
->where('name', 'like', $like)
->orWhere('description', 'like', $like)
->orWhere('body', 'like', $like)
),
)
->when(
$query->tag !== null && $query->tag !== '',
fn (Builder $q) => $q->whereHas('tags', fn (Builder $t) => $t->where('name', $query->tag)),
)
->when($query->favoritesOnly, fn (Builder $q) => $q->where('is_favorite', true))
->when(
$sort === 'last_used_at',
// NULLs always sort last: `IS NULL` is 0/1, so a first
// ascending pass groups non-NULLs before NULLs in either
// direction, then the value itself orders within the group.
fn (Builder $q) => $q
->orderByRaw('last_used_at IS NULL')
->orderBy('last_used_at', $direction),
fn (Builder $q) => $q->orderBy($sort, $direction),
)
->orderBy('id', 'desc')
->paginate(self::PER_PAGE);
}
/**
* All tags, alphabetically (for filter dropdowns).
*/
public function tags(): Collection
{
return Tag::query()->orderBy('name')->get();
}
}