81 lines
3.7 KiB
PHP
81 lines
3.7 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Editorial;
|
|
|
|
use App\Models\Articles;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Meilisearch\Client;
|
|
use Spatie\ResponseCache\Facades\ResponseCache;
|
|
|
|
final class PublicationEffects
|
|
{
|
|
public function synchronize(string $id): array
|
|
{
|
|
DB::transaction(function () use ($id) {
|
|
$row = DB::table('editorial_publications')->where('id', $id)->lockForUpdate()->first();
|
|
abort_unless($row, 404);
|
|
$receipt = json_decode($row->receipt, true);
|
|
$effects = json_decode($row->effects ?? '{}', true) ?: [];
|
|
if (($effects['cache']['status'] ?? '') !== 'done') {
|
|
try {
|
|
ResponseCache::clear();
|
|
Cache::forget('article_order_likes');
|
|
$effects['cache'] = ['status' => 'done'];
|
|
} catch (\Throwable) {
|
|
$effects['cache'] = ['status' => 'pending', 'reason' => 'Cache refresh failed; retry synchronization'];
|
|
}
|
|
}
|
|
if (($effects['search']['status'] ?? '') !== 'done') {
|
|
try {
|
|
$ids = array_column($receipt['articles'], 'article_id');
|
|
$effects['search'] = $this->index($ids);
|
|
} catch (\Throwable) {
|
|
$effects['search'] = ['status' => 'pending', 'reason' => 'Search synchronization failed; retry synchronization'];
|
|
}
|
|
}
|
|
// Sitemap is generated from current DB rows, no external submission is performed.
|
|
$effects['sitemap'] = ['status' => ($effects['cache']['status'] ?? '') === 'done' ? 'done' : 'pending', 'method' => 'database-driven'];
|
|
DB::table('editorial_publications')->where('id', $id)->update(['effects' => json_encode($effects), 'updated_at' => now()]);
|
|
});
|
|
|
|
return app(Publisher::class)->receipt($id);
|
|
}
|
|
|
|
public function index(?array $ids = null): array
|
|
{
|
|
$driver = config('scout.driver');
|
|
if (in_array($driver, ['collection', 'database'])) {
|
|
return ['status' => 'done', 'method' => 'live-database'];
|
|
}
|
|
if ($driver !== 'meilisearch') {
|
|
return ['status' => 'pending', 'reason' => 'Configure a supported site search driver'];
|
|
}
|
|
$name = config('editorial.search_index');
|
|
$host = config('scout.meilisearch.host');
|
|
if (! $name || (app()->environment('local') && (! in_array(parse_url($host, PHP_URL_HOST), ['localhost', '127.0.0.1', '::1']) || ! str_starts_with($name, 'fna_v3_')))) {
|
|
return ['status' => 'pending', 'reason' => 'An isolated search index is required'];
|
|
}
|
|
$client = new Client($host, config('scout.meilisearch.key'));
|
|
$index = $client->index($name);
|
|
$wait = function ($task) use ($client) {
|
|
$result = $client->waitForTask($task['taskUid'], 10000, 50);
|
|
if (($result['status'] ?? '') !== 'succeeded') {
|
|
throw new \RuntimeException('Index task failed');
|
|
}
|
|
};
|
|
$wait($index->updateSortableAttributes(['iIsTop', 'created_at']));
|
|
$wait($index->updateFilterableAttributes(['iStatus', 'iCategoryId']));
|
|
$query = Articles::query()->where('iStatus', 1);
|
|
if ($ids !== null) {
|
|
$query->whereIn('id', $ids);
|
|
}
|
|
$documents = $query->get()->map(fn ($a) => $a->toSearchableArray() + ['created_at' => $a->created_at?->timestamp])->all();
|
|
if ($documents) {
|
|
$wait($index->addDocuments($documents, 'id'));
|
|
}
|
|
|
|
return ['status' => 'done', 'method' => 'meilisearch', 'index' => $name, 'documents' => count($documents)];
|
|
}
|
|
}
|