minor fixes
This commit is contained in:
@@ -9,6 +9,7 @@ use App\Models\Tag;
|
||||
use App\Services\EarlyGrowth\AdaptiveTimeWindow;
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* High-level search API powered by Meilisearch via Laravel Scout.
|
||||
@@ -19,6 +20,7 @@ final class ArtworkSearchService
|
||||
{
|
||||
private const BASE_FILTER = 'is_public = true AND is_approved = true';
|
||||
private const CACHE_TTL = 300; // 5 minutes
|
||||
private const TAG_SORTS = ['popular', 'likes', 'latest', 'downloads'];
|
||||
|
||||
public function __construct(
|
||||
private readonly AdaptiveTimeWindow $timeWindow,
|
||||
@@ -82,22 +84,46 @@ final class ArtworkSearchService
|
||||
/**
|
||||
* Load artworks for a tag page, sorted by views + likes descending.
|
||||
*/
|
||||
public function byTag(string $slug, int $perPage = 24): LengthAwarePaginator
|
||||
public function byTag(string $slug, int $perPage = 24, string $sort = 'popular'): LengthAwarePaginator
|
||||
{
|
||||
$tag = Tag::where('slug', $slug)->first();
|
||||
if (! $tag) {
|
||||
return $this->emptyPaginator($perPage);
|
||||
}
|
||||
|
||||
$cacheKey = "search.tag.{$slug}.page." . request()->get('page', 1);
|
||||
$sort = in_array($sort, self::TAG_SORTS, true) ? $sort : 'popular';
|
||||
$cacheKey = "search.tag.{$slug}.{$sort}.{$perPage}.page." . request()->get('page', 1);
|
||||
|
||||
return Cache::remember($cacheKey, self::CACHE_TTL, function () use ($slug, $perPage) {
|
||||
return Artwork::search('')
|
||||
->options([
|
||||
'filter' => self::BASE_FILTER . ' AND tags = "' . addslashes($slug) . '"',
|
||||
'sort' => ['views:desc', 'likes:desc'],
|
||||
])
|
||||
->paginate($perPage);
|
||||
return Cache::remember($cacheKey, self::CACHE_TTL, function () use ($tag, $perPage, $sort) {
|
||||
$query = Artwork::query()
|
||||
->public()
|
||||
->published()
|
||||
->whereHas('tags', fn ($tagQuery) => $tagQuery->where('tags.id', $tag->id))
|
||||
->leftJoin('artwork_stats', 'artwork_stats.artwork_id', '=', 'artworks.id')
|
||||
->select('artworks.*')
|
||||
->with(['user.profile', 'categories.contentType']);
|
||||
|
||||
match ($sort) {
|
||||
'likes' => $query
|
||||
->orderByRaw('COALESCE(artwork_stats.favorites, 0) DESC')
|
||||
->orderByRaw('COALESCE(artwork_stats.views, 0) DESC')
|
||||
->orderByDesc('artworks.published_at'),
|
||||
'latest' => $query
|
||||
->orderByDesc('artworks.published_at')
|
||||
->orderByDesc('artworks.id'),
|
||||
'downloads' => $query
|
||||
->orderByRaw('COALESCE(artwork_stats.downloads, 0) DESC')
|
||||
->orderByRaw('COALESCE(artwork_stats.views, 0) DESC')
|
||||
->orderByDesc('artworks.published_at'),
|
||||
default => $query
|
||||
->orderByRaw('COALESCE(artwork_stats.views, 0) DESC')
|
||||
->orderByRaw('COALESCE(artwork_stats.favorites, 0) DESC')
|
||||
->orderByDesc('artworks.published_at'),
|
||||
};
|
||||
|
||||
return $query
|
||||
->paginate($perPage)
|
||||
->withQueryString();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -125,12 +151,12 @@ final class ArtworkSearchService
|
||||
* Used by categoryPageSort() and contentTypePageSort().
|
||||
*/
|
||||
private const CATEGORY_SORT_FIELDS = [
|
||||
'trending' => ['trending_score_24h:desc', 'created_at:desc'],
|
||||
'fresh' => ['created_at:desc'],
|
||||
'trending' => ['trending_score_24h:desc', 'published_at_ts:desc'],
|
||||
'fresh' => ['published_at_ts:desc'],
|
||||
'top-rated' => ['awards_received_count:desc', 'favorites_count:desc'],
|
||||
'favorited' => ['favorites_count:desc', 'trending_score_24h:desc'],
|
||||
'downloaded' => ['downloads_count:desc', 'trending_score_24h:desc'],
|
||||
'oldest' => ['created_at:asc'],
|
||||
'oldest' => ['published_at_ts:asc'],
|
||||
];
|
||||
|
||||
/** Cache TTL (seconds) per sort alias for category pages. */
|
||||
@@ -237,7 +263,7 @@ final class ArtworkSearchService
|
||||
}
|
||||
|
||||
/**
|
||||
* Most recent artworks by created_at.
|
||||
* Most recent artworks by publish timestamp.
|
||||
*/
|
||||
public function recent(int $perPage = 24): LengthAwarePaginator
|
||||
{
|
||||
@@ -245,7 +271,7 @@ final class ArtworkSearchService
|
||||
return Artwork::search('')
|
||||
->options([
|
||||
'filter' => self::BASE_FILTER,
|
||||
'sort' => ['created_at:desc'],
|
||||
'sort' => ['published_at_ts:desc'],
|
||||
])
|
||||
->paginate($perPage);
|
||||
});
|
||||
@@ -294,7 +320,7 @@ final class ArtworkSearchService
|
||||
return Artwork::search('')
|
||||
->options([
|
||||
'filter' => self::BASE_FILTER . ' AND created_at >= "' . $cutoff . '"',
|
||||
'sort' => ['heat_score:desc', 'engagement_velocity:desc', 'created_at:desc'],
|
||||
'sort' => ['heat_score:desc', 'engagement_velocity:desc', 'published_at_ts:desc'],
|
||||
])
|
||||
->paginate($perPage);
|
||||
});
|
||||
@@ -310,7 +336,7 @@ final class ArtworkSearchService
|
||||
return Artwork::search('')
|
||||
->options([
|
||||
'filter' => self::BASE_FILTER,
|
||||
'sort' => ['created_at:desc'],
|
||||
'sort' => ['published_at_ts:desc'],
|
||||
])
|
||||
->paginate($perPage);
|
||||
});
|
||||
@@ -378,7 +404,7 @@ final class ArtworkSearchService
|
||||
}
|
||||
|
||||
/**
|
||||
* Fresh artworks in given categories, sorted by created_at desc.
|
||||
* Fresh artworks in given categories, sorted by publish timestamp desc.
|
||||
* Used for personalized "Fresh in your favourite categories" section.
|
||||
*
|
||||
* @param string[] $categorySlugs
|
||||
@@ -400,7 +426,7 @@ final class ArtworkSearchService
|
||||
return Artwork::search('')
|
||||
->options([
|
||||
'filter' => self::BASE_FILTER . ' AND (' . $catFilter . ')',
|
||||
'sort' => ['created_at:desc'],
|
||||
'sort' => ['published_at_ts:desc'],
|
||||
])
|
||||
->paginate($limit);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user