134 lines
4.9 KiB
PHP
134 lines
4.9 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace App\Console\Commands;
|
||
|
||
use App\Services\Sitemaps\SitemapBuildService;
|
||
use Illuminate\Console\Command;
|
||
use Illuminate\Support\Facades\Storage;
|
||
|
||
/**
|
||
* Builds all sitemap documents and writes them as static .xml files to the
|
||
* public disk (default: public/sitemaps/sitemap.xml and public/sitemaps/{name}.xml).
|
||
*
|
||
* Nginx can then serve those files directly (try_files $uri @php) without
|
||
* hitting PHP at all. The SitemapController falls back to these same files
|
||
* on the PHP path if a request does reach it before a static file exists.
|
||
*
|
||
* Run manually: php artisan skinbase:sitemaps:generate
|
||
* With filtering: php artisan skinbase:sitemaps:generate --only=artworks,users
|
||
*/
|
||
final class GenerateSitemapsCommand extends Command
|
||
{
|
||
protected $signature = 'skinbase:sitemaps:generate
|
||
{--only=* : Limit to specific sitemap families (comma or space separated)}
|
||
{--disk= : Override the target filesystem disk (default: sitemaps.static_publish.disk)}';
|
||
|
||
protected $description = 'Build all sitemaps and write them as static .xml files to the configured public sitemap disk.';
|
||
|
||
public function handle(SitemapBuildService $build): int
|
||
{
|
||
$totalStart = microtime(true);
|
||
$families = $this->selectedFamilies($build);
|
||
|
||
if ($families === []) {
|
||
$this->error('No valid sitemap families selected.');
|
||
|
||
return self::INVALID;
|
||
}
|
||
|
||
$diskName = (string) ($this->option('disk') ?: config('sitemaps.static_publish.disk', 'sitemaps_public'));
|
||
$disk = Storage::disk($diskName);
|
||
$written = 0;
|
||
$failed = 0;
|
||
|
||
$this->info('Disk: ' . $diskName);
|
||
$this->info('Families: ' . implode(', ', $families));
|
||
$this->newLine();
|
||
|
||
// ── Root sitemap index ────────────────────────────────────────────
|
||
$t = microtime(true);
|
||
$index = $build->buildIndex(force: true, persist: false, families: $families);
|
||
$disk->put('sitemaps/sitemap.xml', $index['content']);
|
||
$written++;
|
||
$this->line(sprintf(
|
||
' <info>✔</info> sitemaps/sitemap.xml %d entries <comment>%.3fs</comment>',
|
||
$index['url_count'],
|
||
microtime(true) - $t,
|
||
));
|
||
|
||
// ── Per-family documents ──────────────────────────────────────────
|
||
foreach ($families as $family) {
|
||
$familyStart = microtime(true);
|
||
$names = $build->canonicalDocumentNamesForFamily($family);
|
||
|
||
$this->newLine();
|
||
$this->line(sprintf(' <fg=cyan>%s</> (%d document(s))', $family, count($names)));
|
||
|
||
foreach ($names as $documentName) {
|
||
$t = microtime(true);
|
||
$built = $build->buildNamed($documentName, force: true, persist: false);
|
||
|
||
if ($built === null) {
|
||
$this->line(sprintf(' <comment>–</comment> %s <fg=red>SKIPPED</> (builder returned null)', $documentName));
|
||
$failed++;
|
||
|
||
continue;
|
||
}
|
||
|
||
$path = 'sitemaps/' . $documentName . '.xml';
|
||
$disk->put($path, $built['content']);
|
||
$written++;
|
||
|
||
$this->line(sprintf(
|
||
' <info>✔</info> %s %d URLs <comment>%.3fs</comment>',
|
||
$documentName . '.xml',
|
||
$built['url_count'] ?? 0,
|
||
microtime(true) - $t,
|
||
));
|
||
}
|
||
|
||
$this->line(sprintf(
|
||
' <fg=cyan>%s</> done <comment>%.3fs</comment>',
|
||
$family,
|
||
microtime(true) - $familyStart,
|
||
));
|
||
}
|
||
|
||
// ── Summary ───────────────────────────────────────────────────────
|
||
$this->newLine();
|
||
$this->info(sprintf(
|
||
'Done: %d file(s) written, %d failed total <comment>%.3fs</comment>',
|
||
$written,
|
||
$failed,
|
||
microtime(true) - $totalStart,
|
||
));
|
||
|
||
return $failed > 0 ? self::FAILURE : self::SUCCESS;
|
||
}
|
||
|
||
/** @return list<string> */
|
||
private function selectedFamilies(SitemapBuildService $build): array
|
||
{
|
||
$only = [];
|
||
|
||
foreach ((array) $this->option('only') as $value) {
|
||
foreach (explode(',', (string) $value) as $family) {
|
||
$normalized = trim($family);
|
||
if ($normalized !== '') {
|
||
$only[] = $normalized;
|
||
}
|
||
}
|
||
}
|
||
|
||
$enabled = $build->enabledFamilies();
|
||
|
||
if ($only === []) {
|
||
return $enabled;
|
||
}
|
||
|
||
return array_values(array_filter($enabled, fn (string $f): bool => in_array($f, $only, true)));
|
||
}
|
||
}
|