55 lines
3.0 KiB
PHP
55 lines
3.0 KiB
PHP
<?php
|
|
namespace App\Services;
|
|
use App\Models\Articles;
|
|
use App\Services\Editorial\IndexNowNotification;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Schema;
|
|
final class SeoNotifications
|
|
{
|
|
public function changed(Articles $a, bool $deleted = false): void
|
|
{
|
|
if (!Schema::hasTable('seo_notifications')) return;
|
|
$urls = [];
|
|
if ($deleted || !Seo::public($a)) $urls[] = Seo::articleUrl($a);
|
|
elseif (Seo::indexable($a)) $urls[] = Seo::articleUrl($a);
|
|
if ($a->oCategory?->sSlug === 'freenode') $urls[] = Seo::url();
|
|
if ($a->oCategory) $urls[] = Seo::url(Seo::categoryPath($a->oCategory));
|
|
$event = $deleted || !Seo::public($a) ? 'delete' : 'update';
|
|
$key = hash('sha256',json_encode([$a->id,$event,$a->sContentUpdatedAt,$a->sTitle,$a->sContent,$a->sThumb,$a->iStatus]));
|
|
$this->enqueue($key,$urls,$event);
|
|
}
|
|
public function enqueue(string $key, array $urls, string $event = 'update'): void
|
|
{
|
|
if (!app()->environment(['production','testing']) || !config('editorial.indexnow_enabled',app()->environment('production'))) return;
|
|
DB::table('seo_notifications')->insertOrIgnore(['event_key'=>$key,'urls'=>json_encode(array_values(array_unique($urls))),
|
|
'event'=>$event,'state'=>json_encode(['status'=>'pending','attempts'=>0]),'created_at'=>now(),'updated_at'=>now()]);
|
|
}
|
|
public function retry(int $limit = 10): int
|
|
{
|
|
$processed = 0;
|
|
foreach (DB::table('seo_notifications')->orderBy('id')->cursor() as $candidate) {
|
|
$s = json_decode($candidate->state,true);
|
|
if (($s['status'] ?? '') !== 'pending' || ($s['next_attempt_at'] ?? 0) > now()->timestamp) continue;
|
|
DB::transaction(function () use ($candidate,&$processed) {
|
|
$row = DB::table('seo_notifications')->where('id',$candidate->id)->lockForUpdate()->first();
|
|
$state = json_decode($row->state,true);
|
|
if (($state['status'] ?? '') !== 'pending' || ($state['next_attempt_at'] ?? 0) > now()->timestamp) return;
|
|
$urls = json_decode($row->urls,true);
|
|
if ($row->event !== 'delete') $urls = array_values(array_filter($urls,function($url) {
|
|
$path = parse_url($url,PHP_URL_PATH);
|
|
if (preg_match('~^/a/([a-zA-Z0-9_-]+)\.html$~',$path,$m)) {
|
|
$a = Articles::where('sSlug',$m[1])->first(); return $a && Seo::indexable($a);
|
|
}
|
|
if ($path === '/') return app(ArticlesService::class)->getLatestFreeNodeSlug() !== null;
|
|
return true;
|
|
}));
|
|
$state = app(IndexNowNotification::class)->submit($state,$urls);
|
|
DB::table('seo_notifications')->where('id',$row->id)->update(['state'=>json_encode($state),'updated_at'=>now()]);
|
|
$processed++;
|
|
});
|
|
if ($processed >= $limit) break;
|
|
}
|
|
return $processed;
|
|
}
|
|
}
|