Files
SkinbaseNova/app/Services/Sitemaps/SitemapCacheService.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);
}
}