127 lines
4.1 KiB
PHP
127 lines
4.1 KiB
PHP
<?php
|
|||
|
|
|
||
|
|
namespace App\Http\Controllers\Admin;
|
||
|
|
|
||
|
|
use App\Http\Controllers\Controller;
|
||
|
|
use App\Models\Post;
|
||
|
|
use Illuminate\Http\RedirectResponse;
|
||
|
|
use Illuminate\Http\Request;
|
||
|
|
use Illuminate\Support\Facades\Auth;
|
||
|
|
use Illuminate\Support\Str;
|
||
|
|
use Illuminate\View\View;
|
||
|
|
|
||
|
|
class PostController extends Controller
|
||
|
|
{
|
||
|
|
public function index(Request $request): View
|
||
|
|
{
|
||
|
|
$q = trim((string) $request->query('q', ''));
|
||
|
|
$posts = Post::query()
|
||
|
|
->when($q !== '', function ($qb) use ($q) {
|
||
|
|
$qb->where('title', 'like', "%{$q}%")
|
||
|
|
->orWhere('slug', 'like', "%{$q}%");
|
||
|
|
})
|
||
|
|
->latest('created_at')
|
||
|
|
->paginate(20)
|
||
|
|
->withQueryString();
|
||
|
|
|
||
|
|
return view('admin.posts.index', compact('posts', 'q'));
|
||
|
|
}
|
||
|
|
|
||
|
|
public function create(): View
|
||
|
|
{
|
||
|
|
return view('admin.posts.create');
|
||
|
|
}
|
||
|
|
|
||
|
|
public function store(Request $request): RedirectResponse
|
||
|
|
{
|
||
|
|
$data = $this->validateData($request);
|
||
|
|
|
||
|
|
$slug = trim((string) ($data['slug'] ?? ''));
|
||
|
|
if ($slug === '') {
|
||
|
|
$slug = $this->uniqueSlug($data['title']);
|
||
|
|
}
|
||
|
|
|
||
|
|
$coverImageValue = $data['cover_image'] ?? null;
|
||
|
|
if ($request->hasFile('cover_image_file')) {
|
||
|
|
$coverImageValue = $request->file('cover_image_file')->store('posts/covers', 'public');
|
||
|
|
}
|
||
|
|
|
||
|
|
Post::create([
|
||
|
|
'title' => $data['title'],
|
||
|
|
'slug' => $slug,
|
||
|
|
'excerpt' => $data['excerpt'] ?? null,
|
||
|
|
'body' => $data['body'],
|
||
|
|
'cover_image' => $coverImageValue,
|
||
|
|
'author_id' => Auth::id(),
|
||
|
|
'published_at' => $request->boolean('published') ? now() : null,
|
||
|
|
]);
|
||
|
|
|
||
|
|
return redirect()->route('admin.posts.index')->with('status', 'Post created');
|
||
|
|
}
|
||
|
|
|
||
|
|
public function edit(Post $post): View
|
||
|
|
{
|
||
|
|
return view('admin.posts.edit', compact('post'));
|
||
|
|
}
|
||
|
|
|
||
|
|
public function update(Request $request, Post $post): RedirectResponse
|
||
|
|
{
|
||
|
|
$data = $this->validateData($request, $post->id);
|
||
|
|
|
||
|
|
$slug = trim((string) ($data['slug'] ?? ''));
|
||
|
|
if ($slug === '') {
|
||
|
|
$slug = $this->uniqueSlug($data['title'], $post->id);
|
||
|
|
}
|
||
|
|
|
||
|
|
$coverImageValue = $data['cover_image'] ?? $post->cover_image;
|
||
|
|
if ($request->hasFile('cover_image_file')) {
|
||
|
|
$coverImageValue = $request->file('cover_image_file')->store('posts/covers', 'public');
|
||
|
|
}
|
||
|
|
|
||
|
|
$post->update([
|
||
|
|
'title' => $data['title'],
|
||
|
|
'slug' => $slug,
|
||
|
|
'excerpt' => $data['excerpt'] ?? null,
|
||
|
|
'body' => $data['body'],
|
||
|
|
'cover_image' => $coverImageValue,
|
||
|
|
'published_at' => $request->boolean('published') ? ($post->published_at ?? now()) : null,
|
||
|
|
]);
|
||
|
|
|
||
|
|
return redirect()->route('admin.posts.index')->with('status', 'Post updated');
|
||
|
|
}
|
||
|
|
|
||
|
|
public function destroy(Post $post): RedirectResponse
|
||
|
|
{
|
||
|
|
$post->delete();
|
||
|
|
|
||
|
|
return redirect()->route('admin.posts.index')->with('status', 'Post deleted');
|
||
|
|
}
|
||
|
|
|
||
|
|
protected function validateData(Request $request, ?int $ignoreId = null): array
|
||
|
|
{
|
||
|
|
return $request->validate([
|
||
|
|
'title' => ['required', 'string', 'max:255'],
|
||
|
|
'slug' => ['nullable', 'string', 'max:255', 'unique:posts,slug' . ($ignoreId ? ',' . $ignoreId : '')],
|
||
|
|
'excerpt' => ['nullable', 'string', 'max:500'],
|
||
|
|
'body' => ['required', 'string'],
|
||
|
|
'cover_image' => ['nullable', 'string', 'max:2048'],
|
||
|
|
'cover_image_file' => ['nullable', 'image', 'mimes:jpeg,jpg,png,webp,avif,gif', 'max:8192'],
|
||
|
|
'published' => ['nullable', 'boolean'],
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
|
||
|
|
protected function uniqueSlug(string $title, ?int $ignoreId = null): string
|
||
|
|
{
|
||
|
|
$base = Str::slug($title);
|
||
|
|
if ($base === '') { $base = 'post'; }
|
||
|
|
$slug = $base;
|
||
|
|
$i = 1;
|
||
|
|
while (Post::where('slug', $slug)
|
||
|
|
->when($ignoreId, fn($q) => $q->where('id', '!=', $ignoreId))
|
||
|
|
->exists()) {
|
||
|
|
$slug = $base . '-' . (++$i);
|
||
|
|
}
|
||
|
|
return $slug;
|
||
|
|
}
|
||
|
|
}
|