Files
SkinbaseNova/app/Observers/ArtworkFavouriteObserver.php

69 lines
2.0 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Observers;
use App\Jobs\RecComputeSimilarByBehaviorJob;
use App\Jobs\RecComputeSimilarHybridJob;
use App\Models\ArtworkFavourite;
use App\Services\UserStatsService;
use Illuminate\Support\Facades\DB;
/**
* Updates the artwork creator's favorites_received_count and last_active_at
* whenever a favourite is added or removed.
*/
class ArtworkFavouriteObserver
{
public function __construct(
private readonly UserStatsService $userStats,
) {}
public function created(ArtworkFavourite $favourite): void
{
$creatorId = $this->creatorId($favourite->artwork_id);
if ($creatorId) {
$this->userStats->incrementFavoritesReceived($creatorId);
}
// §7.5 On-demand: recompute behavior similarity when artwork reaches threshold
$this->maybeRecomputeBehavior($favourite->artwork_id);
}
public function deleted(ArtworkFavourite $favourite): void
{
$creatorId = $this->creatorId($favourite->artwork_id);
if ($creatorId) {
$this->userStats->decrementFavoritesReceived($creatorId);
}
}
private function creatorId(int $artworkId): ?int
{
$id = DB::table('artworks')
->where('id', $artworkId)
->value('user_id');
return $id !== null ? (int) $id : null;
}
/**
* Dispatch on-demand behavior recomputation when an artwork crosses a
* favourites threshold (5, 10, 25, 50 …).
*/
private function maybeRecomputeBehavior(int $artworkId): void
{
$count = (int) DB::table('artwork_favourites')
->where('artwork_id', $artworkId)
->count();
$thresholds = [5, 10, 25, 50, 100];
if (in_array($count, $thresholds, true)) {
RecComputeSimilarByBehaviorJob::dispatch($artworkId)->delay(now()->addSeconds(30));
RecComputeSimilarHybridJob::dispatch($artworkId)->delay(now()->addMinute());
}
}
}