145 lines
3.7 KiB
PHP
145 lines
3.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Services\Sitemaps;
|
|
|
|
use Closure;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
final class SitemapCacheService
|
|
{
|
|
public const INDEX_DOCUMENT = 'index';
|
|
|
|
/**
|
|
* @return array{content: string, source: string}|null
|
|
*/
|
|
public function get(string $name): ?array
|
|
{
|
|
if ($this->preferPreGenerated()) {
|
|
$preGenerated = $this->getPreGenerated($name);
|
|
if ($preGenerated !== null) {
|
|
return $preGenerated;
|
|
}
|
|
}
|
|
|
|
$cached = Cache::get($this->cacheKey($name));
|
|
if (is_string($cached) && $cached !== '') {
|
|
return ['content' => $cached, 'source' => 'cache'];
|
|
}
|
|
|
|
if (! $this->preferPreGenerated()) {
|
|
return $this->getPreGenerated($name);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @return array{content: string, source: string}
|
|
*/
|
|
public function remember(string $name, Closure $builder, bool $force = false, bool $persist = true): array
|
|
{
|
|
if (! $force) {
|
|
$existing = $this->get($name);
|
|
|
|
if ($existing !== null) {
|
|
return $existing;
|
|
}
|
|
}
|
|
|
|
$content = (string) $builder();
|
|
|
|
if ($persist) {
|
|
$this->store($name, $content);
|
|
}
|
|
|
|
return ['content' => $content, 'source' => 'built'];
|
|
}
|
|
|
|
public function store(string $name, string $content): void
|
|
{
|
|
Cache::put(
|
|
$this->cacheKey($name),
|
|
$content,
|
|
now()->addSeconds(max(60, (int) config('sitemaps.cache_ttl_seconds', 900))),
|
|
);
|
|
|
|
if ($this->preGeneratedEnabled()) {
|
|
Storage::disk($this->disk())->put($this->documentPath($name), $content);
|
|
}
|
|
}
|
|
|
|
public function clear(array $names): int
|
|
{
|
|
$cleared = 0;
|
|
|
|
foreach (array_values(array_unique($names)) as $name) {
|
|
Cache::forget($this->cacheKey($name));
|
|
|
|
if ($this->preGeneratedEnabled()) {
|
|
Storage::disk($this->disk())->delete($this->documentPath($name));
|
|
}
|
|
|
|
$cleared++;
|
|
}
|
|
|
|
return $cleared;
|
|
}
|
|
|
|
public function documentPath(string $name): string
|
|
{
|
|
$prefix = trim((string) config('sitemaps.pre_generated.path', 'generated-sitemaps'), '/');
|
|
$segments = $name === self::INDEX_DOCUMENT
|
|
? [$prefix, 'sitemap.xml']
|
|
: [$prefix, 'sitemaps', $name . '.xml'];
|
|
|
|
return implode('/', array_values(array_filter($segments, static fn (string $segment): bool => $segment !== '')));
|
|
}
|
|
|
|
private function cacheKey(string $name): string
|
|
{
|
|
return 'sitemaps:v2:' . $name;
|
|
}
|
|
|
|
/**
|
|
* @return array{content: string, source: string}|null
|
|
*/
|
|
private function getPreGenerated(string $name): ?array
|
|
{
|
|
if (! $this->preGeneratedEnabled()) {
|
|
return null;
|
|
}
|
|
|
|
$disk = Storage::disk($this->disk());
|
|
$path = $this->documentPath($name);
|
|
|
|
if (! $disk->exists($path)) {
|
|
return null;
|
|
}
|
|
|
|
$content = $disk->get($path);
|
|
|
|
if (! is_string($content) || $content === '') {
|
|
return null;
|
|
}
|
|
|
|
return ['content' => $content, 'source' => 'pre-generated'];
|
|
}
|
|
|
|
private function disk(): string
|
|
{
|
|
return (string) config('sitemaps.pre_generated.disk', 'local');
|
|
}
|
|
|
|
private function preGeneratedEnabled(): bool
|
|
{
|
|
return (bool) config('sitemaps.pre_generated.enabled', true);
|
|
}
|
|
|
|
private function preferPreGenerated(): bool
|
|
{
|
|
return $this->preGeneratedEnabled() && (bool) config('sitemaps.pre_generated.prefer', false);
|
|
}
|
|
} |