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'); } } }