54 lines
2.8 KiB
PHP
54 lines
2.8 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\Articles;
|
|
use App\Services\IllustrationPool;
|
|
use App\Services\LocalIllustrations;
|
|
use Illuminate\Console\Command;
|
|
use Spatie\ResponseCache\Facades\ResponseCache;
|
|
|
|
final class SyncLocalIllustrations extends Command
|
|
{
|
|
protected $signature = 'illustrations:sync-local {--assign-missing : Create missing Resource assignments for existing public articles}';
|
|
protected $description = 'Copy approved Resource images into deduplicated local static files and atomically reconcile article mappings';
|
|
|
|
public function handle(LocalIllustrations $local): int
|
|
{
|
|
if (! IllustrationPool::enabled()) {
|
|
$this->error('Resource binding is not enabled for this environment');
|
|
return self::FAILURE;
|
|
}
|
|
try {
|
|
$baseline = $local->selectionBaseline();
|
|
$snapshots = [];
|
|
$expected = [];
|
|
foreach (config('illustrations.categories') as $category => $pool) {
|
|
$keys = Articles::where('iCategoryId', $category)->where('iStatus', 1)->orderBy('created_at')->orderBy('id')->pluck('sSlug')->all();
|
|
IllustrationPool::forget($pool);
|
|
$snapshot = IllustrationPool::sourceSnapshot($pool);
|
|
$missing = array_values(array_diff($keys, array_keys($snapshot['selections']), array_keys($snapshot['unavailable'] ?? [])));
|
|
if ($missing && ! $this->option('assign-missing')) throw new \RuntimeException('Missing article assignments; rerun with --assign-missing using a write-scoped consumer');
|
|
foreach (array_chunk($missing, 200) as $chunk) IllustrationPool::assignSource($pool, $chunk);
|
|
if ($missing) $snapshot = IllustrationPool::sourceSnapshot($pool);
|
|
$snapshots[$pool] = $snapshot;
|
|
$expected[$pool] = $keys;
|
|
}
|
|
$result = $local->synchronize($snapshots, $baseline);
|
|
foreach ($expected as $pool => $keys) {
|
|
foreach ($keys as $key) {
|
|
if (! $local->thumbnail($pool, $key)) $result['pending'][$pool.':'.$key] ??= 'local_copy_unavailable';
|
|
}
|
|
}
|
|
ResponseCache::clear();
|
|
\Illuminate\Support\Facades\Cache::forget('article_order_likes');
|
|
$this->line(json_encode($result, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
|
|
return $result['pending'] ? self::FAILURE : self::SUCCESS;
|
|
} catch (\Throwable) {
|
|
// Never print request/credential exceptions or leave partial manifest writes.
|
|
$this->error('Local illustration sync failed; existing manifest retained if publication did not complete. Retry after checking Resource and filesystem access.');
|
|
return self::FAILURE;
|
|
}
|
|
}
|
|
}
|