optimizations

This commit is contained in:
2026-03-28 19:15:39 +01:00
parent 0b25d9570a
commit cab4fbd83e
509 changed files with 1016804 additions and 1605 deletions

View File

@@ -0,0 +1,117 @@
<?php
declare(strict_types=1);
namespace App\Services;
use App\Models\Collection;
use App\Models\CollectionDailyStat;
use App\Services\ThumbnailPresenter;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
class CollectionAnalyticsService
{
public function snapshot(Collection $collection, ?Carbon $date = null): void
{
$bucket = ($date ?? now())->toDateString();
DB::table('collection_daily_stats')->updateOrInsert(
[
'collection_id' => $collection->id,
'stat_date' => $bucket,
],
[
'views_count' => (int) $collection->views_count,
'likes_count' => (int) $collection->likes_count,
'follows_count' => (int) $collection->followers_count,
'saves_count' => (int) $collection->saves_count,
'comments_count' => (int) $collection->comments_count,
'shares_count' => (int) $collection->shares_count,
'submissions_count' => (int) $collection->submissions()->count(),
'created_at' => now(),
'updated_at' => now(),
]
);
}
public function overview(Collection $collection, int $days = 30): array
{
$rows = CollectionDailyStat::query()
->where('collection_id', $collection->id)
->where('stat_date', '>=', now()->subDays(max(7, $days - 1))->toDateString())
->orderBy('stat_date')
->get();
$first = $rows->first();
$last = $rows->last();
$delta = static fn (string $column): int => max(0, (int) ($last?->{$column} ?? 0) - (int) ($first?->{$column} ?? 0));
return [
'totals' => [
'views' => (int) $collection->views_count,
'likes' => (int) $collection->likes_count,
'follows' => (int) $collection->followers_count,
'saves' => (int) $collection->saves_count,
'comments' => (int) $collection->comments_count,
'shares' => (int) $collection->shares_count,
'submissions' => (int) $collection->submissions()->count(),
],
'range' => [
'days' => $days,
'views_delta' => $delta('views_count'),
'likes_delta' => $delta('likes_count'),
'follows_delta' => $delta('follows_count'),
'saves_delta' => $delta('saves_count'),
'comments_delta' => $delta('comments_count'),
],
'timeline' => $rows->map(fn (CollectionDailyStat $row) => [
'date' => $row->stat_date?->toDateString(),
'views' => (int) $row->views_count,
'likes' => (int) $row->likes_count,
'follows' => (int) $row->follows_count,
'saves' => (int) $row->saves_count,
'comments' => (int) $row->comments_count,
'shares' => (int) $row->shares_count,
'submissions' => (int) $row->submissions_count,
])->values()->all(),
'top_artworks' => $this->topArtworks($collection),
];
}
public function topArtworks(Collection $collection, int $limit = 8): array
{
return DB::table('collection_artwork as ca')
->join('artworks as a', 'a.id', '=', 'ca.artwork_id')
->leftJoin('artwork_stats as s', 's.artwork_id', '=', 'a.id')
->where('ca.collection_id', $collection->id)
->whereNull('a.deleted_at')
->orderByDesc(DB::raw('COALESCE(s.ranking_score, 0)'))
->orderByDesc(DB::raw('COALESCE(s.views, 0)'))
->limit(max(1, min($limit, 12)))
->get([
'a.id',
'a.title',
'a.slug',
'a.hash',
'a.thumb_ext',
DB::raw('COALESCE(s.views, 0) as views'),
DB::raw('COALESCE(s.favorites, 0) as favourites'),
DB::raw('COALESCE(s.shares_count, 0) as shares'),
DB::raw('COALESCE(s.ranking_score, 0) as ranking_score'),
])
->map(fn ($row) => [
'id' => (int) $row->id,
'title' => (string) $row->title,
'slug' => (string) $row->slug,
'thumb' => $row->hash && $row->thumb_ext ? ThumbnailPresenter::forHash((string) $row->hash, (string) $row->thumb_ext, 'sq') : null,
'views' => (int) $row->views,
'favourites' => (int) $row->favourites,
'shares' => (int) $row->shares,
'ranking_score' => round((float) $row->ranking_score, 2),
])
->values()
->all();
}
}