presseportale/app/Support/CategoryNavigation.php
Kevin Adametz 72e6a3c210 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>
2026-07-09 15:38:11 +00:00

70 lines
2.6 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Support;
use App\Enums\Portal;
use App\Enums\PressReleaseStatus;
use App\Models\Category;
use App\Scopes\PortalScope;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
/**
* Liefert die Rubriken-Navigation der aktiven Ausgabe (Portal × Sprache).
*
* Es gibt bewusst keine separate Rubriken-Übersichtsseite: Die Navigation
* führt direkt auf die jeweilige Kategorieseite (`route('kategorie', …)`),
* auf der die Pressemitteilungen dieser Rubrik erscheinen.
*/
class CategoryNavigation
{
/**
* Top-Level-Rubriken der aktiven Ausgabe als Navigationsitems.
*
* Sortiert nach Anzahl veröffentlichter Pressemitteilungen; `null` als
* Limit liefert alle Rubriken (z. B. für das „Mehr“-Dropdown im Header).
*
* @return Collection<int, array{label:string, slug:string, href:string}>
*/
public static function items(?int $limit = 9): Collection
{
$portal = Portal::tryFrom((string) config('app.theme')) ?? Portal::Businessportal24;
$language = app()->getLocale();
$portalValues = [$portal->value, Portal::Both->value];
return Category::query()
->with(['translations' => fn ($query) => $query->where('locale', $language)])
->withCount([
'pressReleases as published_count' => function (Builder $query) use ($portalValues, $language): void {
$query
->withoutGlobalScope(PortalScope::class)
->whereIn('portal', $portalValues)
->where('status', PressReleaseStatus::Published)
->where('language', $language)
->whereNotNull('published_at');
},
])
->whereIn('portal', $portalValues)
->where('is_active', true)
->whereNull('parent_id')
->orderByDesc('published_count')
->orderBy('id')
->when($limit !== null, fn (Builder $query) => $query->limit($limit))
->get()
->map(function (Category $category): ?array {
$translation = $category->translations->first();
if (! $translation || ! $translation->slug) {
return null;
}
return [
'label' => $translation->name,
'slug' => $translation->slug,
'href' => route('kategorie', ['slug' => $translation->slug]),
];
})
->filter()
->values();
}
}