Add command to reclassify document content
This commit is contained in:
138
app/Console/Commands/ReclassifyDocumentContent.php
Normal file
138
app/Console/Commands/ReclassifyDocumentContent.php
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user