some progress
This commit is contained in:
@@ -4,6 +4,7 @@ namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Book;
|
||||
use App\Models\Category;
|
||||
use App\Models\Author;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
@@ -12,10 +13,67 @@ class BookController extends Controller
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
public function index(Request $request)
|
||||
{
|
||||
$books = Book::with('category')->get();
|
||||
return view('books.index', compact('books'));
|
||||
$query = Book::query()->with(['category', 'authors', 'summary'])->orderByDesc('created_at');
|
||||
|
||||
// Text search
|
||||
if ($search = trim((string) $request->get('q'))) {
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->where('title', 'like', "%{$search}%")
|
||||
->orWhere('description', 'like', "%{$search}%");
|
||||
});
|
||||
}
|
||||
|
||||
// Category filter (by id or slug)
|
||||
if ($cat = $request->get('category')) {
|
||||
if (is_numeric($cat)) {
|
||||
$query->where('category_id', (int) $cat);
|
||||
} else {
|
||||
$query->whereHas('category', function ($q) use ($cat) {
|
||||
$q->where('slug', $cat)->orWhere('name', 'like', "%{$cat}%");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Author filter (by id, slug, or name)
|
||||
if ($author = $request->get('author')) {
|
||||
$query->whereHas('authors', function ($q) use ($author) {
|
||||
if (is_numeric($author)) {
|
||||
$q->where('authors.id', (int) $author);
|
||||
} else {
|
||||
$q->where('authors.slug', $author)
|
||||
->orWhere('authors.name', 'like', "%{$author}%");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Publication date range
|
||||
if ($from = $request->get('date_from')) {
|
||||
$query->whereDate('publication_date', '>=', $from);
|
||||
}
|
||||
if ($to = $request->get('date_to')) {
|
||||
$query->whereDate('publication_date', '<=', $to);
|
||||
}
|
||||
|
||||
$books = $query->paginate(12)->withQueryString();
|
||||
|
||||
// For filter dropdowns
|
||||
$categories = Category::orderBy('name')->get();
|
||||
$authors = Author::orderBy('name')->get();
|
||||
|
||||
return view('books.index', [
|
||||
'books' => $books,
|
||||
'categories' => $categories,
|
||||
'authors' => $authors,
|
||||
'filters' => [
|
||||
'q' => $request->get('q'),
|
||||
'category' => $request->get('category'),
|
||||
'author' => $request->get('author'),
|
||||
'date_from' => $request->get('date_from'),
|
||||
'date_to' => $request->get('date_to'),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,9 +99,18 @@ class BookController extends Controller
|
||||
'category_id' => 'required|exists:categories,id',
|
||||
]);
|
||||
|
||||
Book::create([
|
||||
// Generate a unique slug for the title
|
||||
$baseSlug = Str::slug($request->title);
|
||||
$slug = $baseSlug;
|
||||
$i = 2;
|
||||
while (Book::where('slug', $slug)->exists()) {
|
||||
$slug = $baseSlug . '-' . $i;
|
||||
$i++;
|
||||
}
|
||||
|
||||
$book = Book::create([
|
||||
'title' => $request->title,
|
||||
'slug' => Str::slug($request->title),
|
||||
'slug' => $slug,
|
||||
'author' => $request->author,
|
||||
'description' => $request->description,
|
||||
'publication_date' => $request->publication_date,
|
||||
@@ -51,6 +118,22 @@ class BookController extends Controller
|
||||
'category_id' => $request->category_id,
|
||||
]);
|
||||
|
||||
// Normalize author: link to authors table via pivot
|
||||
if (!empty($request->author)) {
|
||||
$name = trim($request->author);
|
||||
$slug = Str::slug($name);
|
||||
$author = Author::where('slug', $slug)->first();
|
||||
if (!$author) {
|
||||
$author = Author::where('name', $name)->first();
|
||||
}
|
||||
if ($author) {
|
||||
$author->fill(['name' => $name, 'slug' => $author->slug ?: $slug])->save();
|
||||
} else {
|
||||
$author = Author::create(['name' => $name, 'slug' => $slug]);
|
||||
}
|
||||
$book->authors()->sync([$author->id]);
|
||||
}
|
||||
|
||||
return redirect()->route('books.index')
|
||||
->with('success', 'Book created successfully.');
|
||||
}
|
||||
@@ -60,7 +143,17 @@ class BookController extends Controller
|
||||
*/
|
||||
public function show(Book $book)
|
||||
{
|
||||
return view('books.show', compact('book'));
|
||||
$book->load(['summary', 'category', 'authors', 'reviews.user']);
|
||||
$avgRating = (float) round($book->reviews()->avg('rating') ?? 0, 1);
|
||||
$reviewsCount = (int) $book->reviews()->count();
|
||||
$userReview = auth()->check() ? $book->reviews()->where('user_id', auth()->id())->first() : null;
|
||||
|
||||
return view('books.show', [
|
||||
'book' => $book,
|
||||
'avgRating' => $avgRating,
|
||||
'reviewsCount' => $reviewsCount,
|
||||
'userReview' => $userReview,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,9 +179,30 @@ class BookController extends Controller
|
||||
'category_id' => 'required|exists:categories,id',
|
||||
]);
|
||||
|
||||
// If title changed, compute a unique slug (preserving current slug if still matching)
|
||||
$baseSlug = Str::slug($request->title);
|
||||
$slug = $baseSlug;
|
||||
if ($book->slug !== $baseSlug) {
|
||||
$i = 2;
|
||||
while (Book::where('slug', $slug)->where('id', '!=', $book->id)->exists()) {
|
||||
$slug = $baseSlug . '-' . $i;
|
||||
$i++;
|
||||
}
|
||||
} else {
|
||||
// Ensure no collision with other records even if same base
|
||||
if (Book::where('slug', $baseSlug)->where('id', '!=', $book->id)->exists()) {
|
||||
$i = 2;
|
||||
$slug = $baseSlug . '-' . $i;
|
||||
while (Book::where('slug', $slug)->where('id', '!=', $book->id)->exists()) {
|
||||
$i++;
|
||||
$slug = $baseSlug . '-' . $i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$book->update([
|
||||
'title' => $request->title,
|
||||
'slug' => Str::slug($request->title),
|
||||
'slug' => $slug,
|
||||
'author' => $request->author,
|
||||
'description' => $request->description,
|
||||
'publication_date' => $request->publication_date,
|
||||
@@ -96,6 +210,25 @@ class BookController extends Controller
|
||||
'category_id' => $request->category_id,
|
||||
]);
|
||||
|
||||
// Normalize author: sync pivot to the single provided author
|
||||
if (!empty($request->author)) {
|
||||
$name = trim($request->author);
|
||||
$slug = Str::slug($name);
|
||||
$author = Author::where('slug', $slug)->first();
|
||||
if (!$author) {
|
||||
$author = Author::where('name', $name)->first();
|
||||
}
|
||||
if ($author) {
|
||||
$author->fill(['name' => $name, 'slug' => $author->slug ?: $slug])->save();
|
||||
} else {
|
||||
$author = Author::create(['name' => $name, 'slug' => $slug]);
|
||||
}
|
||||
$book->authors()->sync([$author->id]);
|
||||
} else {
|
||||
// If author field is cleared, detach all author links
|
||||
$book->authors()->detach();
|
||||
}
|
||||
|
||||
return redirect()->route('books.index')
|
||||
->with('success', 'Book updated successfully.');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user