some progress

This commit is contained in:
2025-09-20 16:47:41 +03:00
parent e650f3c1b2
commit 2228469bcb
65 changed files with 3382 additions and 311 deletions
+140 -7
View File
@@ -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.');
}