*/ abstract protected function query(): Builder; abstract protected function shardConfigKey(): string; abstract protected function mapRecord(Model $record): ?SitemapUrl; public function items(): array { return $this->query() ->orderBy($this->idColumn()) ->cursor() ->map(fn (Model $record): ?SitemapUrl => $this->mapRecord($record)) ->filter() ->values() ->all(); } public function lastModified(): ?DateTimeInterface { return $this->newest(...array_map( fn (SitemapUrl $item): ?DateTimeInterface => $item->lastModified, $this->items(), )); } public function totalItems(): int { return (clone $this->query())->count(); } public function shardSize(): int { return max(1, (int) \data_get(\config('sitemaps.shards', []), $this->shardConfigKey() . '.size', 10000)); } public function itemsForShard(int $shard): array { $window = $this->shardWindow($shard); if ($window === null) { return []; } return $this->applyShardWindow($window['from'], $window['to']) ->get() ->map(fn (Model $record): ?SitemapUrl => $this->mapRecord($record)) ->filter() ->values() ->all(); } public function lastModifiedForShard(int $shard): ?DateTimeInterface { return $this->newest(...array_map( fn (SitemapUrl $item): ?DateTimeInterface => $item->lastModified, $this->itemsForShard($shard), )); } /** * @return array{from: int, to: int}|null */ protected function shardWindow(int $shard): ?array { if ($shard < 1) { return null; } $size = $this->shardSize(); $current = 0; $from = null; $to = null; $windowQuery = (clone $this->query()) ->setEagerLoads([]) ->select([$this->idColumn()]) ->orderBy($this->idColumn()); foreach ($windowQuery->cursor() as $record) { $current++; if ((int) ceil($current / $size) !== $shard) { continue; } $recordId = (int) $record->getAttribute($this->idColumn()); $from ??= $recordId; $to = $recordId; } if ($from === null || $to === null) { return null; } return ['from' => $from, 'to' => $to]; } /** * @return Builder */ protected function applyShardWindow(int $from, int $to): Builder { return (clone $this->query()) ->whereBetween($this->qualifiedIdColumn(), [$from, $to]) ->orderBy($this->idColumn()); } protected function idColumn(): string { return 'id'; } protected function qualifiedIdColumn(): string { return $this->idColumn(); } }