Files
SkinbaseNova/app/Services/ArtworkSearchIndexer.php

107 lines
2.8 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Services;
use App\Jobs\DeleteArtworkFromIndexJob;
use App\Jobs\IndexArtworkJob;
use App\Models\Artwork;
use Closure;
use Illuminate\Support\Facades\Log;
/**
* Manages Meilisearch index operations for artworks.
*
* All write operations are dispatched to queues — never block requests.
*/
final class ArtworkSearchIndexer
{
/**
* Queue an artwork for indexing (insert or update).
*/
public function index(Artwork $artwork): void
{
IndexArtworkJob::dispatch($artwork->id);
}
/**
* Queue an artwork for re-indexing after an update.
*/
public function update(Artwork $artwork): void
{
IndexArtworkJob::dispatch($artwork->id);
}
/**
* Queue removal of an artwork from the index.
*/
public function delete(int $id): void
{
DeleteArtworkFromIndexJob::dispatch($id);
}
/**
* Rebuild the entire artworks index in background chunks.
* Run via: php artisan artworks:search-rebuild
*
* @param Closure(int, int, int, int, int, int): void|null $onChunk
* @return array{total:int, dispatched:int, chunks:int}
*/
public function rebuildAll(int $chunkSize = 500, ?Closure $onChunk = null, bool $reverse = false, ?int $limit = null): array
{
$query = Artwork::query()
->public()
->published();
if ($reverse) {
$query->orderByDesc('id');
} else {
$query->orderBy('id');
}
if ($limit !== null) {
$query->limit($limit);
}
$total = (clone $query)->count();
$dispatched = 0;
$chunks = 0;
$query
->with(['user', 'tags', 'categories', 'stats', 'awardStat'])
->chunk($chunkSize, function ($artworks) use (&$chunks, &$dispatched, $total, $onChunk): void {
$chunks++;
$count = $artworks->count();
$firstId = (int) ($artworks->first()?->id ?? 0);
$lastId = (int) ($artworks->last()?->id ?? 0);
foreach ($artworks as $artwork) {
IndexArtworkJob::dispatch($artwork->id);
$dispatched++;
}
if ($onChunk !== null) {
$onChunk($chunks, $count, $dispatched, $total, $firstId, $lastId);
}
});
Log::info('ArtworkSearchIndexer::rebuildAll — jobs dispatched', [
'total' => $total,
'dispatched' => $dispatched,
'chunks' => $chunks,
'chunk_size' => $chunkSize,
'reverse' => $reverse,
'limit' => $limit,
]);
return [
'total' => $total,
'dispatched' => $dispatched,
'chunks' => $chunks,
];
}
}