with('document.type') ->where('page_key', $pageKey) ->orderByRaw("CASE region WHEN 'header' THEN 1 WHEN 'body' THEN 2 ELSE 3 END") ->orderBy('sort_order') ->get() ->groupBy('region'); $documents = ContentDocument::query() ->with('type') ->withCount('placements') ->orderBy('title') ->get(); return view('content::admin.composition', compact('pageKey', 'placements', 'documents')); } public function editPage(Page $page): View { $placements = PageContent::query() ->with('document.type') ->where(fn ($query) => $query->where('page_id', $page->id)->orWhere('page_key', $page->slug)) ->orderByRaw("CASE region WHEN 'header' THEN 1 WHEN 'body' THEN 2 ELSE 3 END") ->orderBy('sort_order') ->get(); PageContent::query() ->whereNull('page_id') ->where('page_key', $page->slug) ->update(['page_id' => $page->id]); $documents = ContentDocument::query() ->with('type') ->withCount('placements') ->orderBy('title') ->get(); return view('content::admin.composition', [ 'pageKey' => $page->slug, 'page' => $page, 'placements' => $placements->groupBy('region'), 'documents' => $documents, ]); } public function preview(string $pageKey): View { abort_unless($pageKey === 'home', 404, 'This phase currently provides the Saasland homepage preview.'); return view('stylist-theme-saasland::home', ['pageKey' => $pageKey]); } public function store(Request $request, string $pageKey): RedirectResponse { $validated = $request->validate([ 'content_document_id' => ['required', 'integer', Rule::exists('content_documents', 'id')->whereNull('deleted_at')], 'region' => ['required', Rule::in(self::REGIONS)], ]); $document = ContentDocument::query()->with('type')->findOrFail($validated['content_document_id']); abort_unless(in_array($validated['region'], $document->type?->allowed_regions ?? [], true), 422, 'This content type is not allowed in the selected region.'); $page = Page::query()->where('slug', $pageKey)->first(); $nextOrder = ((int) PageContent::query()->where(fn ($query) => $query->where('page_key', $pageKey)->when($page, fn ($q) => $q->orWhere('page_id', $page->id)))->where('region', $validated['region'])->max('sort_order')) + 10; PageContent::query()->create([ 'page_id' => $page?->id, 'page_key' => $pageKey, 'content_document_id' => $document->id, 'region' => $validated['region'], 'sort_order' => $nextOrder, 'is_enabled' => true, ]); return back()->with('status', 'Document added to the '.$validated['region'].' region.'); } public function update(Request $request, PageContent $placement): RedirectResponse { $validated = $request->validate([ 'is_enabled' => ['nullable', 'boolean'], 'starts_at' => ['nullable', 'date'], 'ends_at' => ['nullable', 'date', 'after:starts_at'], ]); $placement->update([ 'is_enabled' => $request->boolean('is_enabled'), 'starts_at' => $validated['starts_at'] ?? null, 'ends_at' => $validated['ends_at'] ?? null, ]); return back()->with('status', 'Page placement updated.'); } public function destroy(PageContent $placement): RedirectResponse { $placement->delete(); $this->normaliseRegion($placement->page_key, $placement->region); return back()->with('status', 'Document removed from this page. The reusable document was not deleted.'); } public function duplicate(Request $request, PageContent $placement): RedirectResponse { $source = $placement->document()->firstOrFail(); $copy = DB::transaction(function () use ($request, $placement, $source): ContentDocument { $copy = $source->replicate(['slug', 'status', 'published_at', 'created_by', 'updated_by']); $copy->title = $source->title.' copy'; $copy->slug = $source->slug.'-copy-'.strtolower(str()->random(6)); $copy->status = 'draft'; $copy->published_at = null; $copy->created_by = $request->user()?->id; $copy->updated_by = $request->user()?->id; $copy->save(); PageContent::query()->create([ 'page_id' => $placement->page_id, 'page_key' => $placement->page_key, 'content_document_id' => $copy->id, 'region' => $placement->region, 'sort_order' => $placement->sort_order + 5, 'is_enabled' => false, 'visibility_rules' => $placement->visibility_rules, 'presentation' => $placement->presentation, ]); return $copy; }); $this->normaliseRegion($placement->page_key, $placement->region); return redirect()->route('content.documents.edit', $copy)->with('status', 'Page-specific draft copy created and added after the original.'); } public function reorder(Request $request, string $pageKey): JsonResponse|RedirectResponse { $validated = $request->validate([ 'region' => ['required', Rule::in(self::REGIONS)], 'placements' => ['required', 'array'], 'placements.*' => ['required', 'integer'], ]); $ids = array_values(array_unique(array_map('intval', $validated['placements']))); $owned = PageContent::query()->where('page_key', $pageKey)->where('region', $validated['region'])->whereIn('id', $ids)->pluck('id')->all(); abort_unless(count($owned) === count($ids), 422, 'One or more placements do not belong to this page region.'); DB::transaction(function () use ($ids): void { PageContent::query()->whereIn('id', $ids)->increment('sort_order', 100000); foreach ($ids as $index => $id) { PageContent::query()->whereKey($id)->update(['sort_order' => ($index + 1) * 10]); } }); return $request->expectsJson() ? response()->json(['message' => 'Order saved.']) : back()->with('status', 'Page order updated.'); } private function normaliseRegion(?string $pageKey, string $region): void { $ids = PageContent::query()->where('page_key', $pageKey)->where('region', $region)->orderBy('sort_order')->pluck('id'); DB::transaction(function () use ($ids): void { foreach ($ids as $index => $id) { PageContent::query()->whereKey($id)->update(['sort_order' => ($index + 1) * 10]); } }); } }