Build Your First CRUD App in Laravel
Summary: Step-by-step CRUD application in Laravel using controllers and Blade.
Laravel, a powerful PHP framework, offers an elegant syntax and robust features to kickstart web applications. One of the first steps for any developer is to master CRUD: Create, Read, Update, Delete. In this tutorial, we'll build a simple CRUD app in Laravel using controllers and Blade views from scratch. Let’s get started!
Prerequisites
Before you begin, ensure you have:
- PHP (8.x recommended)
- Composer
- Laravel CLI
- A database system (MySQL, Postgres, etc.)
1. Setting Up a New Laravel Project
Open your terminal and run:
composer create-project laravel/laravel laravel-crud-app
cd laravel-crud-app
2. Set Up the Database
Edit your .env
file with your database configuration:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=crud_app
DB_USERNAME=root
DB_PASSWORD=your-password
Create the database in your DBMS, for example:
CREATE DATABASE crud_app;
3. Create a Model, Migration, and Controller
Suppose we want to manage Posts. Generate the required files:
php artisan make:model Post -mcr
This does three things:
-m
creates a migration file.-c
creates a controller (app/Http/Controllers/PostController.php).-r
makes the controller resourceful.
4. Update the Migration
Open database/migrations/xxxx_xx_xx_create_posts_table.php
and update:
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->timestamps();
});
}
Run the migration:
php artisan migrate
5. Define Resource Routes
Open routes/web.php
and add:
use App\Http\Controllers\PostController;
Route::resource('posts', PostController::class);
This generates all CRUD routes for posts.
6. Building the Controller Logic
Open app/Http/Controllers/PostController.php
and add CRUD methods:
use App\Models\Post;
public function index()
{
$posts = Post::latest()->get();
return view('posts.index', compact('posts'));
}
public function create()
{
return view('posts.create');
}
public function store(Request $request)
{
$validated = $request->validate([
'title' => 'required|max:255',
'content' => 'required',
]);
Post::create($validated);
return redirect()->route('posts.index')->with('success', 'Post created successfully!');
}
public function show(Post $post)
{
return view('posts.show', compact('post'));
}
public function edit(Post $post)
{
return view('posts.edit', compact('post'));
}
public function update(Request $request, Post $post)
{
$validated = $request->validate([
'title' => 'required|max:255',
'content' => 'required',
]);
$post->update($validated);
return redirect()->route('posts.index')->with('success', 'Post updated successfully!');
}
public function destroy(Post $post)
{
$post->delete();
return redirect()->route('posts.index')->with('success', 'Post deleted successfully!');
}
7. Enable Mass Assignment
Open app/Models/Post.php
and add:
protected $fillable = ['title', 'content'];
8. Creating Blade Views
Create a new folder: resources/views/posts
.
index.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<h1>Posts</h1>
<a href="{{ route('posts.create') }}" class="btn btn-primary mb-2">New Post</a>
@if(session('success'))
<div class="alert alert-success">{{ session('success') }}</div>
@endif
<table class="table">
<thead>
<tr>
<th>Title</th>
<th>Content</th>
<th colspan="2"></th>
</tr>
</thead>
<tbody>
@forelse($posts as $post)
<tr>
<td><a href="{{ route('posts.show', $post) }}">{{ $post->title }}</a></td>
<td>{{ Str::limit($post->content, 50) }}</td>
<td><a href="{{ route('posts.edit', $post) }}" class="btn btn-sm btn-secondary">Edit</a></td>
<td>
<form action="{{ route('posts.destroy', $post) }}" method="POST">
@csrf
@method('DELETE')
<button class="btn btn-sm btn-danger" onclick="return confirm('Delete this post?')">Delete</button>
</form>
</td>
</tr>
@empty
<tr><td colspan="4">No posts found.</td></tr>
@endforelse
</tbody>
</table>
</div>
@endsection
create.blade.php
and edit.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<h1>{{ isset($post) ? 'Edit Post' : 'Create Post' }}</h1>
<form method="POST" action="{{ isset($post) ? route('posts.update', $post) : route('posts.store') }}">
@csrf
@if(isset($post))
@method('PUT')
@endif
<div class="mb-3">
<label class="form-label">Title</label>
<input type="text" name="title" class="form-control" value="{{ old('title', $post->title ?? '') }}" required>
</div>
<div class="mb-3">
<label class="form-label">Content</label>
<textarea name="content" class="form-control" rows="5" required>{{ old('content', $post->content ?? '') }}</textarea>
</div>
<button class="btn btn-success">{{ isset($post) ? 'Update' : 'Create' }}</button>
<a href="{{ route('posts.index') }}" class="btn btn-secondary">Back</a>
</form>
</div>
@endsection
show.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<h1>{{ $post->title }}</h1>
<p>{{ $post->content }}</p>
<a class="btn btn-secondary" href="{{ route('posts.index') }}">Back</a>
</div>
@endsection
9. Layout (Optional Bootstrap Setup)
For quick styling, generate a base layout: resources/views/layouts/app.blade.php
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Laravel CRUD App</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
@yield('content')
</body>
</html>
10. Test Your Application
Run your app locally:
php artisan serve
Visit http://127.0.0.1:8000/posts in your browser.
Conclusion
Congratulations! You’ve built a full-featured CRUD application in Laravel using resource controllers and Blade views. From setting up the database to creating, updating, and deleting posts, you have touched on essential Laravel fundamentals.
Happy coding! 🚀
Further Reading:
If you enjoyed this guide or have questions, leave a comment below!