339 lines
11 KiB
PHP
339 lines
11 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Admin;
|
|
|
|
use App\Enums\Tour\TourScope;
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Requests\Admin\Tour\TourStoreRequest;
|
|
use App\Http\Requests\Admin\Tour\TourUpdateRequest;
|
|
use App\Models\City;
|
|
use App\Models\Country;
|
|
use App\Models\File;
|
|
use App\Models\Tour;
|
|
use App\Models\TourDeparture;
|
|
use App\Models\TourImage;
|
|
use Hekmatinasser\Verta\Verta;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class TourController extends Controller
|
|
{
|
|
public function index(Request $request)
|
|
{
|
|
$title = 'جزئیات تور';
|
|
$search = $request->input('search');
|
|
$sort = $request->input('sort');
|
|
|
|
$tours = Tour::query()
|
|
->with([
|
|
'originCity',
|
|
'city',
|
|
'file',
|
|
])
|
|
->withCount('tourDepartures')
|
|
->when($search, function ($query) use ($search) {
|
|
$query->where(function ($query) use ($search) {
|
|
$query->where('title', 'like', "%{$search}%")
|
|
->orWhere('summary', 'like', "%{$search}%")
|
|
->orWhereHas('originCity', function ($query) use ($search) {
|
|
$query->where('name', 'like', "%{$search}%");
|
|
})
|
|
->orWhereHas('city', function ($query) use ($search) {
|
|
$query->where('name', 'like', "%{$search}%");
|
|
});
|
|
});
|
|
})
|
|
->applySort($sort)
|
|
->paginate(3)
|
|
->withQueryString();
|
|
|
|
return view('admin.tours.index', compact('title', 'tours'));
|
|
}
|
|
|
|
public function create()
|
|
{
|
|
$title = 'ایجاد تور';
|
|
|
|
$cities = City::query()
|
|
->orderBy('name')
|
|
->get();
|
|
|
|
$countries = Country::query()
|
|
->orderBy('name')
|
|
->get();
|
|
|
|
return view('admin.tours.create', compact('title', 'cities', 'countries'));
|
|
}
|
|
|
|
public function citiesByCountry(Country $country)
|
|
{
|
|
$cities = City::query()
|
|
->where('county_id', $country->id)
|
|
->orderBy('name')
|
|
->get(['id', 'name']);
|
|
|
|
return response()->json($cities);
|
|
}
|
|
|
|
public function store(TourStoreRequest $request)
|
|
{
|
|
$data = $request->validated();
|
|
|
|
try {
|
|
$startDate = Verta::parseFormat('Y/m/d H:i', $data['start_date'])->toCarbon();
|
|
$endDate = Verta::parseFormat('Y/m/d H:i', $data['end_date'])->toCarbon();
|
|
} catch (\Throwable $e) {
|
|
return back()
|
|
->withErrors(['start_date' => 'فرمت تاریخ و ساعت وارد شده معتبر نیست.'])
|
|
->withInput();
|
|
}
|
|
|
|
if ($startDate < now()) {
|
|
return back()
|
|
->withErrors(['start_date' => 'تاریخ حرکت نمیتواند قبل از زمان و ساعت جاری باشد.'])
|
|
->withInput();
|
|
}
|
|
|
|
if ($endDate <= $startDate) {
|
|
return back()
|
|
->withErrors(['end_date' => 'تاریخ برگشت باید بعد از تاریخ حرکت باشد.'])
|
|
->withInput();
|
|
}
|
|
|
|
DB::beginTransaction();
|
|
|
|
try {
|
|
$tour = Tour::create([
|
|
'title' => $data['title'],
|
|
'summary' => $data['summary'] ?? null,
|
|
'description' => $data['description'] ?? null,
|
|
'origin_city_id' => $data['origin_city_id'],
|
|
'destination_city_id' => $data['destination_city_id'],
|
|
'tour_scope' => $data['tour_scope'],
|
|
'tour_mode' => $data['tour_mode'],
|
|
'tour_type' => $data['tour_type'],
|
|
'views_count' => 0,
|
|
]);
|
|
|
|
TourDeparture::create([
|
|
'tour_id' => $tour->id,
|
|
'start_date' => $startDate,
|
|
'end_date' => $endDate,
|
|
'price' => $data['price'],
|
|
'capacity' => $data['capacity'],
|
|
'status' => 1,
|
|
]);
|
|
if (!empty($data['images'])) {
|
|
$isDefault = true;
|
|
|
|
foreach ($data['images'] as $index => $image) {
|
|
$imageName = $tour->id . '_' . time() . rand(11111, 99999) . '.' . $image->extension();
|
|
|
|
$path = $image->storeAs('tour_images', $imageName, 'public');
|
|
|
|
$file = File::create([
|
|
'name' => $imageName,
|
|
'size' => $image->getSize(),
|
|
'original_name' => $image->getClientOriginalName(),
|
|
'path' => $path,
|
|
'extension' => $image->extension()
|
|
]);
|
|
|
|
TourImage::create([
|
|
'tour_id' => $tour->id,
|
|
'file_id' => $file->id,
|
|
'sort_order' => $index + 1,
|
|
'is_default' => $isDefault
|
|
]);
|
|
|
|
if ($isDefault) {
|
|
$isDefault = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
DB::commit();
|
|
|
|
return redirect()
|
|
->route('admin.tours.index')
|
|
->with('success', 'تور با موفقیت ایجاد شد.');
|
|
|
|
} catch (\Throwable $e) {
|
|
DB::rollBack();
|
|
Log::error('خطا در ایجاد تور: ' . $e->getMessage());
|
|
|
|
return back()
|
|
->withErrors(['error' => 'خطایی در ثبت اطلاعات رخ داد. لطفاً دوباره تلاش کنید.'])
|
|
->withInput();
|
|
}
|
|
}
|
|
|
|
public function edit(Tour $tour)
|
|
{
|
|
$title = 'ویرایش تور';
|
|
|
|
$tour->load(['originCity', 'city', 'images', 'tourDepartures']);
|
|
|
|
$departure = $tour->tourDepartures->first();
|
|
|
|
$cities = City::query()->orderBy('name')->get();
|
|
$countries = Country::query()->orderBy('name')->get();
|
|
|
|
$selectedCountryId = null;
|
|
$destinationCities = $cities;
|
|
|
|
if ($tour->tour_scope === TourScope::INTERNATIONAL && $tour->city) {
|
|
$selectedCountryId = $tour->city->county_id;
|
|
|
|
$destinationCities = City::query()
|
|
->where('county_id', $selectedCountryId)
|
|
->orderBy('name')
|
|
->get();
|
|
}
|
|
|
|
return view('admin.tours.edit', compact(
|
|
'title', 'tour', 'departure', 'cities', 'countries',
|
|
'selectedCountryId', 'destinationCities'
|
|
));
|
|
}
|
|
|
|
public function update(TourUpdateRequest $request, Tour $tour)
|
|
{
|
|
$data = $request->validated();
|
|
try {
|
|
$startDate = Verta::parse($data['start_date'])->datetime();
|
|
$endDate = Verta::parse($data['end_date'])->datetime();
|
|
} catch (\Throwable $e) {
|
|
return back()
|
|
->withErrors(['start_date' => 'فرمت تاریخ و ساعت وارد شده معتبر نیست.'])
|
|
->withInput();
|
|
}
|
|
|
|
if ($endDate <= $startDate) {
|
|
return back()
|
|
->withErrors(['end_date' => 'تاریخ برگشت باید بعد از تاریخ حرکت باشد.'])
|
|
->withInput();
|
|
}
|
|
|
|
DB::beginTransaction();
|
|
|
|
try {
|
|
$tour->update([
|
|
'title' => $data['title'],
|
|
'summary' => $data['summary'] ?? null,
|
|
'description' => $data['description'] ?? null,
|
|
'origin_city_id' => $data['origin_city_id'],
|
|
'destination_city_id' => $data['destination_city_id'],
|
|
'tour_scope' => $data['tour_scope'],
|
|
'tour_mode' => $data['tour_mode'],
|
|
'tour_type' => $data['tour_type'],
|
|
]);
|
|
|
|
$departure = $tour->tourDepartures()->first();
|
|
|
|
if ($departure) {
|
|
$departure->update([
|
|
'start_date' => $startDate,
|
|
'end_date' => $endDate,
|
|
'price' => $data['price'],
|
|
'capacity' => $data['capacity'],
|
|
]);
|
|
} else {
|
|
TourDeparture::create([
|
|
'tour_id' => $tour->id,
|
|
'start_date' => $startDate,
|
|
'end_date' => $endDate,
|
|
'price' => $data['price'],
|
|
'capacity' => $data['capacity'],
|
|
'status' => 1,
|
|
]);
|
|
}
|
|
|
|
if (!empty($data['images'])) {
|
|
$hasDefault = $tour->images()->where('is_default', true)->exists();
|
|
$nextSort = (int)$tour->images()->max('sort_order');
|
|
|
|
foreach ($data['images'] as $index => $image) {
|
|
$imageName = $tour->id . '_' . time() . rand(11111, 99999) . '.' . $image->extension();
|
|
$path = $image->storeAs('tour_images', $imageName, 'public');
|
|
|
|
$file = File::create([
|
|
'name' => $imageName,
|
|
'size' => $image->getSize(),
|
|
'original_name' => $image->getClientOriginalName(),
|
|
'path' => $path,
|
|
'extension' => $image->extension(),
|
|
]);
|
|
|
|
TourImage::create([
|
|
'tour_id' => $tour->id,
|
|
'file_id' => $file->id,
|
|
'sort_order' => $nextSort + $index + 1,
|
|
'is_default' => !$hasDefault && $index === 0,
|
|
]);
|
|
}
|
|
}
|
|
|
|
DB::commit();
|
|
|
|
return redirect()
|
|
->route('admin.tours.index')
|
|
->with('success', 'تور با موفقیت ویرایش شد.');
|
|
|
|
} catch (\Exception $exception) {
|
|
DB::rollBack();
|
|
Log::error('خطا در ویرایش تور: ' . $exception->getMessage());
|
|
|
|
return back()
|
|
->withErrors(['error' => 'خطایی در ثبت اطلاعات رخ داد. لطفاً دوباره تلاش کنید.'])
|
|
->withInput();
|
|
}
|
|
}
|
|
|
|
public function trash()
|
|
{
|
|
$title = 'تورهای حذف شده';
|
|
$tours = Tour::onlyTrashed()
|
|
->with([
|
|
'originCity',
|
|
'city',
|
|
'coverImage.file',
|
|
])
|
|
->orderByDesc('deleted_at')
|
|
->paginate(4);
|
|
return view('admin.tours.trash', compact('title', 'tours'));
|
|
}
|
|
|
|
public function destroy(Tour $tour)
|
|
{
|
|
$tour->delete();
|
|
|
|
return redirect()
|
|
->route('admin.tours.index')
|
|
->with('success', 'تور با موفقیت به سطل زباله منتقل شد.');
|
|
}
|
|
|
|
public function restore( $id)
|
|
{
|
|
$tour = Tour::onlyTrashed()->findOrFail($id);
|
|
|
|
$tour->restore();
|
|
|
|
return redirect()
|
|
->route('admin.tours.trash.index')
|
|
->with('success', 'تور با موفقیت بازگردانی شد.');
|
|
}
|
|
|
|
public function forceDelete($id)
|
|
{
|
|
$tour = Tour::onlyTrashed()->findOrFail($id);
|
|
|
|
$tour->forceDelete();
|
|
|
|
return redirect()
|
|
->route('admin.tours.trash.index')
|
|
->with('success', 'تور بهصورت دائمی حذف شد.');
|
|
}
|
|
}
|