['except' => 'all'], ]; public function setTimeframe(string $timeframe): void { $this->timeframe = $timeframe; $this->resetPage(); } public function with(): array { $releases = $this->pressReleases(); return [ 'releases' => $releases, 'totalCount' => $releases->total(), ]; } /** * Der Feed rendert auf jeder Startseiten-Impression → die vorderen Seiten * werden stale-while-revalidate gecacht (WebPageCache, wie die übrigen * Seitendaten). Der Paginator wird pro Request neu gebaut, damit die * Pagination-Links den Host des aktuellen Requests tragen und nicht den * des Cache-Erzeugers. */ private function pressReleases(): LengthAwarePaginator { $page = max(1, (int) Paginator::resolveCurrentPage('page')); $timeframe = $this->normalizedTimeframe(); $build = fn (): array => $this->feedPayload($timeframe, $page); $payload = $page <= self::CACHED_PAGES ? WebPageCache::remember( WebPageCache::key('feed', [$this->portalValues()[0], $this->language, $timeframe, 'page', $page]), $build, ) : $build(); return new LengthAwarePaginator( $payload['items'], $payload['total'], 8, $page, ['path' => Paginator::resolveCurrentPath(), 'pageName' => 'page'], ); } /** * @return array{items: \Illuminate\Database\Eloquent\Collection, total: int} */ private function feedPayload(string $timeframe, int $page): array { $query = $this->baseQuery(); if ($timeframe !== 'all') { $reference = $this->referenceNow(); $query ->when($timeframe === 'today', fn (Builder $query) => $query->whereBetween('published_at', [$reference->copy()->startOfDay(), $reference->copy()->endOfDay()])) ->when($timeframe === 'week', fn (Builder $query) => $query->where('published_at', '>=', $reference->copy()->subDays(7))); } return [ 'items' => (clone $query)->orderByDesc('published_at')->forPage($page, 8)->get(), 'total' => (clone $query)->count(), ]; } /** * Der timeframe kommt aus der URL (queryString) — unbekannte Werte fallen * auf "all" zurück, damit sie weder Queries noch Cache-Keys erreichen. */ private function normalizedTimeframe(): string { return in_array($this->timeframe, self::TIMEFRAMES, true) ? $this->timeframe : 'all'; } private function referenceNow(): Carbon { return EditorialClock::reference($this->portalValues(), $this->language); } private function baseQuery(): Builder { return PressRelease::query() ->with([ 'company', 'category.translations' => fn ($query) => $query->where('locale', $this->language), // Nur öffentlich auslieferbare Bilder (Audit 29.09., B-01). 'images' => fn ($query) => $query ->publiclyVisible() ->orderByDesc('is_preview') ->orderBy('sort_order') ->limit(1), ]) ->whereIn('portal', $this->portalValues()) ->where('status', PressReleaseStatus::Published) ->where('language', $this->language) ->whereNotNull('published_at') ->where('published_at', '<=', now()); } /** * @return array */ private function portalValues(): array { $primary = $this->portal ?? Portal::Businessportal24->value; return [$primary, Portal::Both->value]; } }; ?>

{{ __('web.feed.title') }}


@php $items = $releases->items(); $top = $items[0] ?? null; $rest = array_slice($items, 1); @endphp @if ($top) @else

{{ __('web.feed.empty') }}

@endif @foreach ($rest as $release) @if ($loop->index === 2) {{-- Werbeplatz nach der dritten Feed-Meldung (Position der früheren feed-ad). --}} @endif @endforeach @if ($releases->hasMorePages()) @endif