Files
SkinbaseNova/app/Http/Controllers/Api/Posts/PostSearchController.php

93 lines
3.4 KiB
PHP

<?php
namespace App\Http\Controllers\Api\Posts;
use App\Http\Controllers\Controller;
use App\Models\Post;
use App\Services\Posts\PostFeedService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
/**
* GET /api/feed/search?q=...
*
* Searches posts body + hashtags via Meilisearch (Laravel Scout).
* Falls back to a simple LIKE query if Scout is unavailable.
*/
class PostSearchController extends Controller
{
public function __construct(private PostFeedService $feedService) {}
public function search(Request $request): JsonResponse
{
$request->validate([
'q' => ['required', 'string', 'min:2', 'max:100'],
'page' => ['nullable', 'integer', 'min:1'],
]);
$query = trim($request->input('q'));
$page = max(1, (int) $request->query('page', 1));
$perPage = 20;
$viewerId = $request->user()?->id;
// Scout search (Meilisearch)
try {
$results = Post::search($query)
->where('visibility', Post::VISIBILITY_PUBLIC)
->where('status', Post::STATUS_PUBLISHED)
->paginate($perPage, 'page', $page);
$results->load($this->feedService->publicEagerLoads());
if ($viewerId) {
$results->getCollection()->loadExists([
'saves as viewer_saved' => fn ($saveQuery) => $saveQuery->where('user_id', $viewerId),
]);
}
$formatted = $results->getCollection()
->map(fn ($post) => $this->feedService->formatPost($post, $viewerId))
->values();
return response()->json([
'data' => $formatted,
'query' => $query,
'meta' => [
'total' => $results->total(),
'current_page' => $results->currentPage(),
'last_page' => $results->lastPage(),
'per_page' => $results->perPage(),
],
]);
} catch (\Exception $e) {
// Fallback: basic LIKE search on body
$paginated = Post::with($this->feedService->publicEagerLoads())
->withExists([
'saves as viewer_saved' => fn ($saveQuery) => $saveQuery->where('user_id', $viewerId),
])
->where('status', Post::STATUS_PUBLISHED)
->where('visibility', Post::VISIBILITY_PUBLIC)
->where(function ($q) use ($query) {
$q->where('body', 'like', '%' . $query . '%')
->orWhereHas('hashtags', fn ($hq) => $hq->where('tag', 'like', '%' . mb_strtolower($query) . '%'));
})
->orderByDesc('created_at')
->paginate($perPage, ['*'], 'page', $page);
$formatted = $paginated->getCollection()
->map(fn ($post) => $this->feedService->formatPost($post, $viewerId))
->values();
return response()->json([
'data' => $formatted,
'query' => $query,
'meta' => [
'total' => $paginated->total(),
'current_page' => $paginated->currentPage(),
'last_page' => $paginated->lastPage(),
'per_page' => $paginated->perPage(),
],
]);
}
}
}