optimizations
This commit is contained in:
117
app/Services/CollectionAnalyticsService.php
Normal file
117
app/Services/CollectionAnalyticsService.php
Normal 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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user