feat: add desciption to category and sub category

This commit is contained in:
2026-06-03 16:07:29 +03:30
parent 0cb4954579
commit c52a234835
8 changed files with 107 additions and 7 deletions
+35 -3
View File
@@ -3,10 +3,14 @@
namespace App\Http\Controllers;
use App\Models\Category;
use App\Traits\StoresUploads;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
class CategoryController extends Controller
{
use StoresUploads;
public function index(Request $request)
{
$query = Category::query()->withCount('subcategories');
@@ -24,9 +28,17 @@ public function store(Request $request)
{
$data = $request->validate([
'name' => 'required|string|max:255|unique:categories,name',
'description' => 'nullable|string',
'icon' => 'nullable|image|max:8192',
]);
$category = Category::create($data);
$category = Category::create([
'name' => $data['name'],
'description' => $data['description'] ?? null,
'icon' => $request->hasFile('icon')
? $this->storeUpload($request->file('icon'), 'categories/icons')
: null,
]);
return response()->json([
'message' => 'Category created successfully',
@@ -46,10 +58,25 @@ public function update(Request $request, $id)
$category = Category::findOrFail($id);
$data = $request->validate([
'name' => 'required|string|max:255|unique:categories,name,' . $category->id,
'name' => 'sometimes|string|max:255|unique:categories,name,' . $category->id,
'description' => 'nullable|string',
'icon' => 'nullable|image|max:8192',
]);
$category->update($data);
if (array_key_exists('name', $data)) {
$category->name = $data['name'];
}
if (array_key_exists('description', $data)) {
$category->description = $data['description'];
}
if ($request->hasFile('icon')) {
if ($category->icon) {
Storage::disk('public')->delete($category->icon);
}
$category->icon = $this->storeUpload($request->file('icon'), 'categories/icons');
}
$category->save();
return response()->json([
'message' => 'Category updated successfully',
@@ -60,6 +87,11 @@ public function update(Request $request, $id)
public function destroy($id)
{
$category = Category::findOrFail($id);
if ($category->icon) {
Storage::disk('public')->delete($category->icon);
}
$category->delete();
return response()->json(['message' => 'Category deleted successfully']);
+2 -2
View File
@@ -299,7 +299,7 @@ public function filters(Request $request)
$categories = Category::query()
->withCount(['media as media_count' => $visibleMedia])
->orderByDesc('media_count')
->get(['id', 'name']);
->get(['id', 'name', 'description', 'icon']);
/*
|--------------------------------------------------------------------------
@@ -310,7 +310,7 @@ public function filters(Request $request)
$subcategories = SubCategory::query()
->withCount(['media as media_count' => $visibleMedia])
->orderByDesc('media_count')
->get(['id', 'category_id', 'name']);
->get(['id', 'category_id', 'name', 'description']);
/*
@@ -27,6 +27,7 @@ public function store(Request $request)
$data = $request->validate([
'category_id' => 'required|exists:categories,id',
'name' => 'required|string|max:255',
'description' => 'nullable|string',
]);
$existing = SubCategory::where('category_id', $data['category_id'])
@@ -62,6 +63,7 @@ public function update(Request $request, $id)
$data = $request->validate([
'category_id' => 'sometimes|exists:categories,id',
'name' => 'sometimes|string|max:255',
'description' => 'nullable|string',
]);
$categoryId = $data['category_id'] ?? $subCategory->category_id;
+8 -1
View File
@@ -6,7 +6,14 @@
class Category extends Model
{
protected $fillable = ['name'];
protected $fillable = ['name', 'description', 'icon'];
protected $appends = ['icon_url'];
public function getIconUrlAttribute(): ?string
{
return $this->icon ? asset('storage/' . $this->icon) : null;
}
public function questions()
{
+1 -1
View File
@@ -10,7 +10,7 @@ class SubCategory extends Model
{
protected $table = 'sub_categories';
protected $fillable = ['category_id', 'name'];
protected $fillable = ['category_id', 'name', 'description'];
public function category(): BelongsTo
{
@@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('categories', function (Blueprint $table) {
$table->text('description')->nullable()->after('name');
$table->string('icon')->nullable()->after('description'); // stored icon image path
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('categories', function (Blueprint $table) {
$table->dropColumn(['description', 'icon']);
});
}
};
@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('sub_categories', function (Blueprint $table) {
$table->text('description')->nullable()->after('name');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('sub_categories', function (Blueprint $table) {
$table->dropColumn('description');
});
}
};
+2
View File
@@ -222,6 +222,8 @@
Route::post('/media/{id}/note', [MediaController::class, 'storeNote']);
// Media categories
// Explicit POST update so an icon image can be uploaded (multipart can't ride a PUT).
Route::post('categories/{id}', [CategoryController::class, 'update']);
Route::apiResource('categories', CategoryController::class);
// Media sub categories