Files
SkinbaseNova/app/Http/Controllers/Api/ArtworkNavigationController.php
klevze 437d943827 Prefetch artwork prev/next navigation off the critical path.
Move neighbor lookup into a dedicated service and let the viewer load adjacent artworks after first paint instead of blocking the detail request.
2026-08-29 12:25:49 +02:00

87 lines
2.6 KiB
PHP

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Resources\ArtworkResource;
use App\Models\Artwork;
use App\Services\ArtworkNavigationService;
use App\Services\ThumbnailPresenter;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ArtworkNavigationController extends Controller
{
public function __construct(private readonly ArtworkNavigationService $navigation) {}
/**
* GET /api/artworks/navigation/{id}
*
* Returns prev/next published artworks by the same author.
*/
public function neighbors(int $id): JsonResponse
{
$artwork = Artwork::published()
->select(['id', 'user_id', 'title', 'slug'])
->find($id);
if (! $artwork) {
return response()->json([
'prev_id' => null, 'next_id' => null,
'prev_url' => null, 'next_url' => null,
'prev_slug' => null, 'next_slug' => null,
'prev_preview' => null, 'next_preview' => null,
]);
}
return response()->json($this->navigation->navigationFor($artwork));
}
/**
* GET /api/artworks/{id}/page
*
* Returns full artwork resource by numeric ID for client-side (no-reload) navigation.
*/
public function pageData(Request $request, int $id): JsonResponse
{
if ($request->boolean('prefetch')) {
return $this->prefetchData($id);
}
$artwork = Artwork::with(['user.profile', 'categories.contentType', 'categories.parent.contentType', 'tags', 'stats'])
->published()
->find($id);
if (! $artwork) {
return response()->json(['error' => 'Not found'], 404);
}
$resource = (new ArtworkResource($artwork))->toArray(request());
$resource['navigation'] = $this->navigation->navigationFor($artwork);
return response()->json($resource);
}
private function prefetchData(int $id): JsonResponse
{
$artwork = Artwork::query()
->published()
->select(['id', 'title', 'slug', 'hash', 'file_path', 'file_name'])
->find($id);
if (! $artwork) {
return response()->json(['error' => 'Not found'], 404);
}
return response()->json([
'id' => (int) $artwork->id,
'title' => (string) $artwork->title,
'slug' => (string) $artwork->slug,
'thumbs' => [
'md' => ThumbnailPresenter::present($artwork, 'md'),
'lg' => ThumbnailPresenter::present($artwork, 'lg'),
],
]);
}
}