23-01-2026
This commit is contained in:
parent
8fd1f4d451
commit
389d5d1820
59 changed files with 9642 additions and 883 deletions
681
app/Services/NavigationTreeService.php
Normal file
681
app/Services/NavigationTreeService.php
Normal file
|
|
@ -0,0 +1,681 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Page;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class NavigationTreeService
|
||||
{
|
||||
/**
|
||||
* Cache-Zeit in Minuten
|
||||
* @var int
|
||||
*/
|
||||
protected $cacheTime = 60;
|
||||
|
||||
/**
|
||||
* Ob Caching aktiviert ist
|
||||
* @var bool
|
||||
*/
|
||||
protected $cacheEnabled = true;
|
||||
|
||||
/**
|
||||
* Aktiviert oder deaktiviert Caching
|
||||
*
|
||||
* @param bool $enabled
|
||||
* @return $this
|
||||
*/
|
||||
public function setCacheEnabled(bool $enabled): self
|
||||
{
|
||||
$this->cacheEnabled = $enabled;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setzt die Cache-Zeit
|
||||
*
|
||||
* @param int $minutes
|
||||
* @return $this
|
||||
*/
|
||||
public function setCacheTime(int $minutes): self
|
||||
{
|
||||
$this->cacheTime = $minutes;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Löscht den Navigation-Cache
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function clearCache(): void
|
||||
{
|
||||
Cache::forget('navigation_tree_full');
|
||||
Cache::forget('navigation_tree_active');
|
||||
Cache::forget('navigation_flat_full');
|
||||
Cache::forget('navigation_flat_active');
|
||||
|
||||
// Lösche auch alle Subtree-Caches
|
||||
$keys = Cache::get('navigation_subtree_keys', []);
|
||||
foreach ($keys as $key) {
|
||||
Cache::forget($key);
|
||||
}
|
||||
Cache::forget('navigation_subtree_keys');
|
||||
}
|
||||
/**
|
||||
* Gibt den kompletten Navigationsbaum zurück
|
||||
*
|
||||
* @param bool $onlyActive Nur aktive und sichtbare Seiten zurückgeben
|
||||
* @param bool $onlyShowInNavi Nur Seiten die in der Navigation angezeigt werden sollen
|
||||
* @return array
|
||||
*/
|
||||
public function getNavigationTree(bool $onlyActive = false, bool $onlyShowInNavi = false): array
|
||||
{
|
||||
$cacheKey = $onlyActive ? 'navigation_tree_active' : 'navigation_tree_full';
|
||||
|
||||
if ($this->cacheEnabled) {
|
||||
return Cache::remember($cacheKey, $this->cacheTime, function () use ($onlyActive, $onlyShowInNavi) {
|
||||
return $this->buildNavigationTree($onlyActive, $onlyShowInNavi);
|
||||
});
|
||||
}
|
||||
|
||||
return $this->buildNavigationTree($onlyActive, $onlyShowInNavi);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt den Navigationsbaum wie im Frontend zurück (nur Länderseiten mit Children)
|
||||
*
|
||||
* @param bool $includeHidden Auch ausgeblendete Pages anzeigen
|
||||
* @return array
|
||||
*/
|
||||
public function getFrontendNavigationTree(bool $includeHidden = false): array
|
||||
{
|
||||
$cacheKey = 'navigation_tree_frontend_' . ($includeHidden ? 'with_hidden' : 'visible');
|
||||
|
||||
if ($this->cacheEnabled) {
|
||||
return Cache::remember($cacheKey, $this->cacheTime, function () use ($includeHidden) {
|
||||
return $this->buildFrontendNavigationTree($includeHidden);
|
||||
});
|
||||
}
|
||||
|
||||
return $this->buildFrontendNavigationTree($includeHidden);
|
||||
}
|
||||
|
||||
/**
|
||||
* Baut den Frontend-Navigationsbaum auf
|
||||
*
|
||||
* @param bool $includeHidden
|
||||
* @return array
|
||||
*/
|
||||
protected function buildFrontendNavigationTree(bool $includeHidden = false): array
|
||||
{
|
||||
$tree = [];
|
||||
|
||||
// 1. Länderseiten (Hauptnavigation)
|
||||
$countryPages = $this->getCountryPages($includeHidden);
|
||||
foreach ($countryPages as $page) {
|
||||
$node = $this->buildFrontendNode($page, $includeHidden);
|
||||
if ($node) {
|
||||
$node['section'] = 'Länder-Navigation';
|
||||
$tree[] = $node;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Ferienwohnungen (USEDOM)
|
||||
$fewoPages = $this->getFewoPages($includeHidden);
|
||||
if (!empty($fewoPages)) {
|
||||
$tree[] = [
|
||||
'is_section_separator' => true,
|
||||
'title' => 'USEDOM Ferienwohnungen',
|
||||
'icon' => 'isv-fewo',
|
||||
'section' => 'Ferienwohnungen'
|
||||
];
|
||||
foreach ($fewoPages as $page) {
|
||||
$node = $this->buildFrontendNode($page, $includeHidden);
|
||||
if ($node) {
|
||||
$node['section'] = 'Ferienwohnungen';
|
||||
$tree[] = $node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Weitere wichtige Seiten (Mehr-Menü)
|
||||
$morePages = $this->getMoreMenuPages($includeHidden);
|
||||
if (!empty($morePages)) {
|
||||
$tree[] = [
|
||||
'is_section_separator' => true,
|
||||
'title' => 'Weitere Seiten (Mehr-Menü)',
|
||||
'icon' => 'fa fa-ellipsis-v',
|
||||
'section' => 'Mehr'
|
||||
];
|
||||
foreach ($morePages as $page) {
|
||||
$node = $this->buildFrontendNode($page, $includeHidden);
|
||||
if ($node) {
|
||||
$node['section'] = 'Mehr';
|
||||
$tree[] = $node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hole alle Länderseiten
|
||||
*
|
||||
* @param bool $includeHidden
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
protected function getCountryPages(bool $includeHidden = false)
|
||||
{
|
||||
$query = Page::whereNull('parent_id')
|
||||
->whereNotNull('country_id')
|
||||
->orderBy('order')
|
||||
->orderBy('title');
|
||||
|
||||
if (!$includeHidden) {
|
||||
$query->where('show_in_navi', 1);
|
||||
$query->where('status', 1);
|
||||
}
|
||||
|
||||
return $query->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hole Ferienwohnungs-Übersichtsseite mit Children
|
||||
*
|
||||
* @param bool $includeHidden
|
||||
* @return array
|
||||
*/
|
||||
protected function getFewoPages(bool $includeHidden = false)
|
||||
{
|
||||
// Suche die Hauptseite "Ferienwohnungen"
|
||||
$query = Page::where('slug', 'ferienwohnungen')
|
||||
->orWhere('real_url_path', '/ferienwohnungen');
|
||||
|
||||
if (!$includeHidden) {
|
||||
$query->where('status', 1);
|
||||
}
|
||||
|
||||
$fewoMainPage = $query->first();
|
||||
|
||||
if (!$fewoMainPage) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Nur die Hauptseite zurückgeben, Children werden über buildFrontendNode geladen
|
||||
return [$fewoMainPage];
|
||||
}
|
||||
|
||||
/**
|
||||
* Hole Seiten für "Mehr"-Menü
|
||||
*
|
||||
* @param bool $includeHidden
|
||||
* @return array
|
||||
*/
|
||||
protected function getMoreMenuPages(bool $includeHidden = false)
|
||||
{
|
||||
// Typische Slugs/Pfade aus dem Mehr-Menü mit ihren möglichen Children
|
||||
$morePages = [
|
||||
'ueber-uns' => true, // Könnte Children haben
|
||||
'reiseversicherung' => false, // Keine Children
|
||||
'reisefuehrer' => true, // Könnte Children haben
|
||||
'reisemagazin' => true, // Könnte Children haben
|
||||
'reisenews' => true // Könnte Children haben
|
||||
];
|
||||
|
||||
$pages = [];
|
||||
|
||||
foreach ($morePages as $slug => $hasChildren) {
|
||||
$query = Page::where('slug', $slug)
|
||||
->orWhere('real_url_path', '/' . $slug);
|
||||
|
||||
if (!$includeHidden) {
|
||||
$query->where('status', 1);
|
||||
}
|
||||
|
||||
$page = $query->first();
|
||||
if ($page) {
|
||||
$pages[] = $page;
|
||||
}
|
||||
}
|
||||
|
||||
return $pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Baut einen Frontend-Node auf (mit Children gruppiert nach beforeTitle)
|
||||
*
|
||||
* @param Page $page
|
||||
* @param bool $includeHidden
|
||||
* @param bool $loadChildren Soll Children geladen werden?
|
||||
* @return array|null
|
||||
*/
|
||||
protected function buildFrontendNode(Page $page, bool $includeHidden = false, bool $loadChildren = true): ?array
|
||||
{
|
||||
$node = $this->buildNodeData($page, true);
|
||||
|
||||
if (!$loadChildren) {
|
||||
$node['children'] = [];
|
||||
$node['has_children'] = false;
|
||||
return $node;
|
||||
}
|
||||
|
||||
// Hole Children
|
||||
$query = Page::where('parent_id', $page->id)
|
||||
->orderBy('order')
|
||||
->orderBy('title');
|
||||
|
||||
if (!$includeHidden) {
|
||||
$query->where('show_in_navi', 1);
|
||||
$query->where('status', 1);
|
||||
}
|
||||
|
||||
$children = $query->get();
|
||||
|
||||
// Gruppiere Children nach beforeTitle
|
||||
$groupedChildren = [
|
||||
'main' => [],
|
||||
'infos' => []
|
||||
];
|
||||
|
||||
foreach ($children as $child) {
|
||||
$childNode = $this->buildNodeData($child, true);
|
||||
|
||||
if ($child->before_title === 'Infos') {
|
||||
$groupedChildren['infos'][] = $childNode;
|
||||
} else {
|
||||
$groupedChildren['main'][] = $childNode;
|
||||
}
|
||||
}
|
||||
|
||||
// Baue finale Children-Liste mit Gruppierung
|
||||
$finalChildren = [];
|
||||
|
||||
// Erst Haupt-Children
|
||||
foreach ($groupedChildren['main'] as $childNode) {
|
||||
$finalChildren[] = $childNode;
|
||||
}
|
||||
|
||||
// Dann Info-Children mit Separator
|
||||
if (!empty($groupedChildren['infos'])) {
|
||||
$finalChildren[] = [
|
||||
'is_separator' => true,
|
||||
'title' => 'Infos',
|
||||
'icon' => 'fa fa-info-circle'
|
||||
];
|
||||
foreach ($groupedChildren['infos'] as $childNode) {
|
||||
$finalChildren[] = $childNode;
|
||||
}
|
||||
}
|
||||
|
||||
$node['children'] = $finalChildren;
|
||||
$node['has_children'] = count($finalChildren) > 0;
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Baut den Navigationsbaum auf (ohne Caching)
|
||||
*
|
||||
* @param bool $onlyActive
|
||||
* @param bool $onlyShowInNavi
|
||||
* @return array
|
||||
*/
|
||||
protected function buildNavigationTree(bool $onlyActive = false, bool $onlyShowInNavi = false): array
|
||||
{
|
||||
// Hole alle Root-Seiten (ohne Parent)
|
||||
$query = Page::whereNull('parent_id')
|
||||
->orderBy('order')
|
||||
->orderBy('title');
|
||||
|
||||
if ($onlyActive) {
|
||||
$query->where('status', 1);
|
||||
}
|
||||
|
||||
if ($onlyShowInNavi) {
|
||||
$query->where('show_in_navi', 1);
|
||||
}
|
||||
|
||||
$rootPages = $query->get();
|
||||
|
||||
$tree = [];
|
||||
foreach ($rootPages as $page) {
|
||||
$tree[] = $this->buildNode($page, $onlyActive, $onlyShowInNavi);
|
||||
}
|
||||
|
||||
return $tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt einen Teilbaum zurück, beginnend mit einer bestimmten Page
|
||||
*
|
||||
* @param int $rootId Die ID der Root-Page
|
||||
* @param bool $onlyActive Nur aktive Seiten zurückgeben
|
||||
* @param bool $onlyShowInNavi Nur Seiten die in der Navigation angezeigt werden sollen
|
||||
* @return array|null
|
||||
*/
|
||||
public function getNavigationSubTree(int $rootId, bool $onlyActive = false, bool $onlyShowInNavi = false): ?array
|
||||
{
|
||||
$cacheKey = "navigation_subtree_{$rootId}_" . ($onlyActive ? 'active' : 'full');
|
||||
|
||||
if ($this->cacheEnabled) {
|
||||
// Speichere Cache-Key für späteres Löschen
|
||||
$keys = Cache::get('navigation_subtree_keys', []);
|
||||
if (!in_array($cacheKey, $keys)) {
|
||||
$keys[] = $cacheKey;
|
||||
Cache::put('navigation_subtree_keys', $keys, $this->cacheTime);
|
||||
}
|
||||
|
||||
return Cache::remember($cacheKey, $this->cacheTime, function () use ($rootId, $onlyActive, $onlyShowInNavi) {
|
||||
return $this->buildSubTree($rootId, $onlyActive, $onlyShowInNavi);
|
||||
});
|
||||
}
|
||||
|
||||
return $this->buildSubTree($rootId, $onlyActive, $onlyShowInNavi);
|
||||
}
|
||||
|
||||
/**
|
||||
* Baut einen Teilbaum auf (ohne Caching)
|
||||
*
|
||||
* @param int $rootId
|
||||
* @param bool $onlyActive
|
||||
* @param bool $onlyShowInNavi
|
||||
* @return array|null
|
||||
*/
|
||||
protected function buildSubTree(int $rootId, bool $onlyActive = false, bool $onlyShowInNavi = false): ?array
|
||||
{
|
||||
$page = Page::find($rootId);
|
||||
|
||||
if (!$page) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->buildNode($page, $onlyActive, $onlyShowInNavi);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt eine flache Liste aller Navigationspunkte zurück
|
||||
*
|
||||
* @param bool $onlyActive Nur aktive Seiten zurückgeben
|
||||
* @param bool $onlyShowInNavi Nur Seiten die in der Navigation angezeigt werden sollen
|
||||
* @return array
|
||||
*/
|
||||
public function getFlatNavigationList(bool $onlyActive = false, bool $onlyShowInNavi = false): array
|
||||
{
|
||||
$cacheKey = $onlyActive ? 'navigation_flat_active' : 'navigation_flat_full';
|
||||
|
||||
if ($this->cacheEnabled) {
|
||||
return Cache::remember($cacheKey, $this->cacheTime, function () use ($onlyActive, $onlyShowInNavi) {
|
||||
return $this->buildFlatList($onlyActive, $onlyShowInNavi);
|
||||
});
|
||||
}
|
||||
|
||||
return $this->buildFlatList($onlyActive, $onlyShowInNavi);
|
||||
}
|
||||
|
||||
/**
|
||||
* Baut eine flache Liste auf (ohne Caching)
|
||||
*
|
||||
* @param bool $onlyActive
|
||||
* @param bool $onlyShowInNavi
|
||||
* @return array
|
||||
*/
|
||||
protected function buildFlatList(bool $onlyActive = false, bool $onlyShowInNavi = false): array
|
||||
{
|
||||
$query = Page::orderBy('order')
|
||||
->orderBy('title');
|
||||
|
||||
if ($onlyActive) {
|
||||
$query->where('status', 1);
|
||||
}
|
||||
|
||||
if ($onlyShowInNavi) {
|
||||
$query->where('show_in_navi', 1);
|
||||
}
|
||||
|
||||
$pages = $query->get();
|
||||
|
||||
$list = [];
|
||||
foreach ($pages as $page) {
|
||||
$list[] = $this->buildNodeData($page, false);
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Baut einen einzelnen Knoten mit allen Kindern rekursiv auf
|
||||
*
|
||||
* @param Page $page
|
||||
* @param bool $onlyActive
|
||||
* @param bool $onlyShowInNavi
|
||||
* @return array
|
||||
*/
|
||||
protected function buildNode(Page $page, bool $onlyActive = false, bool $onlyShowInNavi = false): array
|
||||
{
|
||||
$node = $this->buildNodeData($page, true);
|
||||
|
||||
// Hole alle Child-Seiten
|
||||
$query = Page::where('parent_id', $page->id)
|
||||
->orderBy('order')
|
||||
->orderBy('title');
|
||||
|
||||
if ($onlyActive) {
|
||||
$query->where('status', 1);
|
||||
}
|
||||
|
||||
if ($onlyShowInNavi) {
|
||||
$query->where('show_in_navi', 1);
|
||||
}
|
||||
|
||||
$children = $query->get();
|
||||
|
||||
$childNodes = [];
|
||||
foreach ($children as $child) {
|
||||
$childNodes[] = $this->buildNode($child, $onlyActive, $onlyShowInNavi);
|
||||
}
|
||||
|
||||
$node['children'] = $childNodes;
|
||||
$node['has_children'] = count($childNodes) > 0;
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt die Datenstruktur für einen einzelnen Navigationspunkt
|
||||
*
|
||||
* @param Page $page
|
||||
* @param bool $includeRelations Beziehungen laden (TravelProgram, etc.)
|
||||
* @return array
|
||||
*/
|
||||
protected function buildNodeData(Page $page, bool $includeRelations = true): array
|
||||
{
|
||||
$data = [
|
||||
'id' => $page->id,
|
||||
'title' => $page->title,
|
||||
'title_short' => $page->title_short,
|
||||
'before_title' => $page->before_title,
|
||||
'slug' => $page->slug,
|
||||
'real_url_path' => $page->real_url_path,
|
||||
'url' => $page->real_url_path ?: $this->buildUrlPath($page),
|
||||
'status' => $page->status,
|
||||
'show_in_navi' => $page->show_in_navi,
|
||||
'order' => $page->order,
|
||||
'template' => $page->template,
|
||||
'lvl' => $page->lvl,
|
||||
'parent_id' => $page->parent_id,
|
||||
|
||||
// SEO-Informationen
|
||||
'pagetitle' => $page->pagetitle,
|
||||
'description' => $page->description,
|
||||
'keywords' => $page->keywords,
|
||||
'canonical_url' => $page->canonical_url,
|
||||
|
||||
// Tree-Informationen
|
||||
'lft' => $page->lft,
|
||||
'rgt' => $page->rgt,
|
||||
'tree_root' => $page->tree_root,
|
||||
|
||||
// Box-Informationen (für Karten/Boxen in der Navigation)
|
||||
'box_body' => $page->box_body,
|
||||
'box_image_url' => $page->box_image_url,
|
||||
'box_star' => $page->box_star,
|
||||
'box_discount' => $page->box_discount,
|
||||
|
||||
// Zusätzliche Flags
|
||||
'is_travel_program' => !is_null($page->travel_program),
|
||||
'is_fewo_lodging' => !is_null($page->fewo_lodging),
|
||||
'is_country_page' => !is_null($page->country_id),
|
||||
];
|
||||
|
||||
if ($includeRelations) {
|
||||
// Lade Beziehungen wenn benötigt
|
||||
if ($page->travel_program) {
|
||||
$travelProgram = $page->travel_program_content;
|
||||
if ($travelProgram) {
|
||||
$data['travel_program'] = [
|
||||
'id' => $travelProgram->id,
|
||||
'title' => $travelProgram->title,
|
||||
'subtitle' => $travelProgram->subtitle,
|
||||
'status' => $travelProgram->status,
|
||||
'position' => $travelProgram->position,
|
||||
'duration' => $travelProgram->duration,
|
||||
'price_from' => $travelProgram->price_from,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if ($page->fewo_lodging) {
|
||||
$fewoLodging = $page->fewo_lodging();
|
||||
if ($fewoLodging) {
|
||||
$fewo = $fewoLodging->first();
|
||||
if ($fewo) {
|
||||
$data['fewo_lodging'] = [
|
||||
'id' => $fewo->id,
|
||||
'name' => $fewo->name,
|
||||
'status' => $fewo->status,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($page->country_id) {
|
||||
$country = $page->travel_country;
|
||||
if ($country) {
|
||||
$data['country'] = [
|
||||
'id' => $country->id,
|
||||
'name' => $country->name,
|
||||
'title' => $country->title,
|
||||
'slug' => $country->slug,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CMS Settings (JSON)
|
||||
if ($page->cms_settings) {
|
||||
try {
|
||||
$data['cms_settings'] = json_decode($page->cms_settings, true);
|
||||
} catch (\Exception $e) {
|
||||
$data['cms_settings'] = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Baut den URL-Pfad für eine Page rekursiv auf (Fallback wenn real_url_path nicht gesetzt)
|
||||
*
|
||||
* @param Page $page
|
||||
* @return string
|
||||
*/
|
||||
protected function buildUrlPath(Page $page): string
|
||||
{
|
||||
$slugs = [];
|
||||
$current = $page;
|
||||
|
||||
// Sammle alle Slugs von unten nach oben
|
||||
while ($current) {
|
||||
if ($current->slug) {
|
||||
array_unshift($slugs, $current->slug);
|
||||
}
|
||||
$current = $current->parent_page;
|
||||
}
|
||||
|
||||
return '/' . implode('/', $slugs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zählt die Anzahl der Knoten im Baum
|
||||
*
|
||||
* @param array $tree
|
||||
* @return int
|
||||
*/
|
||||
public function countNodes(array $tree): int
|
||||
{
|
||||
$count = 0;
|
||||
foreach ($tree as $node) {
|
||||
$count++; // Zähle den aktuellen Knoten
|
||||
if (isset($node['children']) && is_array($node['children'])) {
|
||||
$count += $this->countNodes($node['children']);
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Findet einen Knoten anhand seiner ID im Baum
|
||||
*
|
||||
* @param array $tree
|
||||
* @param int $nodeId
|
||||
* @return array|null
|
||||
*/
|
||||
public function findNodeById(array $tree, int $nodeId): ?array
|
||||
{
|
||||
foreach ($tree as $node) {
|
||||
if ($node['id'] === $nodeId) {
|
||||
return $node;
|
||||
}
|
||||
if (isset($node['children']) && is_array($node['children'])) {
|
||||
$found = $this->findNodeById($node['children'], $nodeId);
|
||||
if ($found) {
|
||||
return $found;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt den Breadcrumb-Pfad für eine bestimmte Page zurück
|
||||
*
|
||||
* @param int $pageId
|
||||
* @return array
|
||||
*/
|
||||
public function getBreadcrumb(int $pageId): array
|
||||
{
|
||||
$page = Page::find($pageId);
|
||||
if (!$page) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$breadcrumb = [];
|
||||
$current = $page;
|
||||
|
||||
while ($current) {
|
||||
array_unshift($breadcrumb, [
|
||||
'id' => $current->id,
|
||||
'title' => $current->title,
|
||||
'title_short' => $current->title_short,
|
||||
'url' => $current->real_url_path ?: $this->buildUrlPath($current),
|
||||
'slug' => $current->slug,
|
||||
]);
|
||||
$current = $current->parent_page;
|
||||
}
|
||||
|
||||
return $breadcrumb;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue