diff --git a/app/Http/Controllers/Admin/CategoryController.php b/app/Http/Controllers/Admin/CategoryController.php index 284dfa4..6fc86be 100644 --- a/app/Http/Controllers/Admin/CategoryController.php +++ b/app/Http/Controllers/Admin/CategoryController.php @@ -108,7 +108,7 @@ class CategoryController extends Controller if ($request->filled('search')) { $needle = trim((string) $request->search); $categories = $categories->filter( - static fn ($category) => str_contains((string) $category->name, $needle) + static fn ($category) => strpos((string) $category->name, $needle) !== false )->values(); } diff --git a/app/Services/CategoryService.php b/app/Services/CategoryService.php index f313b84..6c86ea8 100644 --- a/app/Services/CategoryService.php +++ b/app/Services/CategoryService.php @@ -5,6 +5,7 @@ namespace App\Services; use App\Models\Category; use App\Models\Product; use Illuminate\Support\Collection; +use Illuminate\Support\Facades\Schema; class CategoryService { @@ -145,11 +146,56 @@ class CategoryService return collect(); } - return Category::query() + if (! Schema::hasTable('categories')) { + return $this->fallbackClientCategories($groupsWithProducts); + } + + if (! Schema::hasColumn('categories', 'sort_order')) { + return $this->fallbackClientCategories($groupsWithProducts); + } + + $categories = Category::query() ->where('active', 1) ->whereIn('name', $groupsWithProducts) ->orderBy('sort_order') ->orderBy('id') ->get(['id', 'name', 'sort_order']); + + if ($categories->isEmpty()) { + $this->syncFromProducts(); + + return Category::query() + ->where('active', 1) + ->whereIn('name', $groupsWithProducts) + ->orderBy('sort_order') + ->orderBy('id') + ->get(['id', 'name', 'sort_order']); + } + + return $categories; + } + + /** وقتی جدول categories هنوز migrate نشده — از group_type محصولات */ + private function fallbackClientCategories(Collection $groupsWithProducts): Collection + { + $ordered = collect(self::DEFAULT_CATEGORY_NAMES) + ->merge($groupsWithProducts) + ->unique() + ->values(); + + $order = 0; + + return $ordered + ->filter(static fn (string $name) => $groupsWithProducts->contains($name)) + ->values() + ->map(static function (string $name) use (&$order) { + $order++; + + return (object) [ + 'id' => $order, + 'name' => $name, + 'sort_order' => $order, + ]; + }); } } diff --git a/database/migrations/2026_06_16_000002_ensure_categories_table_exists.php b/database/migrations/2026_06_16_000002_ensure_categories_table_exists.php new file mode 100644 index 0000000..464daab --- /dev/null +++ b/database/migrations/2026_06_16_000002_ensure_categories_table_exists.php @@ -0,0 +1,46 @@ +id(); + $table->string('name')->unique(); + $table->boolean('active')->default(true); + $table->boolean('show_in_filter')->default(true); + $table->boolean('show_in_select')->default(true); + $table->unsignedSmallInteger('sort_order')->default(0); + $table->timestamp('created_at')->nullable(); + }); + + return; + } + + Schema::table('categories', function (Blueprint $table) { + if (! Schema::hasColumn('categories', 'show_in_filter')) { + $table->boolean('show_in_filter')->default(true); + } + if (! Schema::hasColumn('categories', 'show_in_select')) { + $table->boolean('show_in_select')->default(true); + } + if (! Schema::hasColumn('categories', 'sort_order')) { + $table->unsignedSmallInteger('sort_order')->default(0); + } + }); + } + + public function down(): void + { + // عمداً خالی — rollback جدول را حذف نمی‌کند + } +}; diff --git a/database/sql/categories_table_deploy.sql b/database/sql/categories_table_deploy.sql new file mode 100644 index 0000000..81e554f --- /dev/null +++ b/database/sql/categories_table_deploy.sql @@ -0,0 +1,17 @@ +-- جدول دسته‌بندی محصولات (تب‌های فیلتر اپ + ادمین) +-- خطای 500 روی GET /customer/categories وقتی این جدول نیست + +CREATE TABLE IF NOT EXISTS `categories` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `active` tinyint(1) NOT NULL DEFAULT 1, + `show_in_filter` tinyint(1) NOT NULL DEFAULT 1, + `show_in_select` tinyint(1) NOT NULL DEFAULT 1, + `sort_order` smallint unsigned NOT NULL DEFAULT 0, + `created_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `categories_name_unique` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- بعد از اجرا: ادمین → دسته‌بندی → «همگام‌سازی از محصولات» +-- یا: POST /admin/categories/sync-from-products