131 lines
4.8 KiB
PHP
131 lines
4.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\World;
|
|
use App\Services\WebStories\WorldWebStoryGenerator;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Validation\ValidationException;
|
|
|
|
final class GenerateWorldWebStoriesCommand extends Command
|
|
{
|
|
protected $signature = 'skinbase:webstories:generate
|
|
{world? : World ID or slug}
|
|
{--all : Generate stories in batch mode}
|
|
{--pages=7 : Number of pages to generate (5-10)}
|
|
{--limit=25 : Maximum worlds to process in batch mode}
|
|
{--force : Rebuild an existing story for the target world}
|
|
{--publish : Publish immediately after generation if validation passes}
|
|
{--dry-run : Preview generation without saving anything}';
|
|
|
|
protected $description = 'Generate standalone AMP Web Stories from Skinbase Worlds';
|
|
|
|
public function handle(WorldWebStoryGenerator $generator): int
|
|
{
|
|
$worldKey = $this->argument('world');
|
|
$force = (bool) $this->option('force');
|
|
$publish = (bool) $this->option('publish');
|
|
$dryRun = (bool) $this->option('dry-run');
|
|
$pages = max(5, min(10, (int) $this->option('pages')));
|
|
|
|
if ($worldKey !== null && trim((string) $worldKey) !== '') {
|
|
$world = $this->resolveWorld((string) $worldKey);
|
|
|
|
if (! $world instanceof World) {
|
|
$this->error(sprintf('World [%s] was not found.', (string) $worldKey));
|
|
|
|
return self::FAILURE;
|
|
}
|
|
|
|
return $this->generateOne($generator, $world, $pages, $force, $publish, $dryRun);
|
|
}
|
|
|
|
if (! (bool) $this->option('all')) {
|
|
$this->error('Provide a world ID/slug or pass --all for batch generation.');
|
|
|
|
return self::INVALID;
|
|
}
|
|
|
|
return $this->generateBatch($generator, $pages, $force, $publish, $dryRun, max(1, (int) $this->option('limit')));
|
|
}
|
|
|
|
private function generateOne(WorldWebStoryGenerator $generator, World $world, int $pages, bool $force, bool $publish, bool $dryRun): int
|
|
{
|
|
try {
|
|
$result = $generator->generateFromWorld($world, null, $pages, $force, $publish, $dryRun);
|
|
} catch (ValidationException $exception) {
|
|
foreach ($exception->errors() as $messages) {
|
|
foreach ($messages as $message) {
|
|
$this->error((string) $message);
|
|
}
|
|
}
|
|
|
|
return self::FAILURE;
|
|
}
|
|
|
|
$story = $result['story'];
|
|
$validation = $result['validation'];
|
|
|
|
$this->info(sprintf(
|
|
'%s story for world [%s] -> /web-stories/%s (%d pages)',
|
|
$result['created'] ? 'Created' : 'Updated',
|
|
(string) $world->slug,
|
|
(string) $story->slug,
|
|
(int) $validation['page_count'],
|
|
));
|
|
|
|
foreach ((array) $validation['warnings'] as $warning) {
|
|
$this->warn(' - ' . $warning);
|
|
}
|
|
|
|
foreach ((array) $validation['errors'] as $error) {
|
|
$this->error(' - ' . $error);
|
|
}
|
|
|
|
return $validation['valid'] || ! $publish ? self::SUCCESS : self::FAILURE;
|
|
}
|
|
|
|
private function generateBatch(WorldWebStoryGenerator $generator, int $pages, bool $force, bool $publish, bool $dryRun, int $limit): int
|
|
{
|
|
$processed = 0;
|
|
$created = 0;
|
|
$updated = 0;
|
|
$failed = 0;
|
|
|
|
$query = World::query()
|
|
->published()
|
|
->orderByDesc('published_at')
|
|
->orderByDesc('id');
|
|
|
|
if (! $force) {
|
|
$query->whereDoesntHave('webStories');
|
|
}
|
|
|
|
$query->limit($limit)->get()->each(function (World $world) use ($generator, $pages, $force, $publish, $dryRun, &$processed, &$created, &$updated, &$failed): void {
|
|
$processed++;
|
|
|
|
try {
|
|
$result = $generator->generateFromWorld($world, null, $pages, $force, $publish, $dryRun);
|
|
$result['created'] ? $created++ : $updated++;
|
|
$this->line(sprintf('[%d] %s -> %s', (int) $world->id, (string) $world->slug, (string) $result['story']->slug));
|
|
} catch (ValidationException $exception) {
|
|
$failed++;
|
|
$first = collect($exception->errors())->flatten()->first();
|
|
$this->error(sprintf('[%d] %s failed: %s', (int) $world->id, (string) $world->slug, (string) $first));
|
|
}
|
|
});
|
|
|
|
$this->info(sprintf('Done. processed=%d created=%d updated=%d failed=%d', $processed, $created, $updated, $failed));
|
|
|
|
return $failed === 0 ? self::SUCCESS : self::FAILURE;
|
|
}
|
|
|
|
private function resolveWorld(string $value): ?World
|
|
{
|
|
return World::query()
|
|
->when(is_numeric($value), fn ($query) => $query->where('id', (int) $value), fn ($query) => $query->where('slug', $value))
|
|
->first();
|
|
}
|
|
} |