Files
admin/app/Http/Controllers/CategoryController.php
Husanjonazamov e0f1989655 classify admin
2026-02-24 12:52:01 +05:00

478 lines
19 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\Category;
use App\Models\CategoryTranslation;
use App\Models\CustomField;
use App\Models\CustomFieldCategory;
use App\Services\BootstrapTableService;
use App\Services\CachingService;
use App\Services\FileService;
use App\Services\HelperService;
use App\Services\ResponseService;
use DB;
use Illuminate\Database\QueryException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Throwable;
use function compact;
use function view;
class CategoryController extends Controller {
private string $uploadFolder;
public function __construct() {
$this->uploadFolder = "category";
}
public function index() {
ResponseService::noAnyPermissionThenRedirect(['category-list', 'category-create', 'category-update', 'category-delete']);
return view('category.index');
}
public function create(Request $request) {
$languages = CachingService::getLanguages()->values();
ResponseService::noPermissionThenRedirect('category-create');
$categories = Category::with('subcategories')->get();
return view('category.create', compact('categories', 'languages'));
}
public function store(Request $request) {
ResponseService::noPermissionThenSendJson('category-create');
$languages = CachingService::getLanguages();
$defaultLangId = 1;
$otherLanguages = $languages->where('id', '!=', $defaultLangId);
$rules = [
"name.$defaultLangId" => 'required|string|max:30',
'image' => 'required|mimes:jpg,jpeg,png|max:7168',
'parent_category_id' => 'nullable|integer',
"description.$defaultLangId" => 'nullable|string',
'slug' => [
'nullable',
'regex:/^[a-zA-Z0-9\-_]+$/'
],
'status' => 'required|boolean',
];
foreach ($otherLanguages as $lang) {
$langId = $lang->id;
$rules["name.$langId"] = 'nullable|string|max:30';
$rules["description.$langId"] = 'nullable|string';
}
$request->validate($rules, [
'slug.regex' => 'Slug must be only English letters, numbers, hyphens (-), or underscores (_).'
]);
try {
$data = [
'name' => $request->input("name.$defaultLangId"),
'description' => $request->input("description.$defaultLangId"),
'parent_category_id' => $request->parent_category_id,
'status' => $request->status,
'is_job_category' => $request->is_job_category ?? 0,
'price_optional' => $request->price_optional ?? 0,
];
$slug = trim($request->input('slug') ?? '');
$slug = preg_replace('/[^a-z0-9]+/i', '-', strtolower($slug));
$slug = trim($slug, '-');
if (empty($slug)) {
$slug = HelperService::generateRandomSlug();
}
$data['slug'] = HelperService::generateUniqueSlug(new Category, $slug);
if ($request->hasFile('image')) {
$data['image'] = FileService::compressAndUpload($request->file('image'), $this->uploadFolder);
}
$category = Category::create($data);
foreach ($otherLanguages as $lang) {
$langId = $lang->id;
$translatedName = $request->input("name.$langId");
$translatedDescription = $request->input("description.$langId");
if (!empty($translatedName) || !empty($translatedDescription)) {
$category->translations()->create([
'name' => $translatedName ?? '',
'description' => $translatedDescription ?? null,
'language_id' => $langId,
]);
}
}
ResponseService::successRedirectResponse("Category Added Successfully");
} catch (Throwable $th) {
ResponseService::logErrorRedirect($th);
ResponseService::errorRedirectResponse();
}
}
public function show(Request $request, $id) {
ResponseService::noPermissionThenSendJson('category-list');
$offset = $request->input('offset', 0);
$limit = $request->input('limit', 10);
$sort = $request->input('sort', 'sequence');
$order = $request->input('order', 'ASC');
$sql = Category::without('translations')->withCount('subcategories')->withCount('custom_fields')->with('subcategories');
if ($id == "0") {
$sql->whereNull('parent_category_id');
} else {
$sql->where('parent_category_id', $id);
}
if (!empty($request->search)) {
$sql = $sql->search($request->search);
}
if ($sort !== 'advertisements_count') {
$sql->orderBy($sort, $order);
}
$result = $sql->get();
if ($sort === 'advertisements_count') {
$result = $result->sortBy(function ($category) {
return $category->all_items_count;
}, SORT_REGULAR, strtolower($order) === 'desc')->values();
$result = $result->slice($offset, $limit)->values();
} else {
$result = $result->slice($offset, $limit);
}
$total = $sql->count();
$bulkData = array();
$bulkData['total'] = $total;
$rows = array();
$no = 1;
foreach ($result as $key => $row) {
$operate = '';
if (Auth::user()->can('category-update')) {
$operate .= BootstrapTableService::editButton(route('category.edit', $row->id));
}
if (Auth::user()->can('category-delete')) {
$operate .= BootstrapTableService::deleteButton(route('category.destroy', $row->id));
}
if ($row->subcategories_count > 1) {
$operate .= BootstrapTableService::button('fa fa-list-ol',route('sub.category.order.change', $row->id),['btn-secondary']);
}
$tempRow = $row->toArray();
$tempRow['no'] = $no++;
$tempRow['subcategories_count'] = $row->subcategories_count . ' ' . __('Subcategories');
$tempRow['custom_fields_count'] = $row->custom_fields_count . ' ' . __('Custom Fields');
$tempRow['operate'] = $operate;
$tempRow['advertisements_count'] = $row->all_items_count;
$rows[] = $tempRow;
}
$bulkData['rows'] = $rows;
return response()->json($bulkData);
}
public function edit($id) {
ResponseService::noPermissionThenRedirect('category-update');
$category_data = Category::findOrFail($id);
// Initialize translations array with English (default) data
$translations = [];
$translations[1] = [
'name' => $category_data->name,
'description' => $category_data->description,
];
// Add other language translations
foreach ($category_data->translations as $translation) {
$translations[$translation->language_id] = [
'name' => $translation->name,
'description' => $translation->description,
];
}
$parent_category_data = Category::find($category_data->parent_category_id);
$parent_category = $parent_category_data->name ?? '';
$categories = Category::with('subcategories')->get();
// Fetch all languages including English
$languages = CachingService::getLanguages()->values();
return view('category.edit', compact('category_data', 'parent_category_data','parent_category', 'translations', 'languages','categories'));
}
public function update(Request $request, $id) {
ResponseService::noPermissionThenSendJson('category-update');
try {
$languages = CachingService::getLanguages();
$defaultLangId = 1;
$otherLanguages = $languages->where('id', '!=', $defaultLangId);
$rules = [
"name.$defaultLangId" => 'required|string|max:30',
'image' => 'nullable|mimes:jpg,jpeg,png|max:7168',
'parent_category_id' => 'nullable|integer',
"description.$defaultLangId" => 'nullable|string',
'slug' => [
'nullable',
'regex:/^[a-zA-Z0-9\-_]+$/'
],
'status' => 'required|boolean',
];
foreach ($otherLanguages as $lang) {
$langId = $lang->id;
$rules["name.$langId"] = 'nullable|string|max:30';
$rules["description.$langId"] = 'nullable|string';
}
$request->validate($rules, [
'slug.regex' => 'Slug must be only English letters, numbers, hyphens (-), or underscores (_).'
]);
$category = Category::find($id);
if ($request->parent_category_id == $category->id) {
return back()->withErrors(['parent_category' => 'A category cannot be set as its own parent.']);
}
$data = [
'name' => $request->input("name.$defaultLangId"),
'description' => $request->input("description.$defaultLangId"),
'parent_category_id' => $request->parent_category_id,
'status' => $request->status,
'is_job_category' => $request->is_job_category ?? 0,
'price_optional' => $request->price_optional ?? 0,
];
if ($request->hasFile('image')) {
$data['image'] = FileService::compressAndReplace($request->file('image'), $this->uploadFolder, $category->getRawOriginal('image'));
}
$slug = trim($request->input('slug') ?? '');
$slug = preg_replace('/[^a-z0-9]+/i', '-', strtolower($slug));
$slug = trim($slug, '-');
if (empty($slug)) {
$slug = HelperService::generateRandomSlug();
}
$data['slug'] = HelperService::generateUniqueSlug(new Category(), $slug, $category->id);
$category->update($data);
if ($request->has('is_job_category')) {
$category->subcategories()->update([
'is_job_category' => $request->is_job_category ? 1 : 0,
]);
}
if ($request->has('price_optional')) {
$category->subcategories()->update([
'price_optional' => $request->price_optional ? 1 : 0,
]);
}
foreach ($otherLanguages as $lang) {
$langId = $lang->id;
$translatedName = $request->input("name.$langId");
$translatedDescription = $request->input("description.$langId");
CategoryTranslation::updateOrCreate(
['category_id' => $category->id, 'language_id' => $langId],
[
'name' => $translatedName ?? '',
'description' => $translatedDescription ?? null
]
);
}
ResponseService::successRedirectResponse("Category Updated Successfully", route('category.index'));
} catch (Throwable $th) {
ResponseService::logErrorRedirect($th);
ResponseService::errorRedirectResponse('Something Went Wrong');
}
}
// public function destroy($id) {
// ResponseService::noPermissionThenSendJson('category-delete');
// try {
// $category = Category::withCount(['subcategories', 'custom_fields'])
// ->with('subcategories')
// ->findOrFail($id);
// if ($category->all_items_count > 0) {
// ResponseService::errorResponse('Cannot delete category. It has associated advertisements.');
// }
// if ($category->other_items_count > 0) {
// ResponseService::errorResponse(
// 'Cannot delete category. Delete non-active items first.'
// );
// }
// if ($category->subcategories_count > 0 || $category->custom_fields_count > 0) {
// ResponseService::errorResponse('Failed to delete category', 'Cannot delete category. Remove associated subcategories and custom fields first.');
// }
// if ($category->delete()) {
// ResponseService::successResponse('Category delete successfully');
// }
// } catch (QueryException $th) {
// ResponseService::logErrorResponse($th, 'Failed to delete category', 'Cannot delete category. Remove associated subcategories and custom fields first.');
// ResponseService::errorResponse('Something Went Wrong');
// } catch (Throwable $th) {
// ResponseService::logErrorResponse($th, "CategoryController -> delete");
// ResponseService::errorResponse('Something Went Wrong');
// }
// }
public function destroy($id)
{
ResponseService::noPermissionThenSendJson('category-delete');
try {
$category = Category::withCount([
'subcategories',
'custom_fields',
'items as all_items_count',
'items as other_items_count' => function ($q) {
$q->where('status', '!=', 'active');
}
])->findOrFail($id);
if ($category->all_items_count > 0) {
return ResponseService::errorResponse(
'Cannot delete category. It has associated advertisements.'
);
}
if ($category->other_items_count > 0) {
return ResponseService::errorResponse(
'Cannot delete category. Delete non-active items first.'
);
}
if ($category->subcategories_count > 0 || $category->custom_fields_count > 0) {
return ResponseService::errorResponse(
'Cannot delete category. Remove associated subcategories and custom fields first.'
);
}
$category->delete();
return ResponseService::successResponse('Category deleted successfully');
} catch (Throwable $th) {
ResponseService::logErrorResponse($th, 'CategoryController -> destroy');
return ResponseService::errorResponse('Something went wrong');
}
}
public function getSubCategories($id) {
ResponseService::noPermissionThenRedirect('category-list');
$subcategories = Category::where('parent_category_id', $id)
->with('subcategories')
->withCount('custom_fields')
->withCount('subcategories')
->withCount('items')
->orderBy('sequence')
->get()
->map(function ($subcategory) {
$operate = '';
if (Auth::user()->can('category-update')) {
$operate .= BootstrapTableService::editButton(route('category.edit', $subcategory->id));
}
if (Auth::user()->can('category-delete')) {
$operate .= BootstrapTableService::deleteButton(route('category.destroy', $subcategory->id));
}
if ($subcategory->subcategories_count > 1) {
$operate .= BootstrapTableService::button('fa fa-list-ol',route('sub.category.order.change',$subcategory->id),['btn-secondary']);
}
$subcategory->operate = $operate;
return $subcategory;
});
return response()->json($subcategories);
}
public function customFields($id) {
ResponseService::noPermissionThenRedirect('custom-field-list');
$category = Category::find($id);
$p_id = $category->parent_category_id;
$cat_id = $category->id;
$category_name = $category->name;
return view('category.custom-fields', compact('cat_id', 'category_name', 'p_id'));
}
public function getCategoryCustomFields(Request $request, $id) {
ResponseService::noPermissionThenSendJson('custom-field-list');
$offset = $request->input('offset', 0);
$limit = $request->input('limit', 10);
$sort = $request->input('sort', 'id');
$order = $request->input('order', 'ASC');
$sql = CustomField::whereHas('categories', static function ($q) use ($id) {
$q->where('category_id', $id);
})->orderBy($sort, $order);
if (isset($request->search)) {
$sql->search($request->search);
}
$sql->take($limit);
$total = $sql->count();
$res = $sql->skip($offset)->take($limit)->get();
$bulkData = array();
$rows = array();
$tempRow['type'] = '';
foreach ($res as $row) {
$tempRow = $row->toArray();
// $operate = BootstrapTableService::editButton(route('custom-fields.edit', $row->id));
$operate = BootstrapTableService::deleteButton(route('category.custom-fields.destroy', [$id, $row->id]));
$tempRow['operate'] = $operate;
$rows[] = $tempRow;
}
$bulkData['rows'] = $rows;
$bulkData['total'] = $total;
return response()->json($bulkData);
}
public function destroyCategoryCustomField($categoryID, $customFieldID) {
try {
ResponseService::noPermissionThenRedirect('custom-field-delete');
CustomFieldCategory::where(['category_id' => $categoryID, 'custom_field_id' => $customFieldID])->delete();
ResponseService::successResponse("Custom Field Deleted Successfully");
} catch (Throwable $th) {
ResponseService::logErrorResponse($th, "CategoryController -> destroyCategoryCustomField");
ResponseService::errorResponse('Something Went Wrong');
}
}
public function categoriesReOrder(Request $request) {
$categories = Category::whereNull('parent_category_id')->orderBy('sequence')->get();
return view('category.categories-order', compact('categories'));
}
public function subCategoriesReOrder(Request $request ,$id) {
$categories = Category::with('subcategories')->where('parent_category_id', $id)->orderBy('sequence')->get();
return view('category.sub-categories-order', compact('categories'));
}
public function updateOrder(Request $request) {
$request->validate([
'order' => 'required'
]);
try {
$order = json_decode($request->input('order'), true);
$data = [];
foreach ($order as $index => $id) {
$data[] = [
'id' => $id,
'sequence' => $index + 1,
];
}
Category::upsert($data, ['id'], ['sequence']);
ResponseService::successResponse("Order Updated Successfully");
} catch (Throwable $th) {
ResponseService::logErrorRedirect($th);
ResponseService::errorResponse('Something Went Wrong');
}
}
}