navigationService = $navigationService; } /** * Zeigt die Navigationsbaum-Übersicht * * @return \Illuminate\View\View */ public function index() { return view('navigation.index', [ 'lfm_helper' => app(Lfm::class), ]); } /** * Gibt die Navigationsbaum-Daten als JSON zurück (Frontend-Struktur) * * @param Request $request * @return JsonResponse */ public function getData(Request $request): JsonResponse { try { $mode = $request->get('mode', 'sitemap'); $includeHidden = $request->get('include_hidden', false); $onlyActive = !$includeHidden; if ($mode === 'sitemap') { $tree = $this->navigationService->getSitemapTree($onlyActive); return response()->json([ 'success' => true, 'data' => $tree, 'meta' => [ 'total_nodes' => $this->navigationService->countNodes($tree), 'missing_preview_images' => $this->navigationService->countMissingPreviewImages($tree), 'include_hidden' => $includeHidden, 'structure' => 'sitemap', ], ]); } $tree = $this->navigationService->getFrontendNavigationTree($includeHidden); return response()->json([ 'success' => true, 'data' => $tree, 'meta' => [ 'total_nodes' => $this->navigationService->countNodes($tree), 'include_hidden' => $includeHidden, 'structure' => 'header', ], ]); } catch (\Exception $e) { return response()->json([ 'success' => false, 'error' => $e->getMessage() ], 500); } } /** * Sucht im Navigationsbaum * * @param Request $request * @return JsonResponse */ public function search(Request $request): JsonResponse { try { $query = $request->get('query', ''); $flatList = $this->navigationService->getFlatNavigationList(); // Filtere nach Suchbegriff $results = array_filter($flatList, function ($node) use ($query) { return stripos($node['title'], $query) !== false || stripos($node['slug'], $query) !== false || stripos($node['url'], $query) !== false; }); return response()->json([ 'success' => true, 'data' => array_values($results), 'meta' => [ 'query' => $query, 'total_results' => count($results) ] ]); } catch (\Exception $e) { return response()->json([ 'success' => false, 'error' => $e->getMessage() ], 500); } } /** * Exportiert den Navigationsbaum als JSON-Datei * * @param Request $request * @return \Illuminate\Http\Response */ public function export(Request $request) { try { $mode = $request->get('mode', 'sitemap'); $includeHidden = $request->get('include_hidden', false); $onlyActive = !$includeHidden; if ($mode === 'sitemap') { $tree = $this->navigationService->getSitemapTree($onlyActive); $filename = 'sitemap-tree-' . date('Y-m-d-His') . '.json'; } else { $tree = $this->navigationService->getFrontendNavigationTree($includeHidden); $filename = 'navigation-tree-frontend-' . date('Y-m-d-His') . '.json'; } $json = json_encode($tree, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); return response($json) ->header('Content-Type', 'application/json') ->header('Content-Disposition', 'attachment; filename="' . $filename . '"'); } catch (\Exception $e) { return back()->with('error', 'Export fehlgeschlagen: ' . $e->getMessage()); } } /** * Löscht den Cache * * @return \Illuminate\Http\RedirectResponse */ public function clearCache(Request $request) { try { $this->navigationService->clearCache(); if ($request->expectsJson() || $request->ajax()) { return response()->json(['success' => true]); } return back()->with('success', 'Navigation-Cache erfolgreich gelöscht'); } catch (\Exception $e) { if ($request->expectsJson() || $request->ajax()) { return response()->json(['success' => false, 'error' => $e->getMessage()], 500); } return back()->with('error', 'Cache-Löschung fehlgeschlagen: ' . $e->getMessage()); } } /** * Zeigt die Statistiken * * @return JsonResponse */ public function stats(): JsonResponse { try { $allTree = $this->navigationService->getNavigationTree(false); $activeTree = $this->navigationService->getNavigationTree(true); $flatList = $this->navigationService->getFlatNavigationList(); // Zähle verschiedene Typen $stats = [ 'total_pages' => count($flatList), 'total_nodes' => $this->navigationService->countNodes($allTree), 'active_nodes' => $this->navigationService->countNodes($activeTree), 'inactive_nodes' => $this->navigationService->countNodes($allTree) - $this->navigationService->countNodes($activeTree), 'travel_programs' => count(array_filter($flatList, fn($n) => $n['is_travel_program'])), 'fewo_lodgings' => count(array_filter($flatList, fn($n) => $n['is_fewo_lodging'])), 'country_pages' => count(array_filter($flatList, fn($n) => $n['is_country_page'])), 'missing_preview_images' => $this->navigationService->countMissingPreviewImages( $this->navigationService->getSitemapTree(false) ), ]; return response()->json([ 'success' => true, 'data' => $stats ]); } catch (\Exception $e) { return response()->json([ 'success' => false, 'error' => $e->getMessage() ], 500); } } /** * Setzt oder löscht box_image_url einer Seite. */ public function updateBoxImage(Request $request, int $id): JsonResponse { try { $page = Page::findOrFail($id); $action = $request->input('action'); if ($action === 'clear') { if (empty($page->box_image_url)) { return response()->json([ 'success' => false, 'error' => 'Für diese Seite ist kein verknüpftes Seitenbild (box_image_url) hinterlegt.', ], 422); } if (!$this->navigationService->pageCanClearBoxImage($page)) { return response()->json([ 'success' => false, 'error' => 'Das Seitenbild kann hier nicht entfernt werden, weil kein Reiseprogramm-Bild als Ersatz vorhanden ist.', ], 422); } $page->box_image_url = null; $page->save(); } elseif ($action === 'clear_box_body') { if (!$this->navigationService->pageHasBoxBodyPreview($page)) { return response()->json([ 'success' => false, 'error' => 'Für diese Seite ist kein Legacy-Bild (box_body) hinterlegt.', ], 422); } $page->box_body = null; $page->save(); } elseif ($action === 'set') { $url = trim((string) $request->input('box_image_url', '')); if ($url === '') { return response()->json([ 'success' => false, 'error' => 'Bitte wählen Sie zuerst ein Bild aus der Mediathek.', ], 422); } $page->box_image_url = $url; $page->save(); } else { return response()->json([ 'success' => false, 'error' => 'Ungültige Aktion.', ], 422); } $this->navigationService->clearCache(); return response()->json([ 'success' => true, 'message' => match ($action) { 'clear' => 'Das verknüpfte Seitenbild wurde entfernt.', 'clear_box_body' => 'Das Legacy-Bild (box_body) wurde entfernt.', default => 'Das neue Seitenbild wurde gespeichert.', }, ]); } catch (\Exception $e) { return response()->json([ 'success' => false, 'error' => $e->getMessage(), ], 500); } } }