feat: add type category
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
use App\Traits\StoresUploads;
|
use App\Traits\StoresUploads;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
class CategoryController extends Controller
|
class CategoryController extends Controller
|
||||||
{
|
{
|
||||||
@@ -15,6 +16,10 @@ public function index(Request $request)
|
|||||||
{
|
{
|
||||||
$query = Category::query()->withCount('subcategories');
|
$query = Category::query()->withCount('subcategories');
|
||||||
|
|
||||||
|
if ($request->filled('type')) {
|
||||||
|
$query->where('type', $request->input('type'));
|
||||||
|
}
|
||||||
|
|
||||||
if ($request->boolean('with_subcategories')) {
|
if ($request->boolean('with_subcategories')) {
|
||||||
$query->with('subcategories');
|
$query->with('subcategories');
|
||||||
}
|
}
|
||||||
@@ -27,13 +32,20 @@ public function index(Request $request)
|
|||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
$data = $request->validate([
|
$data = $request->validate([
|
||||||
'name' => 'required|string|max:255|unique:categories,name',
|
'name' => [
|
||||||
|
'required',
|
||||||
|
'string',
|
||||||
|
'max:255',
|
||||||
|
Rule::unique('categories', 'name')->where('type', $request->input('type', Category::TYPE_MEDIA)),
|
||||||
|
],
|
||||||
|
'type' => ['nullable', Rule::in(Category::TYPES)],
|
||||||
'description' => 'nullable|string',
|
'description' => 'nullable|string',
|
||||||
'icon' => 'nullable|file|extensions:jpg,jpeg,png,gif,webp,bmp,svg|max:8192',
|
'icon' => 'nullable|file|extensions:jpg,jpeg,png,gif,webp,bmp,svg|max:8192',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$category = Category::create([
|
$category = Category::create([
|
||||||
'name' => $data['name'],
|
'name' => $data['name'],
|
||||||
|
'type' => $data['type'] ?? Category::TYPE_MEDIA,
|
||||||
'description' => $data['description'] ?? null,
|
'description' => $data['description'] ?? null,
|
||||||
'icon' => $request->hasFile('icon')
|
'icon' => $request->hasFile('icon')
|
||||||
? $this->storeUpload($request->file('icon'), 'categories/icons')
|
? $this->storeUpload($request->file('icon'), 'categories/icons')
|
||||||
@@ -57,12 +69,25 @@ public function update(Request $request, $id)
|
|||||||
{
|
{
|
||||||
$category = Category::findOrFail($id);
|
$category = Category::findOrFail($id);
|
||||||
|
|
||||||
|
$targetType = $request->input('type', $category->type);
|
||||||
|
|
||||||
$data = $request->validate([
|
$data = $request->validate([
|
||||||
'name' => 'sometimes|string|max:255|unique:categories,name,' . $category->id,
|
'name' => [
|
||||||
|
'sometimes',
|
||||||
|
'string',
|
||||||
|
'max:255',
|
||||||
|
Rule::unique('categories', 'name')
|
||||||
|
->where('type', $targetType)
|
||||||
|
->ignore($category->id),
|
||||||
|
],
|
||||||
|
'type' => ['nullable', Rule::in(Category::TYPES)],
|
||||||
'description' => 'nullable|string',
|
'description' => 'nullable|string',
|
||||||
'icon' => 'nullable|file|extensions:jpg,jpeg,png,gif,webp,bmp,svg|max:8192',
|
'icon' => 'nullable|file|extensions:jpg,jpeg,png,gif,webp,bmp,svg|max:8192',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if (array_key_exists('type', $data) && $data['type'] !== null) {
|
||||||
|
$category->type = $data['type'];
|
||||||
|
}
|
||||||
if (array_key_exists('name', $data)) {
|
if (array_key_exists('name', $data)) {
|
||||||
$category->name = $data['name'];
|
$category->name = $data['name'];
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-1
@@ -6,7 +6,17 @@
|
|||||||
|
|
||||||
class Category extends Model
|
class Category extends Model
|
||||||
{
|
{
|
||||||
protected $fillable = ['name', 'description', 'icon'];
|
public const TYPE_MEDIA = 'media';
|
||||||
|
public const TYPE_PLAYLIST = 'playlist';
|
||||||
|
public const TYPE_BREATHING_TEMPLATE = 'breathing_template';
|
||||||
|
|
||||||
|
public const TYPES = [
|
||||||
|
self::TYPE_MEDIA,
|
||||||
|
self::TYPE_PLAYLIST,
|
||||||
|
self::TYPE_BREATHING_TEMPLATE,
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $fillable = ['name', 'type', 'description', 'icon'];
|
||||||
|
|
||||||
protected $appends = ['icon_url'];
|
protected $appends = ['icon_url'];
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('categories', function (Blueprint $table) {
|
||||||
|
// General category type: media | playlist | breathing_template
|
||||||
|
$table->string('type')->default('media')->after('name')->index();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Existing categories were used for media content.
|
||||||
|
DB::table('categories')->update(['type' => 'media']);
|
||||||
|
|
||||||
|
// Name is unique per type (same name may exist for media and playlist).
|
||||||
|
Schema::table('categories', function (Blueprint $table) {
|
||||||
|
$table->dropUnique('categories_name_unique');
|
||||||
|
$table->unique(['name', 'type']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('categories', function (Blueprint $table) {
|
||||||
|
$table->dropUnique(['name', 'type']);
|
||||||
|
$table->unique('name');
|
||||||
|
$table->dropColumn('type');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user