Files
2026-09-01 10:46:29 -03:00

494 lines
18 KiB
PHP
Executable File

<?php
namespace Modules\Configindex\Controllers;
use App\Controllers\BaseAdminController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Modules\Configindex\Models\ConfigPage;
class ConfigIndexController extends BaseAdminController
{
/**
* List pages to configure
*/
public function index(Request $request): Response
{
$user = $this->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<div class=\"container my-5\">\n <h1>{{ __('index." . $key . ".title') }}</h1>\n <p>{{ __('index." . $key . ".description') }}</p>\n</div>\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'));
}
}