fix: update tour management
This commit is contained in:
@@ -8,92 +8,139 @@ use Illuminate\Http\Request;
|
||||
|
||||
class TourController extends Controller
|
||||
{
|
||||
//لیست/آرشیو تورها با قابلیت فیلتر
|
||||
/**
|
||||
* لیست / آرشیو تورها با قابلیت فیلتر
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$query = Tour::query()
|
||||
->where('status', 1) // فقط تورهای فعال
|
||||
->with(['travelType', 'flights']); // بارگذاری زودهنگام برای جلوگیری از N+1
|
||||
->where('status', 1)
|
||||
->with(['travelType', 'flights']);
|
||||
|
||||
// فیلتر بر اساس نوع سفر (travel_type_id)
|
||||
// فیلتر بر اساس نوع سفر
|
||||
if ($request->filled('travel_type')) {
|
||||
$query->where('travel_type_id', $request->input('travel_type'));
|
||||
$query->where(
|
||||
'travel_type_id',
|
||||
$request->input('travel_type')
|
||||
);
|
||||
}
|
||||
|
||||
// فیلتر جستجوی متنی (عنوان)
|
||||
// جستجو بر اساس عنوان
|
||||
if ($request->filled('q')) {
|
||||
$query->where('title', 'like', '%' . $request->input('q') . '%');
|
||||
$query->where(
|
||||
'title',
|
||||
'like',
|
||||
'%' . $request->input('q') . '%'
|
||||
);
|
||||
}
|
||||
|
||||
// فیلتر بازه قیمتی
|
||||
// حداقل قیمت
|
||||
if ($request->filled('price_min')) {
|
||||
$query->where('price', '>=', $request->input('price_min'));
|
||||
$query->where(
|
||||
'price',
|
||||
'>=',
|
||||
$request->input('price_min')
|
||||
);
|
||||
}
|
||||
|
||||
// حداکثر قیمت
|
||||
if ($request->filled('price_max')) {
|
||||
$query->where('price', '<=', $request->input('price_max'));
|
||||
$query->where(
|
||||
'price',
|
||||
'<=',
|
||||
$request->input('price_max')
|
||||
);
|
||||
}
|
||||
|
||||
// مرتبسازی بر اساس قیمت (اگر خواستی)
|
||||
// مرتبسازی
|
||||
if ($request->filled('sort')) {
|
||||
$query->orderBy('price', $request->input('sort') === 'desc' ? 'desc' : 'asc');
|
||||
$query->orderBy(
|
||||
'price',
|
||||
$request->input('sort') === 'desc'
|
||||
? 'desc'
|
||||
: 'asc'
|
||||
);
|
||||
} else {
|
||||
$query->latest(); // جدیدترینها اول
|
||||
$query->latest();
|
||||
}
|
||||
|
||||
$tours = $query->paginate(12);
|
||||
$travelTypes = TravelType::where('status', 1)->get(); // برای منوی فیلتر
|
||||
// صفحهبندی
|
||||
$tours = $query->paginate(12)->withQueryString();
|
||||
|
||||
return view('tours.index', compact('tours', 'travelTypes'));
|
||||
// انواع سفر
|
||||
$travelTypes = TravelType::where('status', 1)->get();
|
||||
|
||||
return view(
|
||||
'tours.index',
|
||||
compact('tours', 'travelTypes')
|
||||
);
|
||||
}
|
||||
|
||||
//حذف فیلترها و بازگشت به آرشیو کامل
|
||||
|
||||
/**
|
||||
* حذف فیلترها
|
||||
*/
|
||||
public function removeFilters()
|
||||
{
|
||||
// ساده: فقط برگشت به آرشیو بدون هیچ پارامتری.
|
||||
// (اگر از کوکی/سشن استفاده میکنی، اینجا آنها را هم پاک کن)
|
||||
return redirect()->route('tours.index');
|
||||
}
|
||||
|
||||
//صفحهی جزئیات یک تور
|
||||
|
||||
/**
|
||||
* نمایش جزئیات یک تور
|
||||
*/
|
||||
public function show(Tour $tour)
|
||||
{
|
||||
// فقط اگر تور غیرفعال بود از دسترسی جلوگیری کن (مثلاً ریدایرکت)
|
||||
if ($tour->status == 0) {
|
||||
// فقط تورهای فعال قابل مشاهده باشند
|
||||
if ($tour->status != 1) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
// بارگذاری پروازها + نوع سفر + نظرات تاییدشده
|
||||
// افزایش تعداد بازدید
|
||||
$tour->increment('views_count');
|
||||
|
||||
// بارگذاری اطلاعات مورد نیاز
|
||||
$tour->load([
|
||||
'flights',
|
||||
'travelType',
|
||||
// توجه: این رابطه را باید در مدل Tour تعریف کنی (morphMany)
|
||||
'comments' => function ($q) {
|
||||
$q->where('status', 1)->latest();
|
||||
}
|
||||
]);
|
||||
|
||||
// تورهای پیشنهادی مرتبط (همدسته) برای نمایش کنار صفحه
|
||||
// تورهای مرتبط
|
||||
$relatedTours = Tour::where('status', 1)
|
||||
->where('travel_type_id', $tour->travel_type_id)
|
||||
->where('id', '!=', $tour->id)
|
||||
->latest()
|
||||
->limit(4)
|
||||
->get();
|
||||
|
||||
return view('tours.show', compact('tour', 'relatedTours'));
|
||||
return view(
|
||||
'tours.show',
|
||||
compact('tour', 'relatedTours')
|
||||
);
|
||||
}
|
||||
|
||||
//جستجوی پیشنهادی (Typeahead / AJAX) — خروجی JSON
|
||||
|
||||
/**
|
||||
* جستجوی پیشنهادی
|
||||
*/
|
||||
public function searchSuggestion(Request $request)
|
||||
{
|
||||
$q = $request->input('q', '');
|
||||
|
||||
$tours = Tour::where('status', 1)
|
||||
->where('title', 'like', '%' . $q . '%')
|
||||
->where(
|
||||
'title',
|
||||
'like',
|
||||
'%' . $q . '%'
|
||||
)
|
||||
->limit(8)
|
||||
->get(['id', 'title', 'slug', 'price']);
|
||||
->get([
|
||||
'id',
|
||||
'title',
|
||||
'slug',
|
||||
'price'
|
||||
]);
|
||||
|
||||
return response()->json($tours);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,60 +23,60 @@ class TourStoreRequest extends FormRequest
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'travel_type_id' =>
|
||||
[
|
||||
'required',
|
||||
'exists:travel_types,id'
|
||||
],
|
||||
// 'travel_type_id' =>
|
||||
// [
|
||||
// 'nullable',
|
||||
// 'exists:travel_types,id'
|
||||
// ],
|
||||
'title' =>
|
||||
[
|
||||
'required',
|
||||
'string',
|
||||
'max:200'
|
||||
],
|
||||
'slug' =>
|
||||
['required', 'string',
|
||||
'max:200',
|
||||
'regex:/^[a-z0-9-]+$/',
|
||||
'unique:tours,slug,' . $this->tour
|
||||
],
|
||||
// 'slug' =>
|
||||
// ['nullable', 'string',
|
||||
// 'max:200',
|
||||
// 'regex:/^[a-z0-9-]+$/',
|
||||
// 'unique:tours,slug,' . $this->tour
|
||||
// ],
|
||||
|
||||
'description' =>
|
||||
[
|
||||
'required',
|
||||
'string'
|
||||
],
|
||||
'duration' =>
|
||||
[
|
||||
'required',
|
||||
'string',
|
||||
'max:50'
|
||||
],
|
||||
'start_date' =>
|
||||
[
|
||||
'required',
|
||||
'date'
|
||||
],
|
||||
'end_date' =>
|
||||
[
|
||||
'required',
|
||||
'date',
|
||||
'after_or_equal:start_date'
|
||||
],
|
||||
// 'description' =>
|
||||
// [
|
||||
// 'nullable',
|
||||
// 'string'
|
||||
// ],
|
||||
// 'duration' =>
|
||||
// [
|
||||
// 'nullable',
|
||||
// 'string',
|
||||
// 'max:50'
|
||||
// ],
|
||||
// 'start_date' =>
|
||||
// [
|
||||
// 'nullable',
|
||||
// 'date'
|
||||
// ],
|
||||
// 'end_date' =>
|
||||
// [
|
||||
// 'nullable',
|
||||
// 'date',
|
||||
// 'after_or_equal:start_date'
|
||||
// ],
|
||||
'price' =>
|
||||
[
|
||||
'required',
|
||||
'numeric',
|
||||
'min:0'
|
||||
],
|
||||
'capacity' =>
|
||||
[
|
||||
'required',
|
||||
'integer',
|
||||
'min:0'],
|
||||
// 'capacity' =>
|
||||
// [
|
||||
// 'nullable',
|
||||
// 'integer',
|
||||
// 'min:0'],
|
||||
'images' =>
|
||||
[
|
||||
'required',
|
||||
'nullable',
|
||||
'array'
|
||||
],
|
||||
'images.*' =>
|
||||
|
||||
Reference in New Issue
Block a user