Học Laravel 10 cơ bản – Bài 6: CRUD cơ bản trong Laravel 10

crud-co-ban-laravel

Học Laravel 10 cơ bản: CRUD cơ bản trong Laravel 10

 Trong bài viết này, bạn sẽ học cách xây dựng CRUD cơ bản trong Laravel 10 để quản lý dữ liệu posts một cách trực quan.

👉Mục tiêu: Làm tính năng CRUD (Create – Read – Update – Delete) cho bảng posts.


1. Chuẩn bị Migration + Model trong Laravel 10

Tạo migration + model:

php artisan make:model Post -m

File migration: database/migrations/xxxx_create_posts_table.php

public function up(): void
{
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->string('title');
        $table->text('content')->nullable();
        $table->string('image')->nullable(); // lưu tên file ảnh
        $table->timestamps();
    });
}

 

Chạy migration:

php artisan migrate

Model app/Models/Post.php:

class Post extends Model
{
    use HasFactory;

    protected $fillable = ['title', 'content', 'image'];
}


2. Tạo Controller Resource cho CRUD Laravel

php artisan make:controller PostController --resource

Laravel tạo app/Http/Controllers/PostController.php với sẵn 7 action:

  • index, create, store, show, edit, update, destroy.


3. Định nghĩa Route CRUD trong Laravel

Trong routes/web.php:

use App\Http\Controllers\PostController;

Route::resource('posts', PostController::class);

👉 Laravel sẽ tạo sẵn route CRUD:

  • GET /posts → index

  • GET /posts/create → create

  • POST /posts → store

  • GET /posts/{id} → show

  • GET /posts/{id}/edit → edit

  • PUT/PATCH /posts/{id} → update

  • DELETE /posts/{id} → destroy


4. Code Controller CRUD Laravel 10

app/Http/Controllers/PostController.php:

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;

class PostController extends Controller
{
    // Danh sách
    public function index()
    {
        $posts = Post::latest()->paginate(5);
        return view('posts.index', compact('posts'));
    }

    // Form thêm
    public function create()
    {
        return view('posts.create');
    }

    // Lưu mới
    public function store(Request $request)
    {
        $validated = $request->validate([
            'title'   => 'required|string|max:255',
            'content' => 'nullable|string',
            'image'   => 'nullable|image|mimes:jpg,jpeg,png|max:2048',
        ]);

        // Upload file nếu có
        if ($request->hasFile('image')) {
            $validated['image'] = $request->file('image')->store('uploads', 'public');
        }

        Post::create($validated);

        return redirect()->route('posts.index')->with('success', 'Thêm bài viết thành công!');
    }

    // Hiển thị chi tiết
    public function show(Post $post)
    {
        return view('posts.show', compact('post'));
    }

    // Form sửa
    public function edit(Post $post)
    {
        return view('posts.edit', compact('post'));
    }

    // Cập nhật
    public function update(Request $request, Post $post)
    {
        $validated = $request->validate([
            'title'   => 'required|string|max:255',
            'content' => 'nullable|string',
            'image'   => 'nullable|image|mimes:jpg,jpeg,png|max:2048',
        ]);

        if ($request->hasFile('image')) {
            $validated['image'] = $request->file('image')->store('uploads', 'public');
        }

        $post->update($validated);

        return redirect()->route('posts.index')->with('success', 'Cập nhật thành công!');
    }

    // Xóa
    public function destroy(Post $post)
    {
        $post->delete();
        return redirect()->route('posts.index')->with('success', 'Xóa thành công!');
    }
}


5. Tạo View Blade cho CRUD Laravel

Thư mục: resources/views/posts/

index.blade.php

@extends('layouts.app')

@section('content')
<h2>Danh sách bài viết</h2>
<a href="{{%20route('posts.create')%20}}">+ Thêm mới</a>

@if(session('success'))
    <p style="color:green">{{ session('success') }}</p>
@endif

<table border="1" cellpadding="10">
    <tr>
        <th>ID</th><th>Tiêu đề</th><th>Ảnh</th><th>Hành động</th>
    </tr>
    @foreach($posts as $post)
    <tr>
        <td>{{ $post->id }}</td>
        <td>{{ $post->title }}</td>
        <td>
            @if($post->image)
                <img src="{{%20asset('storage/'%20.%20$post->image)%20}}" width="80">
            @endif
        </td>
        <td>
            <a href="{{%20route('posts.show',%20$post)%20}}">Xem</a> | 
            <a href="{{%20route('posts.edit',%20$post)%20}}">Sửa</a> | 
            <form action="{{ route('posts.destroy', $post) }}" method="POST" style="display:inline">
                @csrf @method('DELETE')
                <button type="submit" onclick="return confirm('Xóa?')">Xóa</button>
            </form>
        </td>
    </tr>
    @endforeach
</table>

{{ $posts->links() }}
@endsection

create.blade.php

@extends('layouts.app')

@section('content')
<h2>Thêm bài viết</h2>

@if ($errors->any())
    <ul style="color:red">
        @foreach ($errors->all() as $error)
            <li>{{ $error }}</li>
        @endforeach
    </ul>
@endif

<form action="{{ route('posts.store') }}" method="POST" enctype="multipart/form-data">
    @csrf
    <label>Tiêu đề:</label><br>
    <input type="text" name="title" value="{{ old('title') }}"><br><br>

    <label>Nội dung:</label><br>
    <textarea name="content">{{ old('content') }}</textarea><br><br>

    <label>Ảnh:</label><br>
    <input type="file" name="image"><br><br>

    <button type="submit">Lưu</button>
</form>
@endsection

edit.blade.php

@extends('layouts.app')

@section('content')
<h2>Sửa bài viết</h2>

@if ($errors->any())
    <ul style="color:red">
        @foreach ($errors->all() as $error)
            <li>{{ $error }}</li>
        @endforeach
    </ul>
@endif

<form action="{{ route('posts.update', $post) }}" method="POST" enctype="multipart/form-data">
    @csrf @method('PUT')

    <label>Tiêu đề:</label><br>
    <input type="text" name="title" value="{{ old('title', $post->title) }}"><br><br>

    <label>Nội dung:</label><br>
    <textarea name="content">{{ old('content', $post->content) }}</textarea><br><br>

    <label>Ảnh:</label><br>
    @if($post->image)
        <img src="{{%20asset('storage/'%20.%20$post->image)%20}}" width="80"><br>
    @endif
    <input type="file" name="image"><br><br>

    <button type="submit">Cập nhật</button>
</form>
@endsection

show.blade.php

@extends('layouts.app')

@section('content')
<h2>{{ $post->title }}</h2>
<p>{{ $post->content }}</p>

@if($post->image)
    <img src="{{%20asset('storage/'%20.%20$post->image)%20}}" width="200">
@endif

<br><a href="{{%20route('posts.index')%20}}">← Quay lại</a>
@endsection


6. Layout chung để CRUD trong Laravel

Tạo file resources/views/layouts/app.blade.php:

<!DOCTYPE html>
<html>
<head>
    <title>Laravel CRUD</title>
</head>
<body>
    <h1>Laravel CRUD Example</h1>
    <hr>
    @yield('content')
</body>
</html>

✅ Kết quả

Bạn đã có CRUD cơ bản hoàn chỉnh cho bảng posts:

  • Xem danh sách

  • Thêm mới

  • Sửa

  • Xóa

  • Upload ảnh