| Current Path : /var/www/html/reddsis/app/Http/Controllers/Backend/ |
| Current File : /var/www/html/reddsis/app/Http/Controllers/Backend/FrontendPageController.php |
<?php
namespace App\Http\Controllers\Backend;
use App\Http\Controllers\Controller;
use App\Models\Backend\FrontendPage;
use App\Models\Backend\FrontendSite;
use App\Models\Backend\FrontendComponent;
use App\Services\BladeSyncService;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
class FrontendPageController extends Controller
{
public function index(Request $request)
{
$siteId = $request->get('site_id');
$search = $request->get('search');
$sites = FrontendSite::orderBy('name')->pluck('name', 'id');
$pages = FrontendPage::with('site')
->when($siteId, fn($q) => $q->where('site_fk', $siteId))
->when($search, fn($q) => $q->where(function($q) use ($search) {
$q->where('name', 'like', "%{$search}%")
->orWhere('slug', 'like', "%{$search}%");
}))
->orderByDesc('status')
->orderBy('sort_order')
->paginate(10);
return view('backend.module.frontendSite.page.index', ['pages' => $pages, 'sites' => $sites, 'siteId' => $siteId, 'search' => $search]);
}
public function create(Request $request)
{
$sites = FrontendSite::orderBy('name')->pluck('name', 'id');
$components = FrontendComponent::where('status', true)->orderBy('category')->orderBy('name')->get();
$selectedSiteId = $request->get('site_id');
return view('backend.module.frontendSite.page.create', ['sites' => $sites, 'components' => $components, 'selectedSiteId' => $selectedSiteId]);
}
public function store(Request $request)
{
$pageId = $request->input('page_id');
$isAjax = $request->ajax();
$data = $request->validate([
'site_fk' => 'required|integer|exists:frontend_sites,id',
'name' => $isAjax ? 'nullable|string|max:255' : 'required|string|max:255',
'slug' => $isAjax
? 'nullable|string|max:255'
: 'required|string|max:255' . ($pageId ? '' : '|unique:frontend_pages,slug,NULL,id,site_fk,' . $request->site_fk),
'layout' => 'nullable|string',
'entry_script' => ['nullable', 'string', function ($attribute, $value, $fail) {
if ($value && preg_match('/\{!!\s*\$/', $value)) {
$fail('Entry Script cannot contain {!! $... !!} syntax. Use Page Content for component output. Entry Script is for @php logic only.');
}
}],
'page_content' => 'nullable|string',
'use_custom_layout' => 'nullable|boolean',
'is_default' => 'nullable|boolean',
'status' => 'nullable|boolean',
'sort_order' => 'nullable|integer|min:0',
'components' => 'nullable|array',
'components.*' => 'integer|exists:frontend_components,id',
]);
$data['is_default'] = $request->boolean('is_default');
$data['status'] = $request->boolean('status');
$data['use_custom_layout'] = $request->boolean('use_custom_layout');
$data['sort_order'] ??= 0;
// Resolve existing page by ID (after first AJAX save) or by slug
if ($pageId) {
$page = FrontendPage::findOrFail($pageId);
} else {
$page = !empty($data['slug'])
? FrontendPage::where('site_fk', $data['site_fk'])->where('slug', $data['slug'])->first()
: null;
}
if ($page) {
// Auto-unset other default pages in same site
if ($data['is_default']) {
FrontendPage::where('site_fk', $data['site_fk'])->where('id', '!=', $page->id)->where('is_default', true)->update(['is_default' => false]);
}
// AJAX modal save only updates code fields, not name/slug
$page->update($isAjax ? Arr::except($data, ['name', 'slug']) : $data);
} else {
if (empty($data['name']) || empty($data['slug'])) {
if ($isAjax) {
return response()->json(['message' => 'Please fill in Name and Slug before saving code.'], 422);
}
return back()->withInput()->withErrors(['name' => 'Please fill in Name and Slug before saving.']);
}
// Auto-unset other default pages in same site
if ($data['is_default']) {
FrontendPage::where('site_fk', $data['site_fk'])->where('is_default', true)->update(['is_default' => false]);
}
$page = FrontendPage::create($data);
// Auto-set default untuk rekod pertama site ni
if (FrontendPage::where('site_fk', $data['site_fk'])->count() === 1) {
$page->update(['is_default' => true]);
}
}
app(BladeSyncService::class)->syncAll();
$page->components()->detach();
if ($request->has('components')) {
$sort = 0;
foreach ($request->components as $compId) {
$page->components()->attach($compId, ['sort' => $sort++]);
}
}
if ($isAjax) {
return response()->json(['message' => 'Code updated successfully!', 'page_id' => $page->id]);
}
if (!$request->filled('entry_script') && !$request->filled('page_content') && !$request->has('components')) {
flash()->warning('Page created but no Entry Script, Page Content, or Components were provided. The page may appear empty.');
} else {
flash()->success('Page created successfully!');
}
return redirect()->route('frontend-site.pages.index', ['site_id' => $page->site_fk]);
}
public function edit($id)
{
$page = FrontendPage::with('components')->findOrFail($id);
$sites = FrontendSite::orderBy('name')->pluck('name', 'id');
$components = FrontendComponent::where('status', true)->orderBy('category')->orderBy('name')->get();
$selectedIds = $page->components->pluck('id')->toArray();
return view('backend.module.frontendSite.page.edit', ['page' => $page, 'sites' => $sites, 'components' => $components, 'selectedIds' => $selectedIds]);
}
public function update(Request $request, $id)
{
$page = FrontendPage::findOrFail($id);
$data = $request->validate([
'site_fk' => 'required|integer|exists:frontend_sites,id',
'name' => $request->ajax() ? 'nullable|string|max:255' : 'required|string|max:255',
'slug' => $request->ajax()
? 'nullable|string|max:255'
: 'required|string|max:255|unique:frontend_pages,slug,' . $id . ',id,site_fk,' . $request->site_fk,
'layout' => 'nullable|string',
'entry_script' => ['nullable', 'string', function ($attribute, $value, $fail) {
if ($value && preg_match('/\{!!\s*\$/', $value)) {
$fail('Entry Script cannot contain {!! $... !!} syntax. Use Page Content for component output. Entry Script is for @php logic only.');
}
}],
'page_content' => 'nullable|string',
'use_custom_layout' => 'nullable|boolean',
'is_default' => 'nullable|boolean',
'status' => 'nullable|boolean',
'sort_order' => 'nullable|integer|min:0',
'components' => 'nullable|array',
'components.*' => 'integer|exists:frontend_components,id',
]);
$data['is_default'] = $request->boolean('is_default');
$data['status'] = $request->boolean('status');
$data['use_custom_layout'] = $request->boolean('use_custom_layout');
// Auto-unset other default pages in same site
if ($data['is_default']) {
FrontendPage::where('site_fk', $data['site_fk'])->where('id', '!=', $id)->where('is_default', true)->update(['is_default' => false]);
}
$page->update($request->ajax() ? Arr::except($data, ['name', 'slug']) : $data);
app(BladeSyncService::class)->syncAll();
$page->components()->detach();
if ($request->has('components')) {
$sort = 0;
foreach ($request->components as $compId) {
$page->components()->attach($compId, ['sort' => $sort++]);
}
}
if ($request->ajax()) {
return response()->json(['message' => 'Code updated successfully!']);
}
if (!$request->filled('entry_script') && !$request->filled('page_content') && !$request->has('components')) {
flash()->warning('Page created but no Entry Script, Page Content, or Components were provided. The page may appear empty.');
} else {
flash()->success('Page updated successfully!');
}
return redirect()->route('frontend-site.pages.index', ['site_id' => $page->site_fk]);
}
public function destroy($id)
{
$page = FrontendPage::findOrFail($id);
$siteId = $page->site_fk;
$page->components()->detach();
$page->delete();
app(BladeSyncService::class)->syncAll();
flash()->success('Page deleted successfully.');
return redirect()->route('frontend-site.pages.index', ['site_id' => $siteId]);
}
public function toggleDefault($id)
{
$page = FrontendPage::findOrFail($id);
FrontendPage::where('site_fk', $page->site_fk)->where('is_default', true)->update(['is_default' => false]);
$page->update(['is_default' => true]);
app(BladeSyncService::class)->syncAll();
flash()->success("'{$page->name}' is now the default page");
return response()->json(['is_default' => true, 'name' => $page->name]);
}
public function reorder(Request $request)
{
$ids = $request->input('ids', []);
$page = (int) $request->input('page', 1);
$perPage = 10;
$offset = ($page - 1) * $perPage;
foreach ($ids as $index => $id) {
FrontendPage::where('id', $id)->update(['sort_order' => $offset + $index + 1]);
}
app(BladeSyncService::class)->syncAll();
return response()->json(['success' => true]);
}
public function toggleStatus($id)
{
$page = FrontendPage::findOrFail($id);
$page->update(['status' => !$page->status]);
app(BladeSyncService::class)->syncAll();
return response()->json(['status' => $page->fresh()->status]);
}
public function layoutBuilder()
{
return view('backend.module.frontendSite.layout-builder');
}
}