Files
SkinbaseNova/app/Services/Sitemaps/SitemapIndexService.php
T

171 lines
4.6 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Services\Sitemaps;
use DateTimeImmutable;
use DateTimeInterface;
final class SitemapIndexService
{
public function __construct(
private readonly SitemapRegistry $registry,
private readonly SitemapShardService $shards,
) {
}
/**
* @return list<SitemapIndexItem>
*/
public function items(?array $families = null): array
{
$items = [];
$selectedFamilies = $families ?? (array) config('sitemaps.enabled', []);
$groupedFamilies = [];
foreach ($this->activeGroupIndexes($selectedFamilies) as $groupName => $groupFamilies) {
$items[] = new SitemapIndexItem(
url('/sitemaps/' . $groupName . '.xml'),
$this->lastModifiedForFamilies($groupFamilies),
);
foreach ($groupFamilies as $family) {
$groupedFamilies[$family] = true;
}
}
foreach ($selectedFamilies as $name) {
if (isset($groupedFamilies[(string) $name])) {
continue;
}
$builder = $this->registry->get((string) $name);
if ($builder === null) {
continue;
}
$items[] = new SitemapIndexItem(
url('/sitemaps/' . $this->shards->rootEntryName($builder) . '.xml'),
$builder->lastModified(),
);
}
return $items;
}
/**
* @param list<string> $families
* @return list<SitemapIndexItem>
*/
public function itemsForFamilies(array $families): array
{
$items = [];
foreach ($families as $family) {
$builder = $this->registry->get($family);
if ($builder === null) {
continue;
}
$items[] = new SitemapIndexItem(
url('/sitemaps/' . $this->shards->rootEntryName($builder) . '.xml'),
$builder->lastModified(),
);
}
return $items;
}
/**
* @return list<SitemapIndexItem>
*/
public function itemsForBuilder(SitemapBuilder $builder): array
{
if ($builder instanceof ShardableSitemapBuilder && $this->shards->shardCount($builder) > 1) {
$items = [];
foreach (range(1, $this->shards->shardCount($builder)) as $shard) {
$items[] = new SitemapIndexItem(
url('/sitemaps/' . $this->shards->canonicalShardName($builder->name(), $shard) . '.xml'),
$builder->lastModifiedForShard($shard),
);
}
return $items;
}
return [new SitemapIndexItem(
url('/sitemaps/' . $this->shards->rootEntryName($builder) . '.xml'),
$builder->lastModified(),
)];
}
/**
* @param list<string> $selectedFamilies
* @return array<string, list<string>>
*/
public function activeGroupIndexes(array $selectedFamilies): array
{
$selectedLookup = array_fill_keys($selectedFamilies, true);
$groups = [];
foreach ((array) config('sitemaps.group_indexes', []) as $groupName => $groupFamilies) {
if (! is_string($groupName) || $groupName === '') {
continue;
}
$validFamilies = array_values(array_filter(
(array) $groupFamilies,
fn (mixed $family): bool => is_string($family) && $family !== '' && $this->registry->get($family) !== null,
));
if ($validFamilies === []) {
continue;
}
foreach ($validFamilies as $family) {
if (! isset($selectedLookup[$family])) {
continue 2;
}
}
$groups[$groupName] = $validFamilies;
}
return $groups;
}
/**
* @param list<string> $families
*/
private function lastModifiedForFamilies(array $families): ?DateTimeInterface
{
$latest = null;
foreach ($families as $family) {
$builder = $this->registry->get($family);
if ($builder === null) {
continue;
}
$lastModified = $builder->lastModified();
if ($lastModified !== null) {
$candidate = $lastModified instanceof DateTimeInterface
? $lastModified
: new DateTimeImmutable((string) $lastModified);
if ($latest === null || $candidate->getTimestamp() > $latest->getTimestamp()) {
$latest = $candidate;
}
}
}
return $latest;
}
}