shardCount($builder); if ($builder instanceof ShardableSitemapBuilder && ($shardCount > 1 || $this->forceFamilyIndexes())) { return $this->familyIndexName($builder->name()); } return $builder->name(); } public function shardCount(SitemapBuilder $builder): int { if (! $builder instanceof ShardableSitemapBuilder || ! $this->enabledFor($builder->name())) { return 1; } $totalItems = $builder->totalItems(); if ($totalItems <= 0) { return 0; } return max(1, (int) ceil($totalItems / max(1, $builder->shardSize()))); } /** * @return list */ public function indexNamesForBuilder(SitemapBuilder $builder): array { $shardCount = $this->shardCount($builder); if ($builder instanceof ShardableSitemapBuilder && $shardCount > 1) { return array_map(fn (int $shard): string => $this->canonicalShardName($builder->name(), $shard), range(1, $shardCount)); } return [$builder->name()]; } /** * @return list */ public function canonicalDocumentNamesForBuilder(SitemapBuilder $builder): array { $names = $this->indexNamesForBuilder($builder); if ($builder instanceof ShardableSitemapBuilder && ($this->shardCount($builder) > 1 || $this->forceFamilyIndexes())) { array_unshift($names, $this->familyIndexName($builder->name())); } return array_values(array_unique($names)); } public function familyIndexName(string $baseName): string { return $baseName . '-index'; } public function canonicalShardName(string $baseName, int $shard): string { return sprintf('%s-%s', $baseName, str_pad((string) $shard, $this->padLength(), '0', STR_PAD_LEFT)); } public function resolve(SitemapRegistry $registry, string $name): ?SitemapTarget { $builder = $registry->get($name); if ($builder !== null) { $shardCount = $this->shardCount($builder); if ($builder instanceof ShardableSitemapBuilder && ($shardCount > 1 || $this->forceFamilyIndexes())) { return new SitemapTarget($name, $this->familyIndexName($builder->name()), $builder->name(), SitemapTarget::TYPE_INDEX, $builder, null, $shardCount); } return new SitemapTarget($name, $builder->name(), $builder->name(), $this->targetType($builder), $builder); } if (preg_match('/^(.+)-index$/', $name, $indexMatches)) { $baseName = (string) $indexMatches[1]; $builder = $registry->get($baseName); if (! $builder instanceof ShardableSitemapBuilder) { return null; } $shardCount = $this->shardCount($builder); if ($shardCount < 1) { return null; } return new SitemapTarget($name, $this->familyIndexName($baseName), $baseName, SitemapTarget::TYPE_INDEX, $builder, null, $shardCount); } if (! preg_match('/^(.+)-([0-9]{1,})$/', $name, $matches)) { return null; } $baseName = (string) $matches[1]; $shardNumber = (int) $matches[2]; $builder = $registry->get($baseName); if (! $builder instanceof ShardableSitemapBuilder) { return null; } $shardCount = $this->shardCount($builder); if ($shardCount < 2 || $shardNumber > $shardCount) { return null; } return new SitemapTarget($name, $this->canonicalShardName($baseName, $shardNumber), $baseName, SitemapTarget::TYPE_URLSET, $builder, $shardNumber, $shardCount); } private function forceFamilyIndexes(): bool { return (bool) config('sitemaps.shards.force_family_indexes', false); } private function padLength(): int { return max(1, (int) config('sitemaps.shards.zero_pad_length', 4)); } private function targetType(SitemapBuilder $builder): string { return $builder->name() === (string) config('sitemaps.news.google_variant_name', 'news-google') ? SitemapTarget::TYPE_GOOGLE_NEWS : SitemapTarget::TYPE_URLSET; } private function enabledFor(string $family): bool { if (! (bool) config('sitemaps.shards.enabled', true)) { return false; } return (int) data_get(config('sitemaps.shards', []), $family . '.size', 0) > 0; } }