getCurrentUser(); if (!$user) { return new RedirectResponse(url('login')); } $theme = $request->query->get('theme', \Kernel\View::getActiveTheme() ?? 'default'); $pagesKeys = $this->getPagesKeys($theme); $pages = []; foreach ($pagesKeys as $key) { $pages[$key] = ucfirst($key); } $themesDir = dirname(dirname(dirname(dirname(__DIR__)))) . '/themes'; $availableThemes = ['default' => 'Default']; if (is_dir($themesDir)) { $folders = array_diff(scandir($themesDir), ['.', '..']); foreach ($folders as $folder) { if (is_dir($themesDir . '/' . $folder)) { $availableThemes[$folder] = ucfirst($folder); } } } return $this->renderAdminView('configindex/views/admin/index.twig', [ 'title' => __('configindex.title'), 'pages' => $pages, 'currentTheme' => $theme, 'availableThemes' => $availableThemes ]); } /** * Show create form */ public function create(Request $request): Response { $user = $this->getCurrentUser(); if (!$user) { return new RedirectResponse(url('login')); } return $this->renderAdminView('configindex/views/admin/create.twig', [ 'title' => 'Nova Página Index' ]); } /** * Store new page */ public function store(Request $request): Response { $user = $this->getCurrentUser(); if (!$user) { return new RedirectResponse(url('login')); } $key = $request->request->get('key'); if (!$key) { return new RedirectResponse(url('admin/configindex/create?error=missing_key')); } // Sanitiza a chave (slug) $key = strtolower(preg_replace('/[^a-zA-Z0-9_-]/', '', $key)); $busId = $user->users_bus_id ?? 1; // Verifica se já existe $existing = ConfigPage::getByKey($key, $busId); if ($existing) { return new RedirectResponse(url('admin/configindex/create?error=already_exists')); } // Cria o registro no banco $page = new ConfigPage(); $page->config_index_bus_id = $busId; $page->config_index_key = $key; $page->config_index_title = ucfirst($key); $page->config_index_show_public_nav = true; $page->config_index_show_dashboard_nav = true; $page->save(); // Cria o arquivo físico se não existir $viewsPath = dirname(__DIR__, 3) . '/index/views'; $templatePath = $viewsPath . '/' . $key . '.twig'; if (!is_dir($viewsPath)) { mkdir($viewsPath, 0755, true); } if (!is_file($templatePath)) { $defaultContent = "{% extends '@index/layout.twig' %}\n\n{% block content %}\n
\n

{{ __('index." . $key . ".title') }}

\n

{{ __('index." . $key . ".description') }}

\n
\n{% endblock %}\n"; file_put_contents($templatePath, $defaultContent); } // Cria arquivos de tradução padrão $localesPath = dirname(__DIR__, 3) . '/index/locales'; $languages = ['pt_BR', 'en_US', 'es_ES', 'de_DE', 'fr_FR']; foreach ($languages as $lang) { $savePath = $localesPath . '/' . $lang . '/index.json'; if (!is_dir(dirname($savePath))) { mkdir(dirname($savePath), 0755, true); } $base = []; if (is_file($savePath)) { $base = json_decode(file_get_contents($savePath), true) ?: []; } if (!isset($base[$key])) { $base[$key] = [ 'title' => ucfirst($key), 'description' => 'Conteúdo da página ' . $key ]; file_put_contents($savePath, json_encode($base, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); } } return new RedirectResponse(url('admin/configindex/' . $key . '/edit?success=created')); } /** * Get all valid page keys for a theme */ private function getPagesKeys(string $themeSlug): array { $keys = []; $baseDir = dirname(dirname(dirname(dirname(__DIR__)))); // 1. Coleta do módulo index (Padrão do Sistema) $indexViewsPath = $baseDir . '/modules/index/views'; if (is_dir($indexViewsPath)) { $files = glob($indexViewsPath . '/*.{twig,php}', GLOB_BRACE); foreach ($files as $file) { $filename = pathinfo($file, PATHINFO_FILENAME); if ($filename !== 'layout') { $keys[] = $filename; } } } // 2. Coleta do Tema (Se houver overrides de módulos) $themeModuleViewsPath = $baseDir . '/themes/' . $themeSlug . '/modules/index/views'; if (is_dir($themeModuleViewsPath)) { $files = glob($themeModuleViewsPath . '/*.{twig,php}', GLOB_BRACE); foreach ($files as $file) { $filename = pathinfo($file, PATHINFO_FILENAME); if ($filename !== 'layout') { $keys[] = $filename; } } } // 3. Coleta do Tema (Views genéricas na raiz do tema ou subpasta views) $themeRootViews = [ $baseDir . '/themes/' . $themeSlug, $baseDir . '/themes/' . $themeSlug . '/views' ]; foreach ($themeRootViews as $path) { if (is_dir($path)) { $files = glob($path . '/*.{twig,php}', GLOB_BRACE); foreach ($files as $file) { $filename = pathinfo($file, PATHINFO_FILENAME); // Ignorar arquivos de sistema e layouts if (!in_array($filename, ['layout', 'header', 'footer', 'sidebar'])) { $keys[] = $filename; } } } } if (empty($keys)) { $keys = ['index', 'about', 'contact', 'services']; } return array_unique($keys); } /** * Show edit form */ public function edit(Request $request, string $key): Response { $user = $this->getCurrentUser(); if (!$user) { return new RedirectResponse(url('login')); } $theme = $request->query->get('theme', \Kernel\View::getActiveTheme() ?? 'default'); $busId = $user->users_bus_id ?? 1; $page = ConfigPage::getByKey($key, $busId); $templateCode = null; $baseDir = dirname(dirname(dirname(dirname(__DIR__)))); // Prioridade de busca do arquivo para edição: // 1. Override do módulo no tema selecionado $paths = [ $baseDir . '/themes/' . $theme . '/modules/index/views/' . $key . '.twig', $baseDir . '/themes/' . $theme . '/modules/index/views/' . $key . '.php', $baseDir . '/themes/' . $theme . '/' . $key . '.twig', $baseDir . '/themes/' . $theme . '/' . $key . '.php', $baseDir . '/themes/' . $theme . '/views/' . $key . '.twig', $baseDir . '/themes/' . $theme . '/views/' . $key . '.php', $baseDir . '/modules/index/views/' . $key . '.twig', $baseDir . '/modules/index/views/' . $key . '.php', ]; $foundPath = null; foreach ($paths as $path) { if (is_file($path)) { $templateCode = file_get_contents($path); $foundPath = $path; break; } } $languagesMap = []; // Locais de tradução: Módulo index + Tema selecionado $localesPaths = [ $baseDir . '/modules/index/locales', $baseDir . '/themes/' . $theme . '/locales' ]; foreach ($localesPaths as $base) { if (is_dir($base)) { foreach (glob($base . '/*', GLOB_ONLYDIR) as $dir) { $languagesMap[basename($dir)] = true; } } } $languages = array_keys($languagesMap); if (empty($languages)) { $languages = ['pt_BR', 'en_US', 'es_ES', 'de_DE', 'fr_FR']; } sort($languages); $validKeys = $this->getPagesKeys($theme); $translationsIndexSection = []; foreach ($languages as $lang) { $langData = []; foreach ($localesPaths as $base) { $path = $base . '/' . $lang . '/index.json'; if (is_file($path)) { $decoded = json_decode(file_get_contents($path), true); if (is_array($decoded)) { $langData = array_merge($langData, $decoded); } } } if ($key === 'index') { $indexData = []; foreach ($langData as $k => $v) { if (!in_array($k, $validKeys) || $k === 'index') { $indexData[$k] = $v; } } $translationsIndexSection[$lang] = json_encode($indexData, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); } elseif (isset($langData[$key])) { $translationsIndexSection[$lang] = json_encode($langData[$key], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); } else { $translationsIndexSection[$lang] = json_encode(new \stdClass(), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); } } return $this->renderAdminView('configindex/views/admin/edit.twig', [ 'title' => __('configindex.edit_title', ['page' => ucfirst($key)]), 'page_key' => $key, 'page_data' => $page, 'template_code' => $templateCode, 'languages' => $languages, 'translations_index_section' => $translationsIndexSection, 'currentTheme' => $theme, 'foundPath' => $foundPath, 'base_path' => $baseDir ]); } /** * Update page content */ public function update(Request $request, string $key): Response { try { $user = $this->getCurrentUser(); if (!$user) { return new RedirectResponse(url('login')); } $busId = $user->users_bus_id ?? 1; $data = $request->request->all(); $page = ConfigPage::getByKey($key, $busId); if (!$page) { $page = new ConfigPage(); $page->config_index_bus_id = $busId; $page->config_index_key = $key; $page->config_index_title = ucfirst($key); $page->config_index_meta_title = ''; $page->config_index_meta_description = ''; } if (isset($data['content'])) { $page->config_index_content = $data['content']; } $page->config_index_show_public_nav = !empty($data['config_index_show_public_nav']); $page->config_index_show_dashboard_nav = !empty($data['config_index_show_dashboard_nav']); $page->save(); $codeToWrite = $data['content'] ?? ($data['template_code'] ?? null); if ($codeToWrite !== null) { $theme = $request->query->get('theme', \Kernel\View::getActiveTheme() ?? 'default'); $baseDir = dirname(dirname(dirname(dirname(__DIR__)))); // Determina o caminho de salvamento baseado no tema if ($theme === 'default') { $templatePath = $baseDir . '/modules/index/views/' . $key . '.twig'; // Fallback para .php se já existir if (!is_file($templatePath) && is_file(str_replace('.twig', '.php', $templatePath))) { $templatePath = str_replace('.twig', '.php', $templatePath); } } else { // Para temas, salvamos no override do módulo dentro do tema $templatePath = $baseDir . '/themes/' . $theme . '/modules/index/views/' . $key . '.twig'; } $viewsDir = dirname($templatePath); if (!is_dir($viewsDir)) { mkdir($viewsDir, 0755, true); } file_put_contents($templatePath, $codeToWrite); } // Update translations $translations = $request->request->all('translations_index_section'); if (is_array($translations)) { $theme = $request->query->get('theme', \Kernel\View::getActiveTheme() ?? 'default'); $baseDir = dirname(dirname(dirname(dirname(__DIR__)))); // Salva no local apropriado (Módulo ou Tema) if ($theme === 'default') { $localesBase = $baseDir . '/modules/index/locales'; } else { $localesBase = $baseDir . '/themes/' . $theme . '/locales'; } foreach ($translations as $lang => $json) { if ($json !== null && $json !== '') { $section = json_decode($json, true); if (is_array($section)) { $savePath = $localesBase . '/' . $lang . '/index.json'; if (!is_dir(dirname($savePath))) { mkdir(dirname($savePath), 0755, true); } $base = []; if (is_file($savePath)) { $base = json_decode(file_get_contents($savePath), true) ?: []; } if ($key === 'index') { // Mescla chaves soltas na raiz, preservando outras páginas $newBase = $section; foreach ($base as $k => $v) { if (is_array($v) && $k !== 'index' && $k !== 'layout' && $k !== 'menu') { $newBase[$k] = $v; } } $base = $newBase; } else { // Salva na seção da página $base[$key] = $section; } file_put_contents($savePath, json_encode($base, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); } } } } try { \Kernel\Translator::setLocale(\Kernel\Translator::getLocale()); } catch (\Throwable $e) { } $theme = $request->query->get('theme', \Kernel\View::getActiveTheme() ?? 'default'); return new RedirectResponse(url('admin/configindex/' . $key . '/edit?theme=' . $theme . '&success=updated')); } catch (\Exception $e) { error_log("Error in ConfigIndexController::update: " . $e->getMessage()); return new Response("Internal Server Error: " . $e->getMessage(), 500); } } /** * Toggle page visibility status */ public function toggleStatus(Request $request, string $key): Response { $user = $this->getCurrentUser(); if (!$user) { return new RedirectResponse(url('login')); } $busId = $user->users_bus_id ?? 1; $page = ConfigPage::getByKey($key, $busId); if ($page) { $page->config_index_show_public_nav = !$page->config_index_show_public_nav; $page->save(); } return new RedirectResponse(url('admin/configindex?success=status_updated')); } /** * Delete page and associated files */ public function destroy(Request $request, string $key): Response { $user = $this->getCurrentUser(); if (!$user) { return new RedirectResponse(url('login')); } // Não permitir excluir a home (index) if ($key === 'index') { return new RedirectResponse(url('admin/configindex?error=cannot_delete_home')); } $busId = $user->users_bus_id ?? 1; $page = ConfigPage::getByKey($key, $busId); if ($page) { $page->delete(); } // Remover arquivos físicos (.twig) $viewsPath = dirname(__DIR__, 3) . '/index/views'; $templatePath = $viewsPath . '/' . $key . '.twig'; if (is_file($templatePath)) { unlink($templatePath); } // Remover de .php se existir $phpPath = $viewsPath . '/' . $key . '.php'; if (is_file($phpPath)) { unlink($phpPath); } // Remover traduções dos arquivos index.json $localesPath = dirname(__DIR__, 3) . '/index/locales'; $languages = ['pt_BR', 'en_US', 'es_ES', 'de_DE', 'fr_FR']; foreach ($languages as $lang) { $savePath = $localesPath . '/' . $lang . '/index.json'; if (is_file($savePath)) { $base = json_decode(file_get_contents($savePath), true) ?: []; if (isset($base[$key])) { unset($base[$key]); file_put_contents($savePath, json_encode($base, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); } } } return new RedirectResponse(url('admin/configindex?success=deleted')); } }