Files
usher-manage-stack/app/Console/Commands/ReclassifyDocumentContent.php

139 lines
4.4 KiB
PHP

<?php
namespace App\Console\Commands;
use App\Models\Article;
use App\Models\ArticleCategory;
use App\Services\SiteRevalidationService;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class ReclassifyDocumentContent extends Command
{
protected $signature = 'articles:reclassify-document-content {--dry-run : Preview changes without writing to database}';
protected $description = 'Reclassify document-type articles into real documents vs story/blog content';
/**
* Keep as document resources.
*
* @var array<int, string>
*/
private array $keepDocumentSlugs = [
'whisper-colab',
'document-ef6231ce',
'document-d34b35ab',
];
/**
* Move from document to blog/story.
*
* @var array<int, string>
*/
private array $moveToStorySlugs = [
'document-b81734e3',
'document-2f8fad62',
'document-25e793fb',
'document-48ec7f25',
'document-f68da0b8',
'document-a8bdf6d9',
'document-694e4dd6',
'document-d0608b86',
'document-163bc74d',
'document-ef370202',
];
public function handle(): int
{
$dryRun = (bool) $this->option('dry-run');
$allSlugs = array_values(array_unique(array_merge($this->keepDocumentSlugs, $this->moveToStorySlugs)));
$articles = Article::query()
->whereIn('slug', $allSlugs)
->get()
->keyBy('slug');
$missingSlugs = array_values(array_diff($allSlugs, $articles->keys()->all()));
$documentCategory = ArticleCategory::firstOrCreate(
['slug' => 'document'],
['name' => '協會文件', 'sort_order' => 20]
);
$storyCategory = ArticleCategory::firstOrCreate(
['slug' => 'story'],
['name' => '故事', 'sort_order' => 30]
);
$this->newLine();
$this->info('Reclassification plan');
$this->line(' Keep as document: '.count($this->keepDocumentSlugs));
$this->line(' Move to story/blog: '.count($this->moveToStorySlugs));
$this->line(' Found in DB: '.$articles->count());
if (! empty($missingSlugs)) {
$this->warn('Missing slugs in DB: '.implode(', ', $missingSlugs));
}
$this->newLine();
$this->table(
['Slug', 'Current Type', 'Target Type', 'Target Category'],
collect($allSlugs)->map(function (string $slug) use ($articles) {
$article = $articles->get($slug);
$targetIsDocument = in_array($slug, $this->keepDocumentSlugs, true);
return [
$slug,
$article?->content_type ?? '(missing)',
$targetIsDocument ? Article::CONTENT_TYPE_DOCUMENT : Article::CONTENT_TYPE_BLOG,
$targetIsDocument ? 'document' : 'story',
];
})->all()
);
if ($dryRun) {
$this->newLine();
$this->comment('Dry run only. No database updates were applied.');
return static::SUCCESS;
}
DB::transaction(function () use ($articles, $documentCategory, $storyCategory): void {
foreach ($this->keepDocumentSlugs as $slug) {
$article = $articles->get($slug);
if (! $article) {
continue;
}
$article->update(['content_type' => Article::CONTENT_TYPE_DOCUMENT]);
$article->categories()->sync([$documentCategory->id]);
}
foreach ($this->moveToStorySlugs as $slug) {
$article = $articles->get($slug);
if (! $article) {
continue;
}
$article->update(['content_type' => Article::CONTENT_TYPE_BLOG]);
$article->categories()->sync([$storyCategory->id]);
}
});
$revalidated = 0;
foreach ($articles as $article) {
if ($article->isPublished()) {
SiteRevalidationService::revalidateArticle($article->slug);
$revalidated++;
}
}
$this->newLine();
$this->info('Reclassification completed.');
$this->line(' Updated articles: '.$articles->count());
$this->line(' Revalidation requests sent: '.$revalidated);
return static::SUCCESS;
}
}