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.
This commit is contained in:
2026-08-29 12:25:49 +02:00
parent bf902f509a
commit 437d943827
7 changed files with 430 additions and 45 deletions
+70
View File
@@ -0,0 +1,70 @@
<?php
namespace App\Services;
use App\Models\Artwork;
use Illuminate\Support\Str;
final class ArtworkNavigationService
{
/**
* Build the public previous/next navigation payload for an already loaded
* current artwork. No current-artwork lookup is performed here.
*/
public function navigationFor(Artwork $artwork): array
{
$scope = Artwork::published()
->select(['id', 'title', 'slug', 'hash', 'file_path', 'file_name'])
->where('user_id', $artwork->user_id);
$prev = (clone $scope)->where('id', '<', $artwork->id)->orderByDesc('id')->first();
$next = (clone $scope)->where('id', '>', $artwork->id)->orderBy('id')->first();
if (! $prev) {
$prev = (clone $scope)->where('id', '!=', $artwork->id)->orderByDesc('id')->first();
}
if (! $next) {
$next = (clone $scope)->where('id', '!=', $artwork->id)->orderBy('id')->first();
}
$prevSlug = $this->canonicalSlug($prev);
$nextSlug = $this->canonicalSlug($next);
return [
'prev_id' => $prev?->id,
'next_id' => $next?->id,
'prev_url' => $prev ? url('/art/'.$prev->id.'/'.$prevSlug) : null,
'next_url' => $next ? url('/art/'.$next->id.'/'.$nextSlug) : null,
'prev_slug' => $prevSlug,
'next_slug' => $nextSlug,
'prev_preview' => $this->preview($prev),
'next_preview' => $this->preview($next),
];
}
private function canonicalSlug(?Artwork $artwork): ?string
{
if (! $artwork) {
return null;
}
return Str::slug($artwork->slug ?: $artwork->title) ?: (string) $artwork->id;
}
private function preview(?Artwork $artwork): ?array
{
if (! $artwork) {
return null;
}
return [
'id' => (int) $artwork->id,
'title' => (string) $artwork->title,
'slug' => (string) $artwork->slug,
'thumbs' => [
'md' => ThumbnailPresenter::present($artwork, 'md'),
'lg' => ThumbnailPresenter::present($artwork, 'lg'),
],
];
}
}