CMS: Standorte an der Marke, Seitenbaum mit Vorschau, Referenzen-Modul
Nachtrag 11: Herkunfts-Sektion liest Ort, Entfernung und Rolle aus der Markenverwaltung (drei neue Felder an cms_brands, BrandOriginSeeder), Kartenpositionen im Code, „Marken“ in der Sidebar. Nachtrag 12: Inhalte-Editor zeigt die Seiten der Website mit ihren Sektionen in Reihenfolge (config/cms_pages.php, CmsPageTree), Felder in Klartext, fehlende Sektionen aus der Sprachdatei anlegbar, Vorschau der echten Seite im iframe mit Sprung zur Sektion; Anker an allen lebenden Sektionen nachgezogen. Nachtrag 13: Referenzen als eigenes Modul (CmsReference, Portal-Seite, /referenzen mit Fallback auf die Markengalerien); Immobilien-Projekte aus Sidebar und CMS-Übersicht genommen, Route bleibt. Dazu .gitignore für _b2in_interior_shop/ und docs/. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
7953a8c9a1
commit
90aa079cf7
50 changed files with 2580 additions and 324 deletions
187
app/Services/CmsPageTree.php
Normal file
187
app/Services/CmsPageTree.php
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use FluxCms\Core\Models\CmsContent;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* Seitenbaum für den Inhalte-Editor (config/cms_pages.php, Nachtrag 12).
|
||||
*
|
||||
* Verbindet die Registry mit dem Datenbestand: je Sektion, ob sie in flux_cms_contents liegt
|
||||
* (dann mit `content_id`), und was sonst noch in der Datenbank steht, aber in keiner Seite
|
||||
* eingetragen ist („Nicht mehr verwendet“).
|
||||
*/
|
||||
class CmsPageTree
|
||||
{
|
||||
/** Schlüssel des Sammelpunkts für nicht eingetragene Sektionen. */
|
||||
public const UNLISTED = 'unlisted';
|
||||
|
||||
/**
|
||||
* Alle Seiten mit ihren Sektionen in Website-Reihenfolge.
|
||||
*
|
||||
* @return array<string, array{title: string, path: ?string, sections: list<array<string, mixed>>}>
|
||||
*/
|
||||
public function pages(): array
|
||||
{
|
||||
$rows = CmsContent::query()
|
||||
->get(['id', 'group', 'key'])
|
||||
->keyBy(fn (CmsContent $row) => $row->group.'/'.$row->key);
|
||||
|
||||
$pages = [];
|
||||
|
||||
foreach (config('cms_pages.pages', []) as $pageKey => $page) {
|
||||
$sections = [];
|
||||
|
||||
foreach ($page['sections'] ?? [] as $section) {
|
||||
$id = $section['group'].'/'.$section['key'];
|
||||
|
||||
$sections[] = array_merge($section, [
|
||||
'page' => $pageKey,
|
||||
'path' => $section['path'] ?? $page['path'] ?? null,
|
||||
'anchor' => $section['anchor'] ?? null,
|
||||
'content_id' => $rows[$id]->id ?? null,
|
||||
'theme_key' => $this->themeKey($section['group'], $section['key']),
|
||||
]);
|
||||
}
|
||||
|
||||
$pages[$pageKey] = [
|
||||
'title' => $page['title'],
|
||||
'path' => $page['path'] ?? null,
|
||||
'sections' => $sections,
|
||||
];
|
||||
}
|
||||
|
||||
$unlisted = $this->unlistedSections($rows->keys()->all(), $rows);
|
||||
|
||||
if ($unlisted !== []) {
|
||||
$pages[self::UNLISTED] = [
|
||||
'title' => config('cms_pages.unlisted.title', 'Nicht mehr verwendet'),
|
||||
'path' => null,
|
||||
'sections' => $unlisted,
|
||||
];
|
||||
}
|
||||
|
||||
return $pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eine Sektion aus der Registry samt Datenbankbezug, oder null.
|
||||
*
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
public function section(string $group, string $key): ?array
|
||||
{
|
||||
foreach ($this->pages() as $page) {
|
||||
foreach ($page['sections'] as $section) {
|
||||
if ($section['group'] === $group && $section['key'] === $key) {
|
||||
return $section;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Klartext-Beschriftung eines Feldes: Sektions-Override, dann Wörterbuch, sonst lesbar gemacht.
|
||||
*/
|
||||
public function fieldLabel(string $field, ?string $group = null, ?string $key = null): string
|
||||
{
|
||||
if ($group !== null && $key !== null) {
|
||||
foreach (config('cms_pages.pages', []) as $page) {
|
||||
foreach ($page['sections'] ?? [] as $section) {
|
||||
if ($section['group'] === $group && $section['key'] === $key && isset($section['fields'][$field])) {
|
||||
return $section['fields'][$field];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$labels = config('cms_pages.field_labels', []);
|
||||
|
||||
if (isset($labels[$field])) {
|
||||
return $labels[$field];
|
||||
}
|
||||
|
||||
return Str::ucfirst(str_replace('_', ' ', $field));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adresse der Vorschau für eine Sektion: Frontend-Domain, Pfad, Cache-Brecher und Sprungmarke.
|
||||
*/
|
||||
public function previewUrl(?array $section, int $version = 0): ?string
|
||||
{
|
||||
$path = $section['path'] ?? null;
|
||||
|
||||
if ($path === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$url = rtrim(config('domains.protocol', 'https://').config('domains.domain_b2in'), '/')
|
||||
.'/'.ltrim($path, '/')
|
||||
.'?cms-preview='.$version;
|
||||
|
||||
if (! empty($section['anchor'])) {
|
||||
$url .= '#'.$section['anchor'];
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme-Section-Schlüssel (Lang-Datei) zu Gruppe/Key, für „Aus Vorlage anlegen“.
|
||||
*/
|
||||
public function themeKey(string $group, string $key): ?string
|
||||
{
|
||||
foreach (config('cms_section_map.sections', []) as $themeKey => $target) {
|
||||
if ($target === [$group, $key]) {
|
||||
return $themeKey;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<string> $ids
|
||||
* @param \Illuminate\Support\Collection<string, CmsContent> $rows
|
||||
* @return list<array<string, mixed>>
|
||||
*/
|
||||
private function unlistedSections(array $ids, $rows): array
|
||||
{
|
||||
$listed = [];
|
||||
|
||||
foreach (config('cms_pages.pages', []) as $page) {
|
||||
foreach ($page['sections'] ?? [] as $section) {
|
||||
$listed[$section['group'].'/'.$section['key']] = true;
|
||||
}
|
||||
}
|
||||
|
||||
$out = [];
|
||||
|
||||
foreach ($ids as $id) {
|
||||
if (isset($listed[$id])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$row = $rows[$id];
|
||||
|
||||
$out[] = [
|
||||
'group' => $row->group,
|
||||
'key' => $row->key,
|
||||
'page' => self::UNLISTED,
|
||||
'path' => null,
|
||||
'anchor' => null,
|
||||
'title' => $row->group.' / '.$row->key,
|
||||
'description' => null,
|
||||
'content_id' => $row->id,
|
||||
'theme_key' => null,
|
||||
];
|
||||
}
|
||||
|
||||
usort($out, fn (array $a, array $b) => [$a['group'], $a['key']] <=> [$b['group'], $b['key']]);
|
||||
|
||||
return $out;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue