From 02e4f466947d8909b1d7c7302971a223a471afb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Cmit=20Tun=C3=A7?= Date: Fri, 31 Oct 2025 15:49:29 -0300 Subject: [PATCH] Implement dynamic template rendering and page observer: Enhanced PageController to support dynamic header and footer templates, utilizing TemplateService for placeholder replacement. Introduced PageObserver to manage homepage status across pages. Updated routes for improved debugging and dynamic homepage display. Refactored views to accommodate new templating system. --- app/Http/Controllers/PageController.php | 104 +++++++++++++++----- app/Models/Page.php | 1 + app/Observers/PageObserver.php | 26 +++++ app/Providers/AppServiceProvider.php | 5 +- app/Services/TemplateService.php | 44 ++++++++- resources/views/layouts/site.blade.php | 17 +++- resources/views/templates/generic.blade.php | 23 ++++- resources/views/templates/home.blade.php | 19 +++- routes/web.php | 57 ++++++++++- 9 files changed, 259 insertions(+), 37 deletions(-) create mode 100644 app/Observers/PageObserver.php diff --git a/app/Http/Controllers/PageController.php b/app/Http/Controllers/PageController.php index a23b609..d82eb8a 100644 --- a/app/Http/Controllers/PageController.php +++ b/app/Http/Controllers/PageController.php @@ -4,6 +4,7 @@ namespace App\Http\Controllers; use App\Models\Page; use App\Models\Setting; +use App\Services\TemplateService; use Illuminate\Http\Request; class PageController extends Controller @@ -13,22 +14,15 @@ class PageController extends Controller */ public function index() { - // 1) is_homepage işaretli ve published - $page = Page::where('is_homepage', true) + // 1) is_homepage işaretli ve published (en son güncellenen) + $page = Page::with(['headerTemplate', 'footerTemplate']) + ->where('is_homepage', true) ->where('status', 'published') + ->latest('updated_at') ->first(); + - // 2) yoksa 'home' slug'ı - if (!$page) { - $page = Page::where('slug', 'home') - ->where('status', 'published') - ->first(); - } - - // 3) yoksa ilk published sayfa (fallback) - if (!$page) { - $page = Page::where('status', 'published')->orderByDesc('published_at')->first(); - } + $settings = class_exists(Setting::class) ? (Setting::query()->first()) : null; @@ -53,18 +47,48 @@ class PageController extends Controller ? ($page->translate('meta_description') ?: ($page->excerpt ?? null)) : ($page->meta_description ?? $page->excerpt ?? null); + // Section verisini al - Hem eski hem yeni sistemi destekle $sections = $page->sections ?? $page->data ?? []; - $template = ($page->slug === 'home' || ($page->is_homepage ?? false)) - ? 'home' - : ($page->template ?? null); - $view = $template && view()->exists("templates.$template") + + // Yeni dinamik template sistemi için sections_data varsa onu da al + $templatedSections = $page->templated_sections ?? collect([]); + + // Template belirleme mantığı: + // 1. Kullanıcı template seçmişse, onu kullan + // 2. Template seçilmemişse ve homepage ise, 'home' kullan + // 3. Hiçbiri yoksa, 'generic' kullan + $template = $page->template + ?? (($page->slug === 'home' || ($page->is_homepage ?? false)) ? 'home' : 'generic'); + + $view = view()->exists("templates.$template") ? "templates.$template" - : (($page->slug === 'home' || ($page->is_homepage ?? false)) ? 'templates.home' : 'templates.generic'); + : 'templates.generic'; + + // Render Header Template + $renderedHeader = null; + if ($page->headerTemplate) { + $renderedHeader = TemplateService::replacePlaceholders( + $page->headerTemplate->html_content, + $page->header_data ?? [] + ); + } + + // Render Footer Template + $renderedFooter = null; + if ($page->footerTemplate) { + $renderedFooter = TemplateService::replacePlaceholders( + $page->footerTemplate->html_content, + $page->footer_data ?? [] + ); + } return view($view, [ 'page' => $page, 'settings' => $settings, 'sections' => $sections, + 'templatedSections' => $templatedSections, + 'renderedHeader' => $renderedHeader, + 'renderedFooter' => $renderedFooter, 'meta' => [ 'title' => $metaTitle ?: ($settings->default_meta_title ?? config('app.name')), 'description' => $metaDescription ?: ($settings->default_meta_description ?? null), @@ -76,9 +100,10 @@ class PageController extends Controller /** * Display a specific page by slug */ - public function show($slug) +public function show($slug) { - $page = Page::where('slug', $slug) + $page = Page::with(['headerTemplate', 'footerTemplate']) + ->where('slug', $slug) ->where('status', 'published') ->firstOrFail(); @@ -94,15 +119,46 @@ class PageController extends Controller // Use parsed_sections for easier template usage (key-value format) $sections = $page->parsed_sections ?? $page->sections ?? $page->data ?? []; - $template = ($slug === 'home' || ($page->is_homepage ?? false)) - ? 'home' - : ($page->template ?? 'generic'); - $view = view()->exists("templates.$template") ? "templates.$template" : (($slug === 'home') ? 'templates.home' : 'templates.generic'); + + // Yeni dinamik template sistemi için sections_data varsa onu da al + $templatedSections = $page->templated_sections ?? collect([]); + + // Template belirleme mantığı: + // 1. Kullanıcı template seçmişse, onu kullan + // 2. Template seçilmemişse ve homepage ise, 'home' kullan + // 3. Hiçbiri yoksa, 'generic' kullan + $template = $page->template + ?? (($slug === 'home' || ($page->is_homepage ?? false)) ? 'home' : 'generic'); + + $view = view()->exists("templates.$template") + ? "templates.$template" + : 'templates.generic'; + + // Render Header Template + $renderedHeader = null; + if ($page->headerTemplate) { + $renderedHeader = TemplateService::replacePlaceholders( + $page->headerTemplate->html_content, + $page->header_data ?? [] + ); + } + + // Render Footer Template + $renderedFooter = null; + if ($page->footerTemplate) { + $renderedFooter = TemplateService::replacePlaceholders( + $page->footerTemplate->html_content, + $page->footer_data ?? [] + ); + } return view($view, [ 'page' => $page, 'settings' => $settings, 'sections' => $sections, + 'templatedSections' => $templatedSections, + 'renderedHeader' => $renderedHeader, + 'renderedFooter' => $renderedFooter, 'meta' => [ 'title' => $metaTitle ?: ($settings->default_meta_title ?? config('app.name')), 'description' => $metaDescription ?: ($settings->default_meta_description ?? null), diff --git a/app/Models/Page.php b/app/Models/Page.php index e8a70f6..e77e962 100644 --- a/app/Models/Page.php +++ b/app/Models/Page.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\SectionTemplate; use App\Traits\HasTranslations; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; diff --git a/app/Observers/PageObserver.php b/app/Observers/PageObserver.php new file mode 100644 index 0000000..6faa559 --- /dev/null +++ b/app/Observers/PageObserver.php @@ -0,0 +1,26 @@ +is_homepage) { + // Diğer tüm sayfaların homepage işaretini kaldır + Page::where('id', '!=', $page->id) + ->where('is_homepage', true) + ->update(['is_homepage' => false]); + } + } +} + diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 452e6b6..ec8ef22 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,6 +2,8 @@ namespace App\Providers; +use App\Models\Page; +use App\Observers\PageObserver; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider @@ -19,6 +21,7 @@ class AppServiceProvider extends ServiceProvider */ public function boot(): void { - // + // Page model için observer kaydet + Page::observe(PageObserver::class); } } diff --git a/app/Services/TemplateService.php b/app/Services/TemplateService.php index ed32457..7747426 100644 --- a/app/Services/TemplateService.php +++ b/app/Services/TemplateService.php @@ -239,18 +239,58 @@ class TemplateService /** * Replace placeholders in HTML with actual data + * Supports both {text.title} and {{text.title}} formats */ public static function replacePlaceholders(string $html, array $data): string { - foreach ($data as $placeholder => $value) { + // First, parse all placeholders in the format {type.field_name} + preg_match_all('/\{([a-z]+\.[a-z_]+)\}/i', $html, $matches); + $placeholders = array_unique($matches[1] ?? []); + + // Replace each placeholder + foreach ($placeholders as $placeholder) { + // Try to find the value in data with various key formats + $value = null; + + // 1. Try exact match (text.title) + if (isset($data[$placeholder])) { + $value = $data[$placeholder]; + } + // 2. Try with section_data prefix (section_data.text.title) + elseif (isset($data["section_data.{$placeholder}"])) { + $value = $data["section_data.{$placeholder}"]; + } + // 3. Try nested array access (data['section_data']['text.title'] or data['text']['title']) + else { + $parts = explode('.', $placeholder); + if (count($parts) === 2) { + [$type, $field] = $parts; + // Try nested: data['section_data'][$type][$field] + if (isset($data['section_data'][$type][$field])) { + $value = $data['section_data'][$type][$field]; + } + // Try nested: data[$type][$field] + elseif (isset($data[$type][$field])) { + $value = $data[$type][$field]; + } + } + } + // Handle different value types if (is_array($value)) { $value = implode(', ', $value); } elseif (is_bool($value)) { $value = $value ? 'true' : 'false'; + } elseif ($value === null) { + $value = ''; } - $html = str_replace("{{$placeholder}}", $value ?? '', $html); + // Replace both {text.title} and {{text.title}} formats + $html = str_replace( + ["{{$placeholder}}", "{{{$placeholder}}}"], + [$value, $value], + $html + ); } return $html; diff --git a/resources/views/layouts/site.blade.php b/resources/views/layouts/site.blade.php index 724274e..f0d7ec7 100644 --- a/resources/views/layouts/site.blade.php +++ b/resources/views/layouts/site.blade.php @@ -9,9 +9,22 @@ - @include('partials.navbar') + {{-- Dynamic Header Template or Static Navbar --}} + @if(isset($renderedHeader) && $renderedHeader) + {!! $renderedHeader !!} + @else + @include('partials.navbar') + @endif + + {{-- Main Content --}} @yield('content') - @include('partials.footer') + + {{-- Dynamic Footer Template or Static Footer --}} + @if(isset($renderedFooter) && $renderedFooter) + {!! $renderedFooter !!} + @else + @include('partials.footer') + @endif {{-- İsteğe bağlı: tema JS dosyalarınız varsa buraya ekleyin --}} {{-- --}} diff --git a/resources/views/templates/generic.blade.php b/resources/views/templates/generic.blade.php index 894480b..7e2b762 100644 --- a/resources/views/templates/generic.blade.php +++ b/resources/views/templates/generic.blade.php @@ -1,8 +1,27 @@ @extends('layouts.site') @section('content') - @php $blocks = $sections ?? []; @endphp - @if(is_array($blocks) && !empty($blocks)) + @php + // Yeni dinamik template sistemi - Öncelik verilir + $hasTemplatedSections = isset($templatedSections) && $templatedSections->isNotEmpty(); + + // Eski section builder sistemi + $blocks = $sections ?? []; + $hasBlocks = is_array($blocks) && !empty($blocks); + @endphp + + @if($hasTemplatedSections) + {{-- Yeni dinamik template sisteminden gelen sections --}} + @foreach($templatedSections as $section) + @if($section['template'] ?? null) + {!! \App\Services\TemplateService::replacePlaceholders( + $section['template']->html_content, + $section['data'] ?? [] + ) !!} + @endif + @endforeach + @elseif($hasBlocks) + {{-- Eski blok bazlı dinamik render --}} @foreach($blocks as $block) @php $type = $block['type'] ?? null; @endphp @if($type && view()->exists("components.blocks.$type")) diff --git a/resources/views/templates/home.blade.php b/resources/views/templates/home.blade.php index 93e9d8b..a88e1d7 100644 --- a/resources/views/templates/home.blade.php +++ b/resources/views/templates/home.blade.php @@ -2,13 +2,26 @@ @section('content') @php - // sections varsa blok bazlı render, yoksa index.html fallback + // Yeni dinamik template sistemi - Öncelik verilir + $hasTemplatedSections = isset($templatedSections) && $templatedSections->isNotEmpty(); + + // Eski section builder sistemi $blocks = $sections ?? []; $hasBlocks = is_array($blocks) && count($blocks) > 0; @endphp - @if($hasBlocks) - {{-- Blok bazlı dinamik render --}} + @if($hasTemplatedSections) + {{-- Yeni dinamik template sisteminden gelen sections --}} + @foreach($templatedSections as $section) + @if($section['template'] ?? null) + {!! \App\Services\TemplateService::replacePlaceholders( + $section['template']->html_content, + $section['data'] ?? [] + ) !!} + @endif + @endforeach + @elseif($hasBlocks) + {{-- Eski blok bazlı dinamik render --}} @foreach($blocks as $block) @php $type = $block['type'] ?? null; @endphp @if($type && view()->exists("components.blocks.$type")) diff --git a/routes/web.php b/routes/web.php index 3799deb..81d1cb8 100644 --- a/routes/web.php +++ b/routes/web.php @@ -3,11 +3,62 @@ use Illuminate\Support\Facades\Route; use App\Http\Controllers\PageController; use App\Http\Controllers\BlogController; +use App\Models\Page; -// Home -> admin'de işaretli anasayfayı (veya 'home' slug'ını) göster -Route::get('/', [PageController::class, 'index'])->name('home'); -Route::get('/{slug}', [PageController::class, 'show'])->name('page.show'); +// Debug Route - Veritabanı kontrolü +Route::get('/debug-homepage', function () { + $page = Page::with(['headerTemplate', 'footerTemplate']) + ->where('is_homepage', true) + ->where('status', 'published') + ->latest('updated_at') + ->first(); + + if (!$page) { + return response()->json([ + 'error' => 'Homepage bulunamadı!', + 'all_pages' => Page::select('id', 'title', 'slug', 'is_homepage', 'status')->get(), + ]); + } + + return response()->json([ + 'page' => [ + 'id' => $page->id, + 'title' => $page->title, + 'slug' => $page->slug, + 'is_homepage' => $page->is_homepage, + 'status' => $page->status, + ], + 'header_template' => [ + 'id' => $page->header_template_id, + 'exists' => $page->headerTemplate ? true : false, + 'title' => $page->headerTemplate?->title, + 'data_filled' => !empty($page->header_data), + 'data' => $page->header_data, + ], + 'footer_template' => [ + 'id' => $page->footer_template_id, + 'exists' => $page->footerTemplate ? true : false, + 'title' => $page->footerTemplate?->title, + 'data_filled' => !empty($page->footer_data), + 'data' => $page->footer_data, + ], + 'sections' => [ + 'count' => is_array($page->sections) ? count($page->sections) : 0, + 'data' => $page->sections, + ], + 'sections_data' => [ + 'count' => is_array($page->sections_data) ? count($page->sections_data) : 0, + 'data' => $page->sections_data, + ], + ]); +}); + +// Homepage -> admin panelinde "is_homepage" olarak işaretli sayfa dinamik olarak gösterilir +Route::get('/', [PageController::class, 'index'])->name('homepage'); // Blog Route::get('/blog', [BlogController::class, 'index'])->name('blog.index'); Route::get('/blog/{slug}', [BlogController::class, 'show'])->name('blog.show'); + +// Pages (en sonda olmalı - catch-all) +Route::get('/{slug}', [PageController::class, 'show'])->name('page.show');