Courses

React Laravel 12 Starter Kit: CRUD Project

Practice Another CRUD: Task Categories

Summary of this lesson:
- Creating a Task Categories CRUD similar to Tasks CRUD
- Building model, migrations, controllers, and routes
- Implementing React components for category management
- Handling relationship between tasks and categories

Let's practice creating a CRUD with another one: Task Categories. It will be almost the same as Tasks CRUD, so for the most part, I will just show the code and specify the differences.


Task Categories: DB Model/Migration

First, we prepare the back end.

Create Model, Migration, and Pivot table for task categories:

php artisan make:model TaskCategory -m
php artisan make:migration create_task_task_category_table

Migration:

Schema::create('task_categories', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});

Pivot migration:

Schema::create('task_task_category', function (Blueprint $table) {
$table->foreignId('task_id')->constrained();
$table->foreignId('task_category_id')->constrained();
});

app/Models/Task.php:

use Illuminate\Database\Eloquent\Relations\BelongsToMany;
 
// ...
 
public function taskCategories(): BelongsToMany
{
return $this->belongsToMany(TaskCategory::class);
}

app/Models/TaskCategory.php

namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
 
class TaskCategory extends Model
{
protected $fillable = ['name'];
 
public function tasks(): BelongsToMany
{
return $this->belongsToMany(Task::class);
}
}

Controller and Routes

Create a Controller and Form Requests:

php artisan make:controller TaskCategoryController
php artisan make:request StoreTaskCategoryRequest
php artisan make:request UpdateTaskCategoryRequest

app/Http/Controllers/TaskCategoryController.php

use App\Http\Requests\StoreTaskCategoryRequest;
use App\Http\Requests\UpdateTaskCategoryRequest;
use App\Models\TaskCategory;
use Inertia\Inertia;
 
class TaskCategoryController extends Controller
{
public function index()
{
return Inertia::render('TaskCategories/Index', [
'taskCategories' => TaskCategory::query()
->withCount('tasks')
->paginate(10),
]);
}
 
public function create()
{
return Inertia::render('TaskCategories/Create');
}
 
public function store(StoreTaskCategoryRequest $request)
{
TaskCategory::create($request->validated());
 
return redirect()->route('task-categories.index');
}
 
public function edit(TaskCategory $taskCategory)
{
return Inertia::render('TaskCategories/Edit', [
'taskCategory' => $taskCategory,
]);
}
 
public function update(UpdateTaskCategoryRequest $request, TaskCategory $taskCategory)
{
$taskCategory->update($request->validated());
 
return redirect()->route('task-categories.index');
}
 
public function destroy(TaskCategory $taskCategory)
{
if ($taskCategory->tasks()->count() > 0) {
$taskCategory->tasks()->detach();
}
 
$taskCategory->delete();
 
return redirect()->route('task-categories.index');
}
}

As you can see, in the destroy() method, we check for the assigned tasks and detach them if they exist. We'll get back to this when we discuss the deleting action.

app/Http/Requests/StoreTaskCategoryRequest.php

use Illuminate\Foundation\Http\FormRequest;
 
class StoreTaskCategoryRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => ['required'],
];
}
 
public function authorize(): bool
{
return true;
}
}

app/Http/Requests/UpdateTaskCategoryRequest.php

use Illuminate\Foundation\Http\FormRequest;
 
class UpdateTaskCategoryRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => ['required'],
];
}
 
public function authorize(): bool
{
return true;
}
}

routes/web.php

use App\Http\Controllers\TaskCategoryController;
 
// ...
 
Route::middleware(['auth', 'verified'])->group(function () {
 
// ...
 
Route::resource('tasks', TaskController::class);
Route::resource('task-categories', TaskCategoryController::class);
});
 
// ...

TypeScript: Creating Types

Now, let's move to the front end. First, a new...

The full lesson is only for Premium Members.
Want to access all 14 lessons of this course? (77 min read)

You also get:

  • 75 courses
  • Premium tutorials
  • Access to repositories
  • Private Discord