Backend-WIP: Kontakt-Queue, Page-Cache, Validierungs-Feedback, i18n
Gebuendelt, da ueber gemeinsame lang-/Service-Dateien verschraenkt: - Kontakt-Nachrichten: contact_messages-Tabelle + Model/Enums/Factory, Admin-Queue (livewire/admin/contact-messages), ContactController persistiert das Anliegen zusaetzlich zur Brand-Mail - Page-Data-Cache (Services/Web/*PageData) + web-archive-Indizes auf press_releases - Validierungs-Feedback + Company-Portal-Restriction (Feature-Tests) - i18n-Auslagerung lang/de|en (auth, passwords, validation, static) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ef5de54300
commit
72e6a3c210
60 changed files with 3963 additions and 327 deletions
|
|
@ -9,18 +9,39 @@ use App\Models\PressRelease;
|
|||
use App\Support\EditorialClock;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
/**
|
||||
* Datenaufbereitung der öffentlichen Startseite einer Ausgabe: Lead-/Seiten-/
|
||||
* meistgelesene Meldungen, aktive Newsrooms, Branchen-Index, „Heute im Fokus"
|
||||
* (Spotlight) und Kennzahlen. Der Ad-Hoc-Ticker kommt zentral aus TickerData.
|
||||
*
|
||||
* Das Ergebnis wird kurz gecacht (analog TickerData): Der Aufbau umfasst
|
||||
* ~25 Queries über das gesamte Archiv und die Daten ändern sich höchstens
|
||||
* minütlich — neue Meldungen erscheinen spätestens nach Ablauf der TTL.
|
||||
*/
|
||||
class HomePageData
|
||||
{
|
||||
private const CACHE_TTL_SECONDS = 300;
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function build(Portal $portal, string $language = 'de'): array
|
||||
{
|
||||
$cacheKey = sprintf('web.home.%s.%s', $portal->value, $language);
|
||||
|
||||
return Cache::remember(
|
||||
$cacheKey,
|
||||
self::CACHE_TTL_SECONDS,
|
||||
fn (): array => $this->buildFresh($portal, $language)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function buildFresh(Portal $portal, string $language): array
|
||||
{
|
||||
$portalValues = [$portal->value, Portal::Both->value];
|
||||
|
||||
|
|
@ -29,6 +50,10 @@ class HomePageData
|
|||
$recentSince = $referenceNow->copy()->subDays(7);
|
||||
$previousSince = $referenceNow->copy()->subDays(14);
|
||||
|
||||
// Bereichsvergleich statt whereDate(): DATE(published_at) würde die
|
||||
// Index-Nutzung auf published_at verhindern (non-sargable).
|
||||
$todayRange = [$referenceNow->copy()->startOfDay(), $referenceNow->copy()->endOfDay()];
|
||||
|
||||
$publishedQuery = static fn (): Builder => PressRelease::query()
|
||||
->forPortalValues($portalValues)
|
||||
->forLanguage($language)
|
||||
|
|
@ -52,12 +77,14 @@ class HomePageData
|
|||
->orderByDesc('published_at')
|
||||
->first();
|
||||
|
||||
// Ohne mediumText-Spalte `text`: die Seitenleisten-Teaser rendern nur
|
||||
// Titel/Meta, der Volltext wäre unnötiger I/O.
|
||||
$sideReleases = $publishedQuery()
|
||||
->with($with)
|
||||
->when($leadRelease, fn (Builder $query) => $query->where('id', '!=', $leadRelease->id))
|
||||
->orderByDesc('published_at')
|
||||
->limit(4)
|
||||
->get();
|
||||
->get(['id', 'portal', 'language', 'slug', 'title', 'category_id', 'company_id', 'published_at', 'content_score']);
|
||||
|
||||
$mostReadReleases = $publishedQuery()
|
||||
->orderByDesc('hits')
|
||||
|
|
@ -83,12 +110,12 @@ class HomePageData
|
|||
->published()
|
||||
->where('published_at', '>=', $recentSince);
|
||||
},
|
||||
'pressReleases as today_releases_count' => function (Builder $query) use ($portalValues, $referenceNow, $language): void {
|
||||
'pressReleases as today_releases_count' => function (Builder $query) use ($portalValues, $todayRange, $language): void {
|
||||
$query
|
||||
->forPortalValues($portalValues)
|
||||
->forLanguage($language)
|
||||
->published()
|
||||
->whereDate('published_at', $referenceNow->toDateString());
|
||||
->whereBetween('published_at', $todayRange);
|
||||
},
|
||||
])
|
||||
->orderByDesc('today_releases_count')
|
||||
|
|
@ -224,7 +251,7 @@ class HomePageData
|
|||
'spotlight' => $spotlight,
|
||||
'homeStats' => [
|
||||
'publishedCount' => $publishedQuery()->count(),
|
||||
'publishedToday' => $publishedQuery()->whereDate('published_at', $referenceNow->toDateString())->count(),
|
||||
'publishedToday' => $publishedQuery()->whereBetween('published_at', $todayRange)->count(),
|
||||
'archiveSince' => $oldestPublishedAt ? (int) Carbon::parse($oldestPublishedAt)->format('Y') : null,
|
||||
],
|
||||
];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue