Courses

React Laravel 12 Starter Kit: CRUD Project

DB Model, New React Page and Menu Item

You're reading a FREE PREVIEW of a PREMIUM course.
Summary of this lesson:
- Create Task model, migration, and factory with sample data
- Build controller and routes for CRUD operations
- Set up validation with Form Request classes
- Add React.js navigation menu item with icon for Tasks

Let's try to create a simple CRUD for Tasks with two fields (for now): name and is_completed.

In this lesson, we'll manage the Model/Migration, Routes, and Controllers and add a navigation link in the top menu.


Preparing the Database

First, we create the DB structure with factories to create some fake records:

php artisan make:model Task -mf

The table structure is in Migration.

database/migrations/xxxx_create_tasks_table.php:

public function up(): void
{
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->boolean('is_completed')->default(false);
$table->timestamps();
});
}

In the Model, we just make the fields fillable and cast is_completed to boolean.

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
 
class Task extends Model
{
use HasFactory;
 
protected $fillable = [
'name',
'is_completed'
];
 
protected function casts(): array
{
return [
'is_completed' => 'boolean'
];
}
}

Then, the Factory with the rules.

database/factories/TaskFactory.php:

class TaskFactory extends Factory
{
public function definition(): array
{
return [
'name' => fake()->name(),
'is_completed' => fake()->boolean(),
];
}
}

Finally, that Factory should be used in the main seeder to create 10 fake task records.

database/seeders/DatabaseSeeder.php:

use App\Models\Task;
use App\Models\User;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
 
class DatabaseSeeder extends Seeder
{
public function run(): void
{
User::factory()->create([
'name' => 'Test User',
'email' => 'test@example.com',
]);
 
Task::factory()->count(10)->create();
}
}

And then we run the command:

php artisan migrate --seed

As a result, we have 10 records in the DB.


Controller and Routes

We will create a Resource Controller to manage the tasks with this command:

php artisan make:controller TaskController --resource --model=Task

Then, we assign that Controller to the Routes.

routes/web.php:

Route::middleware(['auth', 'verified'])->group(function () {
Route::get('dashboard', function () {
return Inertia::render('dashboard');
})->name('dashboard');
 
Route::resource('tasks', TaskController::class);
});

Now, what's inside that Controller?

We will fill it with the CRUD actions, with Inertia referencing the new React.js components that don't yet exist. We will actually create them in the next lesson.

We will also need validation rules. I prefer to use Form Request classes, so I will generate them right away.

php artisan make:request StoreTaskRequest
php artisan make:request UpdateTaskRequest

And here are the contents.

app/Http/Requests/StoreTaskRequest.php:

class StoreTaskRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
 
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
];
}
}

app/Http/Requests/UpdateTaskRequest.php:

class StoreTaskRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
 
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'is_completed' => ['boolean'],
];
}
}

Almost identical, with one difference: the create form will not contain the is_completed field, so it's not present in the rules() list.

Now, here's our Controller.

app/Http/Controllers/TaskController.php:

namespace App\Http\Controllers;
 
use App\Http\Requests\StoreTaskRequest;
use App\Http\Requests\UpdateTaskRequest;
use App\Models\Task;
use Inertia\Inertia;
 
class TaskController extends Controller
{
public function index()
{
return Inertia::render('Tasks/Index', [
'tasks' => Task::all(),
]);
}
 
public function create()
{
return Inertia::render('Tasks/Create');
}
 
public function store(StoreTaskRequest $request)
{
Task::create($request->validated() + ['is_completed' => false]);
 
return redirect()->route('tasks.index');
}
 
public function edit(Task $task)
{
return Inertia::render('Tasks/Edit', [
'task' => $task,
]);
}
 
public function update(UpdateTaskRequest $request, Task $task)
{
$task->update($request->validated());
 
return redirect()->route('tasks.index');
}
 
public function destroy(Task $task)
{
$task->delete();
 
return redirect()->route('tasks.index');
}
}

Great, now how do we test if it works?

Let's add a menu item leading to the tasks.index route.


Index React Component and Navigation Item

In the index() method of the Controller, we return this React component:

return Inertia::render('Tasks/Index');

By default, Inertia is configured to return React...

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