*/ private array $keepDocumentSlugs = [ 'whisper-colab', 'document-ef6231ce', 'document-d34b35ab', ]; /** * Move from document to blog/story. * * @var array */ 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; $revalidateServiceClass = '\\App\\Services\\SiteRevalidationService'; $canRevalidate = class_exists($revalidateServiceClass); if (! $canRevalidate) { $this->warn('SiteRevalidationService not found. Skipping cache revalidation.'); } foreach ($articles as $article) { if (! $article->isPublished() || ! $canRevalidate) { continue; } $revalidateServiceClass::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; } }