*/ public function build(WebPortalContext $context, string $slug): array { $portalValues = $context->portalValues; $language = $context->language; $publishedScope = static fn (Builder $query): Builder => $query ->forPortalValues($portalValues) ->forLanguage($language) ->visibleInArchive(); $release = PressRelease::query() ->withoutGlobalScope(PortalScope::class) ->tap($publishedScope) ->where('slug', $slug) ->with([ 'company', 'user:id,agency_name', 'category.translations' => fn ($query) => $query->where('locale', $language), 'category.parent.translations' => fn ($query) => $query->where('locale', $language), 'images' => fn ($query) => $query->orderByDesc('is_preview')->orderBy('sort_order'), 'contacts', ]) ->first(); if (! $release) { // T12-Tombstone: depublizierte PMs (kostenpflichtige Entfernung // auf Wunsch des Absenders) melden 410 statt 404 — die URL gab // es, der Inhalt wurde bewusst entfernt. $depublished = PressRelease::query() ->withoutGlobalScope(PortalScope::class) ->forPortalValues($portalValues) ->forLanguage($language) ->whereNotNull('depublished_at') ->where('slug', $slug) ->exists(); if ($depublished) { return ['tombstone' => true]; } abort(404); } $releaseId = $release->getKey(); defer(static fn () => PressRelease::recordDeferredView($releaseId)); // Die Antwort zeigt den aktuellen Aufruf bereits an; die atomaren // Schreibzugriffe erfolgen nach dem Senden der Response. $release->hits = ($release->hits ?? 0) + 1; $with = [ 'company', 'category.translations' => fn ($query) => $query->where('locale', $language), 'images' => fn ($query) => $query->orderByDesc('is_preview')->orderBy('sort_order')->limit(1), ]; $companyReleases = $release->company_id ? PressRelease::query() ->withoutGlobalScope(PortalScope::class) ->tap($publishedScope) ->where('company_id', $release->company_id) ->whereKeyNot($release->getKey()) ->with($with) ->orderByDesc('published_at') ->limit(3) ->get() : collect(); $relatedReleases = $release->category_id ? PressRelease::query() ->withoutGlobalScope(PortalScope::class) ->tap($publishedScope) ->where('category_id', $release->category_id) ->whereKeyNot($release->getKey()) ->when($companyReleases->isNotEmpty(), fn (Builder $query) => $query->whereNotIn('id', $companyReleases->modelKeys())) ->with($with) ->orderByDesc('published_at') ->limit(3) ->get() : collect(); return [ 'release' => $release, 'companyReleases' => $companyReleases, 'relatedReleases' => $relatedReleases, ]; } }