Bài 6: Hướng dẫn từng bước thực hành chức năng thêm, sửa, xóa (CRUD) bảng products trong laravel

Hướng dẫn từng bước thực hành chức năng thêm, sửa, xóa (CRUD) bảng products trong laravel

Dưới đây là hướng dẫn thêm – sửa – xóa trong Laravel với ví dụ cụ thể, từng bước từ đầu đến cuối. ví dụ quản lý sản phẩm (Product) với MySQL.


Lưu ý quan trọng:

  • Kế thừa từ bài thức hành số 5, đã có chức năng CRUD trên bảng categories

Nếu chưa có bài lab số 5

Bước 1: hãy tạo CSDL ql_ban_hang

Kết nối CSDL

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE= ql_ban_hang
DB_USERNAME=root
DB_PASSWORD=

Bước 2: Tạo bảng categories và thêm dữ liệu mẫu cho nó

CREATE TABLE categories (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    status tinyint(1) NULL DEFAULT(1)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 4. Thêm 10 dòng dữ liệu hoa quả
INSERT INTO categories (name) VALUES
('Táo'),
('Cam'),
('Chuối'),
('Xoài'),
('Dưa hấu'),
('Nho'),
('Ổi'),
('Mận'),
('Dứa'),
('Bưởi');

Bước 3: Tạo mdoe Category

php artisan make:model Category

Sau đó làm theo các bước này

1. Tạo migration và model

Nếu bạn đã có model Product rồi thì bỏ qua bước này

php artisan make:model Product -m

database/migrations/xxxx_create_products_table.php

public function up(): void
{
   Schema::create('products', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->boolean('status')->default(1);
        $table->decimal('price', 10, 2);
        $table->string('image')->nullable();
        $table->unsignedBigInteger('category_id');
        $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
        $table->timestamps();
    });
}
php artisan migrate

app/Models/Product .php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    protected $fillable = ['name', 'status', 'price', 'image', 'category_id'];

    public function category()
    {
        return $this->belongsTo(Category::class);
    }
}

2. Tạo Controller

php artisan make:controller ProductController  --model=App\Models\Product

3. Khai báo Route

routes/web.php

use App\Http\Controllers\ProductController;

Route::resource('products', ProductController::class);

4. Nội dung file ProductController

app/Http/Controllers/ProductController.php

<?php

namespace App\Http\Controllers;

use App\Models\Product;
use App\Models\Category;
use Illuminate\Http\Request;

class ProductController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index()
    {
        $data = Product::with('category')->get();
        return view('products.index', compact('data'));
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
        $categories = Category::orderBy('name')->get();
        return view('products.create', compact('categories'));
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        // Validate dữ liệu
        $request->validate([
            'name' => 'required',
            'price' => 'required|numeric',
            'category_id' => 'required|exists:categories,id',
            'image' => 'nullable|image|max:2048'
        ]);

        $data = $request->all();

        // Xử lý upload ảnh
        if ($request->hasFile('image')) {
            $fileName = $request->file('image')->hashName();
            $request->file('image')->move(public_path('uploads/products'), $fileName);
            $data['image'] = $fileName;
        }

        Product::create($data);

        return redirect()->route('products.index')->with('success', 'Thêm sản phẩm thành công');
    }

    /**
     * Display the specified resource.
     */
    public function show(Product $product)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(Product $product)
    {
        $categories = Category::orderBy('name')->get();
        return view('products.edit', compact('product', 'categories'));

    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, Product $product)
    {
        // validate ữ liệu
        $request->validate([
            'name' => 'required',
            'price' => 'required|numeric',
            'category_id' => 'required|exists:categories,id',
            'image' => 'nullable|image|max:2048'
        ]);

        $data = $request->all();

        if ($request->hasFile('image')) {
            $fileName = $request->file('image')->hashName();
            $request->file('image')->move(public_path('uploads/products'), $fileName);
            $data['image'] = $fileName;
        }

        $product->update($data);

        return redirect()->route('products.index')->with('success', 'Cập nhật sản phẩm thành công');
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(Product $product)
    {
        $product->delete();
        return redirect()->route('products.index')->with('success', 'Xóa sản phẩm thành công');
    }
}

4. Tạo View

resources/views/products/index.blade.php

@extends('master.main')
@section('body')
<div class="container">
    <h1>Danh sách sản phẩm</h1>
    
    <table class="table table-bordered table-hover">
        <thead>
            <tr>
                <th>Id</th>
                <th>Name</th>
                <th>Category</th>
                <th>Price</th>
                <th>Created At</th>
                <th>Image</th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            @foreach($data as $model)
            <tr>
                <td>{{$model->id}}</td>
                <td>{{$model->name}}</td>
                <td>{{$model->category ? $model->category->name : ''}}</td>
                <td>{{$model->price}} đ</td>
                <td>{{$model->created_at}} đ</td>
                <td>
                    <img src="{{url('uploads/'.$model->image)}}" width="50">
                </td>
                <td>
                    
                    <form action="{{ route('products.destroy', $model->id)}}" method="POST" role="form">
                        @csrf @method('DELETE')

                        <a href="{{ route('products.edit', $model->id)}}" class="btn btn-primary">Sửa</a>
                        <button type="submit" class="btn btn-danger">Xóa</button>
                    </form>
                    
                </td>
            </tr>
            @endforeach
        </tbody>
    </table>
    
</div>
@stop()

resources/views/products/create.blade.php

@extends('layouts.app')

@section('content')
<div class="container">
    <h1>Thêm sản phẩm</h1>
                <div class="row">
            <div class="col-md-6">
                
            <form action="{{ route('products.store') }}" method="POST" enctype="multipart/form-data">
                @csrf @method('PUT')
                <div class="form-group">
                    <label>Tên:</label>
                    <input type="text" class="form-control" name="name" value="{{old('name')}}">
                    @error('name') {{$message}} @enderror
                </div>
                <div class="form-group">
                    <label>Giá:</label>
                    <input type="text"  class="form-control" name="price"  value="{{old('price')}}">
                    @error('price') {{$message}} @enderror
                </div>
                <div class="form-group">
                    <label>Trạng thái:</label>
                    <select name="status"  class="form-control">
                        <option value="1" @selected(old('status') == 1)>Hiển thị</option>
                        <option value="0"  @selected(old('status') == 0)>Ẩn</option>
                    </select>
                </div>
                <div class="form-group">
                    <label>Danh mục:</label>
                    <select name="category_id"  class="form-control">
                        @foreach($categories as $c)
                            <option value="{{ $c->id }}" @selected($c->id == old('category_id'))>{{ $c->name }}</option>
                        @endforeach
                    </select>
                    @error('category_id') {{$message}} @enderror
                </div>
                <div class="form-group">
                    <label>Ảnh:</label>
                    <input type="file" name="image">
                    @error('image') {{$message}} @enderror
                </div>
                <button type="submit">Lưu</button>
            </form>
                
            </div>
        </div>
    </div>
@endsection

<a href="{{ route('products.index') }}">Quay lại</a>

resources/views/products/edit.blade.php

@extends('master.main')
@section('body')
    <div class="container">
        
        <h1>Chỉnh sửa sản phẩm</h1>
        <div class="row">
            <div class="col-md-6">
                
            <form action="{{ route('products.update', $product->id) }}" method="POST" enctype="multipart/form-data">
                @csrf @method('PUT')
                <div class="form-group">
                    <label>Tên:</label>
                    <input type="text" class="form-control" name="name" value="{{$product->name}}">
                    @error('name') {{$message}} @enderror
                </div>
                <div class="form-group">
                    <label>Giá:</label>
                    <input type="text"  class="form-control" name="price"  value="{{$product->price}}">
                    @error('price') {{$message}} @enderror
                </div>
                <div class="form-group">
                    <label>Trạng thái:</label>
                    <select name="status"  class="form-control">
                        <option value="1" @selected($product->status == 1)>Hiển thị</option>
                        <option value="0"  @selected($product->status == 0)>Ẩn</option>
                    </select>
                </div>
                <div class="form-group">
                    <label>Danh mục:</label>
                    <select name="category_id"  class="form-control">
                        @foreach($categories as $c)
                            <option value="{{ $c->id }}" @selected($c->id == $product->category_id)>{{ $c->name }}</option>
                        @endforeach
                    </select>
                    @error('category_id') {{$message}} @enderror
                </div>
                <div class="form-group">
                    <label>Ảnh:</label>
                    <input type="file" name="image">
                    @error('image') {{$message}} @enderror
                </div>
                <button type="submit">Lưu</button>
            </form>
                
            </div>
        </div>
    </div>
    
@stop()

5. Chạy thử

php artisan serve

Mở: http://127.0.0.1:8000/products → Thêm, sửa, xóa sản phẩm.


📄 ĐỀ BÀI ÔN TẬP LARAVEL – CRUD BLOGS

Mục tiêu: Sinh viên thực hành tạo ứng dụng Laravel quản lý blog, áp dụng kiến thức về migration, model, controller, route, view, và form validation.


1. Yêu cầu cơ sở dữ liệu

Tạo bảng blogs với các trường sau:

Tên cột Kiểu dữ liệu Ghi chú
id BIGINT (PK, AI) Khóa chính, tự tăng
name VARCHAR(255) Tên blog
image DECIMAL(10,2) Giá blog
status BOOLEAN 1: Còn hàng, 0: Hết hàng
created_at TIMESTAMP Tự sinh bởi Laravel
updated_at TIMESTAMP Tự sinh bởi Laravel

2. Yêu cầu chức năng

Sinh viên phải thực hiện đầy đủ các chức năng sau:

  1. Xem danh sách blog

    • Hiển thị bảng gồm ID, tên, giá, trạng thái, ngày tạo, ngày cập nhật.
    • Có nút Thêm mớiSửa / Xóa từng blog.
  2. Thêm blog mới

    • Form nhập gồm: Tên, Giá, Trạng thái (dropdown chọn "Hiển thị hoặc "Tạm ẩn").

    • Có kiểm tra dữ liệu:

      • name: bắt buộc, tối đa 255 ký tự.
      • image: bắt buộc, định dạng ảnh: jpg. jpeg, png, gif, webmp
      • status: bắt buộc, chỉ nhận 0 hoặc 1.
    • Sau khi thêm thành công quay về danh sách và hiển thị thông báo.

  3. Sửa thông tin blog

    • Lấy dữ liệu từ DB đổ vào form để chỉnh sửa.
    • Có validate tương tự khi thêm mới.
    • Lưu cập nhật và quay về danh sách.
  4. Xóa blog

    • Xóa cứng (khỏi DB).
    • Có hộp thoại xác nhận trước khi xóa.

3. Kỹ thuật bắt buộc