"Module là nền tảng giúp chia nhỏ chương trình thành nhiều tệp, dễ quản lý, dễ tái sử dụng và dễ bảo trì. Hầu hết mọi ứng dụng Node.js đều được xây dựng từ các module."
Sau bài học này, bạn sẽ:
Hiểu Module là gì.
Biết tại sao phải chia chương trình thành nhiều file.
Hiểu CommonJS.
Hiểu ES Module.
Sử dụng require().
Sử dụng module.exports.
Sử dụng import.
Sử dụng export.
Hiểu vai trò của package.json.
Module là một file JavaScript chứa:
biến
hằng số
hàm
class
đối tượng
để có thể sử dụng lại ở nhiều nơi.
Ví dụ:
project
│
├── app.js
├── math.js
└── string.js
Thay vì viết toàn bộ chương trình trong một file, chúng ta chia thành nhiều module.
Ưu điểm:
dễ đọc
dễ bảo trì
dễ mở rộng
tái sử dụng
nhiều người cùng làm việc
Giả sử bạn viết toàn bộ chương trình trong một file:
app.js
Sau vài tháng:
3000 dòng
5000 dòng
10000 dòng
Việc tìm kiếm và sửa lỗi sẽ trở nên rất khó khăn.
Module giúp chia chương trình thành từng phần nhỏ.
Ví dụ:
controllers/
models/
routes/
services/
utils/
Đây cũng là cách tổ chức mà Express và NestJS sử dụng.
Trong nhiều năm, Node.js sử dụng hệ thống module mặc định là:
CommonJS
CommonJS sử dụng:
require()
module.exports
Đây vẫn là hệ thống rất phổ biến và bạn sẽ gặp trong nhiều dự án cũ.
Tạo file:
math.js
function sum(a, b) {
return a + b;
}
module.exports = sum;
Trong app.js
const sum = require("./math");
console.log(sum(10, 20));
Kết quả:
30
function sum(a, b) {
return a + b;
}
function sub(a, b) {
return a - b;
}
module.exports = {
sum,
sub
};
Import:
const math = require("./math");
console.log(math.sum(10, 5));
console.log(math.sub(10, 5));
Kết quả:
15
5
Có thể viết ngắn hơn:
const { sum, sub } = require("./math");
console.log(sum(5, 5));
console.log(sub(10, 3));
const PI = 3.14;
module.exports = PI;
Import:
const PI = require("./math");
console.log(PI);
module.exports = {
name: "Node.js",
version: "2026"
};
Import:
const app = require("./math");
console.log(app.name);
console.log(app.version);
JavaScript hiện đại đã có hệ thống module riêng.
Đó là:
ES Module
Sử dụng:
import
export
Đây là chuẩn chính thức của JavaScript và ngày càng được sử dụng rộng rãi trong các dự án mới.
Mở file:
package.json
Thêm:
{
"type": "module"
}
Từ bây giờ Node.js sẽ hiểu rằng project sử dụng ES Module.
Ví dụ:
export function sum(a, b) {
return a + b;
}
Import:
import { sum } from "./math.js";
console.log(sum(20, 30));
Kết quả:
50
export function sum(a, b) {
return a + b;
}
export function sub(a, b) {
return a - b;
}
Import:
import { sum, sub } from "./math.js";
console.log(sum(10, 2));
console.log(sub(10, 2));
export default function hello() {
console.log("Hello Node.js");
}
Import:
import hello from "./hello.js";
hello();
| CommonJS | ES Module |
|---|---|
| require() | import |
| module.exports | export |
| exports | export |
| Mặc định của Node.js cũ | Chuẩn JavaScript hiện đại |
| Phổ biến ở dự án cũ | Phổ biến ở dự án mới |
Mỗi project Node.js đều có:
package.json
Đây là "chứng minh thư" của project.
Nó chứa:
tên project
phiên bản
tác giả
dependencies
scripts
license
type
Ví dụ:
{
"name": "node-basic",
"version": "1.0.0",
"type": "module"
}
Chạy:
npm init
Hoặc nhanh hơn:
npm init -y
Node.js sẽ tự sinh:
package.json
Ví dụ:
node-basic
│
├── package.json
├── app.js
├── math.js
├── string.js
└── utils.js
Đây là cách tổ chức cơ bản của hầu hết các dự án Node.js.
Nên dùng khi:
bảo trì dự án cũ
làm việc với package chưa hỗ trợ ES Module
cần tương thích với mã nguồn cũ
Đối với các dự án mới, nên ưu tiên ES Module vì:
là chuẩn chính thức của JavaScript
cú pháp hiện đại
đồng nhất với trình duyệt
được các framework mới như Express 5, Vite và Next.js hỗ trợ tốt
Trong khóa học này, chúng ta sẽ ưu tiên sử dụng ES Module, đồng thời vẫn tìm hiểu CommonJS để có thể đọc và bảo trì các dự án cũ.
"type": "module"Ví dụ:
import { sum } from "./math.js";
Sẽ báo lỗi nếu project vẫn đang dùng CommonJS.
.jsSai:
import { sum } from "./math";
Đúng:
import { sum } from "./math.js";
import { sum } from "./utils/math.js";
Hãy kiểm tra lại vị trí file và đường dẫn tương đối.
Không nên viết:
const fs = require("fs");
import { sum } from "./math.js";
Hãy thống nhất sử dụng một hệ thống module trong cùng một project.
Qua bài học này, bạn đã biết:
✅ Module giúp chia chương trình thành nhiều file nhỏ.
✅ Hiểu cách sử dụng require() và module.exports trong CommonJS.
✅ Hiểu cách sử dụng import và export trong ES Module.
✅ Biết vai trò của package.json.
✅ Biết khi nào nên dùng CommonJS và khi nào nên dùng ES Module.
Module là nền tảng quan trọng của Node.js. Từ bài học này trở đi, hầu hết các chương trình trong khóa học sẽ được tổ chức thành nhiều module thay vì chỉ một file duy nhất.
Tạo file math.js chứa hàm:
export function sum(a, b) {
return a + b;
}
Import vào app.js và hiển thị kết quả của:
sum(10, 20)
Thêm hai hàm:
sub()
mul()
Import cả ba hàm và tính:
20 + 5
20 - 5
20 × 5
Tạo hello.js sử dụng Default Export để in:
Hello Node.js!
Sau đó import và gọi hàm trong app.js.
Khởi tạo một project mới bằng:
npm init -y
Mở package.json và giải thích ý nghĩa của các trường:
name
version
type
Tạo project với cấu trúc:
node-basic
│
├── app.js
├── package.json
└── utils
├── math.js
└── string.js
Trong đó:
math.js chứa các hàm tính toán (sum, sub).
string.js chứa hàm chuyển chuỗi thành chữ in hoa (toUpperCase).
Import các module vào app.js và kiểm tra kết quả.
📖 Bài tiếp theo: Bài 05 — npm: package.json, package-lock.json, dependencies, devDependencies và scripts.
x0
quay về MỤC LỤC
Cập nhật: 2026-07-20T07:59:00.193+07:00
"Mọi lập trình viên Node.js đều bắt đầu từ một dòng lệnh đơn giản:
node app.js. Từ đó, bạn sẽ khám phá cách chương trình giao tiếp với hệ điều hành và người dùng thông quaconsole,process,argvvàreadline."
Sau bài học này, bạn sẽ:
Biết cách tạo chương trình Node.js đầu tiên.
Chạy file JavaScript bằng lệnh node.
Sử dụng console để hiển thị thông tin.
Hiểu đối tượng process.
Đọc tham số dòng lệnh bằng process.argv.
Nhập dữ liệu từ bàn phím bằng readline.
Tạo thư mục mới:
node-basic
Mở thư mục bằng VS Code.
Tạo file:
app.js
Cấu trúc thư mục:
node-basic
│
└── app.js
Mở file app.js:
console.log("Hello Node.js!");
Lưu lại.
Mở Terminal:
node app.js
Kết quả:
Hello Node.js!
Xin chúc mừng!
Bạn vừa chạy thành công chương trình Node.js đầu tiên.
Chú ý: nhớ cd vào thư mục node-basic
nodeNode.js thực thi file JavaScript bằng lệnh:
node tên_file.js
Ví dụ:
node app.js
hoặc
node hello.js
Node sẽ:
Đọc file.
Biên dịch JavaScript bằng V8 Engine.
Thực thi chương trình.
Hiển thị kết quả.
console là đối tượng dùng để hiển thị thông tin ra Terminal.
Ví dụ:
console.log("Xin chào!");
console.log(100);
console.log(true);
Kết quả:
Xin chào!
100
true
Đây là hàm được sử dụng nhiều nhất.
const name = "An";
console.log(name);
Kết quả:
An
const name = "An";
const age = 20;
console.log(name, age);
Kết quả:
An 20
const name = "An";
const age = 20;
console.log(`Tên: ${name}`);
console.log(`Tuổi: ${age}`);
Kết quả:
Tên: An
Tuổi: 20
Chú ý: dấu huyền backtick chứ k phải nháy đơn
Node.js cung cấp đối tượng toàn cục:
process
Đây là cầu nối giữa chương trình Node.js và hệ điều hành.
Thông qua process, chúng ta có thể:
biết hệ điều hành
biết thư mục hiện tại
đọc biến môi trường
lấy tham số dòng lệnh
kết thúc chương trình
Hiển thị phiên bản Node.js.
console.log(process.version);
Ví dụ:
v24.3.0
Hiển thị hệ điều hành.
console.log(process.platform);
Ví dụ:
Windows
win32
Linux
linux
macOS
darwin
Thư mục hiện tại.
console.log(process.cwd());
Ví dụ:
D:\Projects\node-basic
Kết thúc chương trình.
console.log("Bắt đầu");
process.exit();
console.log("Dòng này sẽ không chạy");
Kết quả:
Bắt đầu
Đây là một trong những tính năng thú vị của Node.js.
argv là mảng chứa các tham số truyền vào từ Terminal.
Ví dụ:
node app.js Hello NodeJS
Trong chương trình:
console.log(process.argv);
Ví dụ kết quả:
[
'C:\\Program Files\\nodejs\\node.exe',
'D:\\node-basic\\app.js',
'Hello',
'NodeJS'
]
console.log(process.argv[2]);
Chạy:
node app.js ChatGPT
Kết quả:
ChatGPT
const name = process.argv[2];
console.log(`Xin chào ${name}!`);
Chạy:
node app.js Minh
Kết quả:
Xin chào Minh!
Nếu argv nhận dữ liệu ngay khi chạy chương trình thì readline cho phép nhập dữ liệu trong lúc chương trình đang chạy.
Đầu tiên import module:
const readline = require("readline");
Tạo đối tượng:
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question("Tên của bạn là gì? ", (name) => {
console.log(`Xin chào ${name}!`);
rl.close();
});
Kết quả:
Tên của bạn là gì?
An
Xin chào An!
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question("Số thứ nhất: ", (a) => {
rl.question("Số thứ hai: ", (b) => {
console.log(Number(a) + Number(b));
rl.close();
});
});
Kết quả:
Số thứ nhất: 10
Số thứ hai: 20
30
| process.argv | readline |
|---|---|
| Nhập dữ liệu khi chạy lệnh | Nhập dữ liệu trong lúc chương trình chạy |
| Thường dùng cho script | Thường dùng cho chương trình tương tác |
| Đọc nhanh | Linh hoạt hơn |
Hello Node.js không thay đổi
Do chưa lưu file.
node ap.js
Kết quả:
Cannot find module
Hãy kiểm tra đúng tên file.
Đang ở thư mục khác:
node app.js
Sẽ báo lỗi.
Kiểm tra bằng:
pwd
hoặc trên Windows:
cd
rl.close()Nếu quên:
rl.close();
Chương trình sẽ tiếp tục chờ nhập dữ liệu và không tự kết thúc.
Qua bài học này, bạn đã biết:
✅ Tạo và chạy chương trình Node.js đầu tiên.
✅ Sử dụng lệnh node app.js.
✅ Hiểu cách dùng console.log() để hiển thị thông tin.
✅ Làm quen với đối tượng process và một số thuộc tính quan trọng như version, platform, cwd() và exit().
✅ Đọc tham số dòng lệnh bằng process.argv.
✅ Nhập dữ liệu từ bàn phím với readline.
Đây là những công cụ cơ bản nhưng sẽ xuất hiện thường xuyên trong suốt quá trình học Node.js.
Tạo file hello.js và hiển thị:
Xin chào Node.js!
Chạy chương trình bằng Terminal.
Viết chương trình hiển thị:
Phiên bản Node.js.
Hệ điều hành.
Thư mục hiện tại.
Gợi ý:
process.version
process.platform
process.cwd()
Viết chương trình nhận tên từ dòng lệnh và hiển thị:
Xin chào <tên>!
Ví dụ:
node app.js Lan
Kết quả:
Xin chào Lan!
Sử dụng readline để nhập:
Họ tên
Tuổi
Sau đó hiển thị:
Xin chào Nguyễn Văn A!
Bạn 20 tuổi.
Viết chương trình nhập hai số bằng readline và hiển thị:
Tổng
Hiệu
Tích
Thương
Ví dụ:
Số thứ nhất: 12
Số thứ hai: 4
Tổng: 16
Hiệu: 8
Tích: 48
Thương: 3
📖 Bài tiếp theo: Bài 04 — Module trong Node.js: CommonJS, ES Module, export, import và package.json.
x1
quay về MỤC LỤC
Cập nhật: 2026-07-19T11:25:51.800+07:00
"Một môi trường phát triển được cài đặt đúng ngay từ đầu sẽ giúp bạn tập trung vào việc học và xây dựng ứng dụng, thay vì mất thời gian xử lý các lỗi cấu hình."
Sau bài học này bạn sẽ:
Hiểu Node.js LTS là gì.
Biết sự khác nhau giữa LTS và Current.
Cài đặt Node.js thành công.
Hiểu npm và npx.
Cài đặt Visual Studio Code.
Làm quen với Terminal.
Kiểm tra môi trường phát triển đã sẵn sàng.
Node.js luôn có hai nhánh phát hành chính:
LTS (Long Term Support)
Current
Đây là phiên bản ổn định, được hỗ trợ lâu dài.
Phù hợp cho:
học tập
dự án thực tế
doanh nghiệp
production
Ưu điểm:
ổn định
ít lỗi
tương thích nhiều thư viện
được cập nhật bản vá bảo mật
Trong toàn bộ khóa học này, chúng ta sẽ sử dụng Node.js LTS (2026).
Đây là phiên bản mới nhất.
Có:
tính năng mới
API mới
hiệu năng mới
Tuy nhiên:
chưa ổn định bằng LTS
một số package có thể chưa hỗ trợ
Nếu mới học Node.js, không nên sử dụng Current.
Truy cập trang chủ:
Bạn sẽ thấy hai nút:
Node.js LTS ✅
Node.js Current
Hãy tải Node.js LTS.
Windows
Chạy file:
node-vxx.x.x-x64.msi
Sau đó:
Next
↓
Next
↓
Install
↓
Finish
Không cần thay đổi thiết lập mặc định.
macOS
Có thể:
tải trực tiếp từ website
hoặc dùng Homebrew
Ví dụ:
brew install node
Linux
Ubuntu
sudo apt update
sudo apt install nodejs npm
Hoặc cài bằng Node Version Manager (nvm) để dễ quản lý nhiều phiên bản.
Mở Terminal.
Gõ:
node -v
Ví dụ:
v24.x.x
Tiếp theo:
npm -v
Ví dụ:
11.x.x
Nếu xuất hiện số phiên bản nghĩa là cài đặt thành công.
Rất nhiều người mới học nhầm hai khái niệm này.
Là JavaScript Runtime.
Ví dụ:
node app.js
Node sẽ chạy file JavaScript.
npm là Node Package Manager.
Nó dùng để:
cài thư viện
cập nhật thư viện
gỡ thư viện
quản lý project
Ví dụ:
npm install express
npm sẽ tải Express về project.
Package có thể hiểu là:
Một thư viện hoặc công cụ được cộng đồng Node.js phát triển và chia sẻ.
Ví dụ:
Express
Prisma
Jest
Socket.IO
Multer
dotenv
Thay vì tự viết mọi thứ từ đầu, chúng ta chỉ cần cài package phù hợp.
Ngoài npm còn có:
npx
Rất nhiều người mới học thường nhầm giữa hai lệnh này.
Dùng để cài đặt package.
Ví dụ:
npm install express
Dùng để chạy package mà không cần cài đặt toàn cục.
Ví dụ:
npx create-next-app
hoặc:
npx prisma init
npx sẽ tải công cụ cần thiết (nếu chưa có) và chạy ngay.
Điều này giúp máy tính luôn gọn gàng và tránh cài đặt quá nhiều package toàn cục.
Visual Studio Code (VS Code) là trình soạn thảo mã nguồn phổ biến nhất cho Node.js.
Ưu điểm:
miễn phí
nhẹ
nhiều tiện ích mở rộng
hỗ trợ Git
tích hợp Terminal
IntelliSense
Debug
Đây sẽ là trình soạn thảo được sử dụng xuyên suốt khóa học.
Sau khi cài VS Code, bạn nên cài thêm:
ESLint — Kiểm tra lỗi cú pháp và các quy tắc viết mã JavaScript, giúp phát hiện lỗi sớm khi lập trình.
Prettier - Code formatter — Tự động định dạng (format) mã nguồn theo một chuẩn thống nhất, giúp code dễ đọc và nhất quán.
Error Lens — Hiển thị lỗi và cảnh báo trực tiếp ngay trên dòng mã trong VS Code, không cần di chuột để xem.
GitLens — Mở rộng khả năng làm việc với Git, cho biết ai sửa dòng code gần nhất, lịch sử commit và so sánh thay đổi.
Material Icon Theme — Thay đổi biểu tượng (icon) của file và thư mục trong VS Code, giúp nhận biết loại file nhanh hơn.
Docker (sẽ cài ở phần Docker của khóa học) — Hỗ trợ tạo, quản lý và chạy container Docker ngay trong VS Code, thuận tiện khi triển khai ứng dụng.
💡 Lời khuyên cho người mới học: Chỉ cần cài ESLint, Prettier, Error Lens và Material Icon Theme là đủ để bắt đầu. GitLens sẽ hữu ích khi học Git, còn Docker hãy cài khi đến Phần 15 — Triển khai để tránh làm môi trường phát triển trở nên phức tạp quá sớm.
Terminal là nơi chúng ta giao tiếp với hệ điều hành bằng dòng lệnh.
Trong khóa học, gần như mọi thao tác đều sử dụng Terminal.
Ví dụ:
Khởi tạo project:
npm init
Cài package:
npm install express
Chạy chương trình:
node app.js
Chạy script:
npm run dev
Có nhiều cách:
Menu
Terminal
↓
New Terminal
Hoặc phím tắt:
Windows/Linux
Ctrl + `
macOS
Control + `
Terminal sẽ xuất hiện ở phía dưới VS Code.
Hãy chạy lần lượt các lệnh sau:
node -v
npm -v
npx -v
Nếu cả ba đều hiển thị phiên bản, môi trường của bạn đã sẵn sàng để học Node.js.
nodeVí dụ:
'node' is not recognized as an internal or external command
Nguyên nhân:
Node.js chưa được cài đặt.
Chưa thêm vào biến môi trường (PATH).
Cần mở lại Terminal sau khi cài đặt.
npmVí dụ:
'npm' is not recognized...
Thường xảy ra khi:
cài đặt Node.js chưa hoàn tất
PATH bị lỗi
Hãy cài đặt lại Node.js LTS và khởi động lại Terminal.
Nếu máy đã cài nhiều phiên bản Node.js, bạn có thể gặp lỗi không đúng phiên bản mong muốn.
Giải pháp phổ biến là sử dụng nvm (Node Version Manager) để quản lý nhiều phiên bản Node.js trên cùng một máy.
Qua bài học này, bạn đã biết:
✅ Node.js LTS là phiên bản ổn định, phù hợp cho học tập và phát triển ứng dụng.
✅ Biết cách cài đặt Node.js trên Windows, macOS và Linux.
✅ Hiểu sự khác nhau giữa Node.js, npm và npx.
✅ Cài đặt Visual Studio Code và làm quen với Terminal.
✅ Kiểm tra môi trường phát triển bằng các lệnh node -v, npm -v và npx -v.
Đến đây, máy tính của bạn đã sẵn sàng để bắt đầu viết những chương trình Node.js đầu tiên.
Cài đặt Node.js LTS trên máy tính của bạn và kiểm tra bằng các lệnh:
node -v
npm -v
npx -v
Ghi lại kết quả hiển thị.
Giải thích ngắn gọn sự khác nhau giữa:
Node.js
npm
npx
Cho biết sự khác nhau giữa Node.js LTS và Node.js Current. Theo bạn, người mới học nên sử dụng phiên bản nào? Vì sao?
Mở Terminal trong VS Code và thực hiện các lệnh sau:
node -v
npm -v
npx -v
Chụp màn hình hoặc ghi lại kết quả để xác nhận môi trường phát triển của bạn đã được cài đặt thành công.
📖 Bài tiếp theo: Bài 03 — Chương trình Node.js đầu tiên: node app.js, console, process, argv và readline.
Errors log:
VSCode k suggest các objects của NodeJS.
Điều này bình thường. ESLint không có chức năng gợi ý (IntelliSense) cho process hay các API của Node.js.
Nguyên nhân thường là VS Code chưa biết project của bạn là môi trường Node.js.
Hãy kiểm tra từng bước:
app.js?Nên mở:
File
└── Open Folder...
Ví dụ:
node-basic/
├── app.js
└── package.json
Không nên chỉ mở riêng app.js.
package.json chưa?Nếu chưa:
npm init -y
Trong Terminal:
npm install -D @types/node
Mặc dù bạn viết JavaScript, package này giúp VS Code hiểu các API của Node.js (process, Buffer, setTimeout,...).
Góc dưới bên phải VS Code phải là:
JavaScript
hoặc
TypeScript
Không phải:
Plain Text
process.
Sau dấu . có hiện:
argv
cwd
env
exit
platform
version
không?
restart lại VSCode sau khi chạy xong 02 lệnh mục 2 và 3 ở trên.x1
quay về MỤC LỤC
Cập nhật: 2026-07-19T11:25:40.858+07:00
Mình sẽ thiết kế theo cùng triết lý: từ nền tảng → thực chiến → triển khai, cập nhật theo hệ sinh thái Node.js năm 2026 (Node.js LTS, Express 5, TypeScript, Prisma, Docker...).
Lộ trình này cũng phù hợp để tiếp nối sau khóa JavaScript ES2026 hoặc dành cho người đã biết PHP/Laravel muốn chuyển sang Node.js.
Nếu cập nhật theo Node.js LTS (2026) thì mình sẽ chia thành các phần như sau để người học đi từ JavaScript → Node.js → Xây dựng REST API → Triển khai dự án thực tế.
Tiếp nối khóa "JavaScript ES2026 — Tự học JavaScript từ ZERO đến Web Developer"
JavaScript Runtime
V8 Engine
Event Loop
Non-blocking I/O
Khi nào nên dùng Node.js?
Node.js LTS
npm
npx
VS Code
Terminal
node app.js
console
process
argv
readline
CommonJS
ES Module
export
import
package.json
package.json
package-lock.json
dependencies
devDependencies
scripts
Authentication (JWT)
Users
Products
Categories
Orders
Upload Images
Pagination
Search
Filter
Role Admin/User
Redis Cache
Docker
Deploy VPS
✅ Thành thạo Node.js LTS
✅ Hiểu Event Loop và Asynchronous Programming
✅ Xây dựng REST API chuyên nghiệp
✅ Làm việc với MongoDB và PostgreSQL
✅ Thành thạo Express.js
✅ Xác thực bằng JWT
✅ Upload và quản lý file
✅ Viết Unit Test và Integration Test
✅ Triển khai ứng dụng bằng Docker và PM2
✅ Đủ nền tảng để học tiếp:
NestJS
Fastify
GraphQL
Microservices
RabbitMQ
Kafka
gRPC
Kubernetes
CI/CD
AWS
Azure
Google Cloud
70 bài học từ cơ bản đến nâng cao.
Bám sát hệ sinh thái Node.js hiện đại năm 2026.
Đi từ Node.js Core → Express → Database → REST API → Authentication → Docker → Deploy.
Có dự án cuối khóa đủ quy mô để đưa vào portfolio hoặc làm nền tảng phát triển các ứng dụng thực tế.
Sau khi hoàn thành, người học có thể tự tin phát triển các backend hiện đại hoặc tiếp tục học NestJS để xây dựng các hệ thống lớn theo kiến trúc doanh nghiệp.
Cập nhật: 2026-07-19T10:07:03.670+07:00
Dưới đây là Bài 01 theo đúng phong cách của series Laravel 12 (2026): giải thích dễ hiểu, nhiều ví dụ thực tế, bám sát Node.js LTS năm 2026 và hướng đến mục tiêu xây dựng REST API.
"JavaScript không còn chỉ chạy trong trình duyệt. Với Node.js, JavaScript có thể xây dựng cả những hệ thống backend hiện đại phục vụ hàng triệu người dùng."
Sau bài học này bạn sẽ hiểu được:
Node.js là gì?
JavaScript Runtime là gì?
V8 Engine hoạt động như thế nào?
Event Loop là gì?
Non-blocking I/O là gì?
Khi nào nên dùng Node.js?
Khi nào không nên dùng Node.js?
Trong nhiều năm, JavaScript chỉ chạy bên trong trình duyệt.
Ví dụ:
alert("Hello World");
hoặc
document.getElementById("title");
Các đoạn mã trên chỉ hoạt động khi có trình duyệt như:
Chrome
Firefox
Edge
Safari
JavaScript lúc này chủ yếu dùng để:
xử lý giao diện
tạo hiệu ứng
kiểm tra dữ liệu nhập
tương tác với người dùng
Nó không thể:
đọc file trên máy chủ
kết nối cơ sở dữ liệu
tạo Web Server
xây dựng REST API
Backend khi đó thường được viết bằng:
PHP
Java
C#
Python
Ruby
Năm 2009, Ryan Dahl giới thiệu Node.js.
Ý tưởng rất đơn giản:
Tại sao JavaScript chỉ được chạy trong trình duyệt?
Nếu JavaScript có thể chạy trực tiếp trên hệ điều hành thì sao?
Đó chính là Node.js.
Node.js là một JavaScript Runtime cho phép chạy JavaScript bên ngoài trình duyệt.
Ví dụ:
console.log("Hello Node.js");
Lưu vào file:
app.js
Chạy:
node app.js
Kết quả:
Hello Node.js
Không cần Chrome.
Không cần Firefox.
Không cần HTML.
Chỉ cần Node.js.
Runtime là môi trường thực thi chương trình.
Ví dụ:
PHP cần:
PHP Runtime
Java cần:
JVM
Python cần:
Python Interpreter
JavaScript trong trình duyệt cần:
Chrome Runtime
JavaScript trên máy chủ cần:
Node.js Runtime
Node.js bổ sung rất nhiều khả năng mà trình duyệt không có.
Ví dụ:
đọc file
ghi file
tạo server
kết nối database
tạo REST API
chạy script tự động
Đây là điều rất nhiều người mới học hiểu nhầm.
Node.js không phải một ngôn ngữ lập trình.
Bạn vẫn viết:
const age = 20;
không phải:
NodeScript
hay
Node Language
Node.js chỉ là môi trường chạy JavaScript.
Node.js sử dụng V8 Engine.
Đây cũng chính là engine đang chạy bên trong trình duyệt Google Chrome.
Quy trình hoạt động:
JavaScript
│
▼
V8 Engine
│
▼
Machine Code
│
▼
CPU
Nhờ V8, JavaScript được biên dịch và tối ưu rất nhanh, thay vì chỉ được thông dịch từng dòng.
Ưu điểm:
tốc độ cao
tối ưu bộ nhớ
hiệu năng tốt
được Google phát triển liên tục
Trình duyệt chỉ cung cấp:
document
window
localStorage
Node.js cung cấp thêm rất nhiều API hệ thống:
fs
path
http
https
os
crypto
stream
process
Ví dụ đọc file:
const fs = require("fs");
const data = fs.readFileSync("hello.txt", "utf8");
console.log(data);
Điều này trình duyệt không thể làm vì lý do bảo mật.
Một trong những điểm đặc biệt nhất của Node.js là Event Loop.
Thay vì tạo nhiều luồng xử lý cho mỗi yêu cầu, Node.js sử dụng:
một luồng JavaScript chính
Event Loop
các API bất đồng bộ của hệ điều hành
Mô hình đơn giản:
Request
│
▼
Event Loop
│
▼
Async Operation
│
▼
Callback
Nhờ vậy Node.js có thể xử lý hàng nghìn kết nối đồng thời mà không cần tạo hàng nghìn luồng.
Đây là nền tảng cho hiệu năng cao của Node.js trong các ứng dụng mạng.
Đây là khái niệm quan trọng nhất của Node.js.
Giả sử đọc một file rất lớn.
Nếu chương trình phải chờ đọc xong mới làm việc tiếp thì gọi là:
Blocking I/O
Ví dụ:
Đọc file...
(chờ)
(chờ)
(chờ)
Đọc xong
Trong thời gian chờ, chương trình không thể xử lý công việc khác.
Ngược lại, với Node.js:
Đọc file
↓
Tiếp tục xử lý yêu cầu khác
↓
File đọc xong
↓
Thông báo kết quả
Đó gọi là:
Non-blocking I/O
Chính cơ chế này giúp Node.js rất mạnh trong các ứng dụng có nhiều kết nối đồng thời.
Node.js đặc biệt phù hợp với:
REST API
Backend Web
Chat Realtime
WebSocket
Dashboard
Streaming
Proxy Server
Microservices
API Gateway
IoT
Serverless Functions
Ví dụ:
Hệ thống bán hàng
Quản lý nhân sự
CRM
ERP
Mạng xã hội
Hệ thống chat
Ứng dụng học trực tuyến
Không phải dự án nào cũng phù hợp.
Ví dụ các tác vụ tính toán nặng như:
xử lý ảnh hàng loạt
dựng video
AI Training
mô phỏng vật lý
tính toán khoa học
Nếu một tác vụ chiếm CPU trong thời gian dài, luồng JavaScript chính sẽ bị bận, làm giảm khả năng phản hồi của ứng dụng.
Trong những trường hợp này, thường sẽ kết hợp Node.js với các tiến trình riêng, Worker Threads hoặc sử dụng các ngôn ngữ phù hợp hơn cho phần tính toán.
Ngày nay Node.js là nền tảng của rất nhiều công nghệ phổ biến:
Express.js
Fastify
NestJS
Prisma ORM
TypeScript
Next.js
Vite
Electron
Trong khóa học này, chúng ta sẽ tập trung vào việc xây dựng backend hiện đại với:
Node.js LTS
Express 5
Prisma ORM
PostgreSQL
MongoDB
JWT Authentication
Docker
PM2
Nginx
Đây cũng là nền tảng để học tiếp các kiến trúc nâng cao như Microservices, GraphQL và triển khai ứng dụng lên môi trường Production.
Qua bài học này, bạn đã biết:
✅ Node.js là JavaScript Runtime chạy ngoài trình duyệt.
✅ Node.js sử dụng V8 Engine để thực thi JavaScript với hiệu năng cao.
✅ Event Loop và Non-blocking I/O là hai nền tảng quan trọng giúp Node.js xử lý nhiều kết nối đồng thời.
✅ Node.js rất phù hợp để xây dựng REST API, backend web và các ứng dụng realtime.
✅ Đây là nền tảng của nhiều framework hiện đại như Express, NestJS và Fastify.
Bài 1
Tìm hiểu lịch sử ra đời của Node.js và cho biết vì sao nó đã thay đổi cách xây dựng ứng dụng web phía máy chủ.
Năm 2009, Ryan Dahl giới thiệu Node.js.
Ý tưởng rất đơn giản:
Tại sao JavaScript chỉ được chạy trong trình duyệt?
Nếu JavaScript có thể chạy trực tiếp trên hệ điều hành thì sao?
Đó chính là Node.js.
Node.js sử dụng một luồng JavaScript chính (single-threaded) kết hợp với Event Loop và các API bất đồng bộ để xử lý rất nhiều kết nối cùng lúc.
Bài 2
Phân biệt JavaScript chạy trong trình duyệt và JavaScript chạy bằng Node.js.
JavaScript chạy trong trình duyệt chủ yếu dùng để:
xử lý giao diện
tạo hiệu ứng
kiểm tra dữ liệu nhập
tương tác với người dùng
NodeJS:
đọc file trên máy chủ
kết nối cơ sở dữ liệu
tạo Web Server
xây dựng REST API
| JavaScript Browser | Node.js |
|---|---|
| DOM | Không có DOM |
| window | Không có window |
| document | Không có document |
| alert() | Không có |
| fs | Có |
| http | Có |
| process | Có |
Bài 3
Giải thích bằng lời của bạn:
JavaScript Runtime là gì?
JavaScript Runtime là môi trường để thực thi mã JavaScript.
Ví dụ: Chrome Runtime hoặc Node.js Runtime.
V8 Engine là gì?
V8 là engine của Google dùng để biên dịch JavaScript thành mã máy giúp chạy nhanh hơn.
Event Loop là gì?
1. JavaScript chạy trên một luồng chính.
2. Các tác vụ I/O được thực hiện bất đồng bộ với sự hỗ trợ của hệ điều hành và libuv.
3. Event Loop điều phối khi nào các callback hoặc promise tiếp tục được thực thi.
Non-blocking I/O là gì?
Không phải chờ thao tác I/O hoàn thành mới tiếp tục chạy chương trình; trong lúc chờ, Node.js có thể xử lý các công việc khác.
Bài 4
Hãy liệt kê ít nhất 5 loại ứng dụng mà theo bạn Node.js là một lựa chọn phù hợp, và giải thích ngắn gọn lý do.
📖 Bài tiếp theo: Bài 02 — Cài đặt Node.js LTS (2026): Node.js, npm, npx, VS Code và Terminal.
x1quay về MỤC LỤC
Cập nhật: 2026-07-19T10:11:05.230+07:00
Sau khi đã biết cách truy vấn dữ liệu bằng Eloquent và Query Builder, bước tiếp theo là tìm hiểu Relationship (mối quan hệ) giữa các Model.
Trong thực tế, dữ liệu hiếm khi tồn tại độc lập.
Một người dùng có thể có hồ sơ cá nhân, một bài viết thuộc về một danh mục, một sản phẩm có nhiều hình ảnh...
Việc liên kết các bảng với nhau giúp cơ sở dữ liệu trở nên khoa học và tránh trùng lặp dữ liệu.
Trong bài này, chúng ta sẽ tìm hiểu mối quan hệ đơn giản nhất: One To One.
Relationship là cách Laravel mô tả mối quan hệ giữa các Model.
Ví dụ:
Một User có một Profile.
Một Passport thuộc về một Person.
Một Student có một Student Card.
Đây đều là các mối quan hệ một - một (One To One).
Ta có hai bảng:
users
| id | name |
|---|---|
| 1 | Nguyễn Văn A |
| 2 | Trần Văn B |
profiles
| id | user_id | phone | address |
|---|---|---|---|
| 1 | 1 | 0901234567 | Hà Nội |
| 2 | 2 | 0912345678 | Đà Nẵng |
Mỗi User chỉ có một Profile và mỗi Profile chỉ thuộc về một User.
Tạo bảng Profile:
php artisan make:migration create_profiles_table
Migration:
Schema::create('profiles', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')
->constrained()
->cascadeOnDelete();
$table->string('phone');
$table->string('address');
$table->timestamps();
});
Sau đó chạy:
php artisan migrate
php artisan make:model Profile
Laravel sẽ tạo:
app/
└── Models/
├── User.php
└── Profile.php
Trong model User:
class User extends Authenticatable
{
public function profile()
{
return $this->hasOne(Profile::class);
}
}
Ý nghĩa:
Một User có một Profile.
Laravel sẽ mặc định tìm khóa ngoại user_id.
Trong model Profile:
class Profile extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
}
Ý nghĩa:
Profile thuộc về một User.
Lấy Profile của User:
$user = User::find(1);
echo $user->profile->phone;
Hoặc:
echo $user->profile->address;
Laravel sẽ tự động truy vấn bảng profiles.
Ngược lại:
$profile = Profile::find(1);
echo $profile->user->name;
Laravel sẽ truy vấn bảng users.
Có thể tạo Profile thông qua User.
$user = User::find(1);
$user->profile()->create([
'phone' => '0901234567',
'address' => 'Hồ Chí Minh'
]);
Laravel sẽ tự động gán:
user_id = 1
Bạn không cần tự điền khóa ngoại.
Nếu hiển thị danh sách nhiều User kèm Profile, không nên để Laravel truy vấn từng Profile riêng lẻ.
Sử dụng:
$users = User::with('profile')->get();
Laravel sẽ lấy toàn bộ dữ liệu chỉ với số lượng truy vấn tối thiểu, giúp ứng dụng hoạt động nhanh hơn.
Không phải User nào cũng đã có Profile.
Ví dụ:
echo $user->profile->phone;
Nếu Profile chưa tồn tại sẽ phát sinh lỗi.
Có thể dùng toán tử null-safe của PHP:
echo $user->profile?->phone;
Hoặc:
optional($user->profile)->phone;
Trong bài này chúng ta đã học:
Relationship là gì.
Quan hệ One To One.
hasOne().
belongsTo().
Truy cập dữ liệu qua Relationship.
Tạo dữ liệu liên kết.
with() để tối ưu truy vấn.
Truy cập an toàn khi quan hệ chưa tồn tại.
One To One là nền tảng để hiểu các mối quan hệ phức tạp hơn trong Eloquent ORM.
Tạo bảng profiles có các trường phone và address.
Khai báo quan hệ hasOne() trong model User.
Khai báo quan hệ belongsTo() trong model Profile.
Hiển thị số điện thoại của User có id = 1.
Hiển thị tên User từ một Profile.
Sử dụng with('profile') để lấy danh sách User cùng thông tin Profile.
Ở bài tiếp theo, chúng ta sẽ tìm hiểu One To Many, mối quan hệ phổ biến nhất trong Laravel, chẳng hạn như một User có nhiều Post hoặc một Category có nhiều Post.
Đây là bài mở đầu phần Relationship, nên chỉ giới thiệu những khái niệm cốt lõi và các phương thức hasOne() và belongsTo().
Các nội dung như khóa ngoại tùy chỉnh, eager loading nâng cao hay polymorphic sẽ được trình bày ở các bài sau khi người học đã nắm vững nền tảng.
x1
Cập nhật: 2026-07-19T21:12:10.782+07:00
Sau khi đã làm quen với Eloquent Model và các thao tác CRUD cơ bản, chúng ta sẽ học cách truy vấn dữ liệu bằng Query Builder.
Query Builder cung cấp một cú pháp trực quan, dễ đọc và an toàn, giúp xây dựng các câu lệnh SQL mà không cần viết SQL thủ công.
Laravel sẽ tự động chuyển đổi các phương thức thành câu lệnh SQL tương ứng.
Query Builder là một thành phần của Laravel dùng để thao tác với cơ sở dữ liệu thông qua các phương thức PHP.
Ví dụ thay vì viết SQL:
SELECT * FROM posts WHERE id = 1;
Ta có thể viết:
Post::where('id', 1)->get();
hoặc
DB::table('posts')
->where('id', 1)
->get();
Hai cách trên đều tạo ra câu lệnh SQL tương tự.
Điều kiện đơn giản nhất là where().
Lấy tất cả bài viết có id bằng 5:
$posts = Post::where('id', 5)->get();
Hoặc tìm theo tiêu đề:
$posts = Post::where('title', 'Laravel 12')->get();
Có thể sử dụng các toán tử so sánh:
$posts = Post::where('id', '>', 10)->get();
Một số toán tử thường dùng:
=
>
<
>=
<=
!=
<>
Có thể kết hợp nhiều where().
$posts = Post::where('status', 1)
->where('views', '>', 100)
->get();
Laravel sẽ tạo SQL tương đương:
WHERE status = 1
AND views > 100
Nếu muốn sử dụng điều kiện OR:
$posts = Post::where('category_id', 1)
->orWhere('category_id', 2)
->get();
SQL tương đương:
WHERE category_id = 1
OR category_id = 2
Có thể kết hợp nhiều điều kiện để tạo các truy vấn phức tạp hơn.
Sắp xếp dữ liệu theo cột.
Tăng dần:
$posts = Post::orderBy('title')->get();
Giảm dần:
$posts = Post::orderBy('created_at', 'desc')->get();
Hoặc:
$posts = Post::orderBy('id', 'asc')->get();
Trong Laravel, latest() là cách viết ngắn gọn của:
orderBy('created_at', 'desc')
Ví dụ:
$posts = Post::latest()->get();
Nếu muốn sắp xếp theo cột khác:
$posts = Post::latest('id')->get();
Điều này rất hữu ích khi hiển thị các bài viết mới nhất.
Khi số lượng dữ liệu lớn, không nên lấy toàn bộ bằng get().
Laravel hỗ trợ phân trang rất đơn giản.
$posts = Post::paginate(10);
Mỗi trang sẽ hiển thị 10 bản ghi.
Trong Blade:
@foreach($posts as $post)
@endforeach
{{ $posts->links() }}
Laravel sẽ tự sinh giao diện phân trang.
Điểm mạnh của Query Builder là có thể nối nhiều phương thức liên tiếp.
Ví dụ:
$posts = Post::where('status', 1)
->where('views', '>', 100)
->latest()
->paginate(10);
Laravel sẽ lần lượt:
Lọc các bài viết đã xuất bản.
Chỉ lấy bài có trên 100 lượt xem.
Sắp xếp mới nhất trước.
Phân trang 10 bài mỗi trang.
Toàn bộ truy vấn chỉ cần một câu lệnh ngắn gọn, dễ đọc và dễ bảo trì.
Trong khóa học này, chúng ta chủ yếu sử dụng Eloquent vì cú pháp gần gũi với mô hình hướng đối tượng.
Tuy nhiên, Query Builder vẫn là nền tảng mà Eloquent sử dụng phía dưới. Khi dự án lớn hơn hoặc cần tối ưu truy vấn, việc hiểu Query Builder sẽ giúp bạn làm việc hiệu quả hơn.
Trong bài này chúng ta đã tìm hiểu:
where() để lọc dữ liệu.
orWhere() để kết hợp điều kiện OR.
orderBy() để sắp xếp dữ liệu.
latest() để lấy dữ liệu mới nhất.
paginate() để phân trang.
Đây là những phương thức được sử dụng hằng ngày trong hầu hết các dự án Laravel.
Hiển thị tất cả bài viết có status = 1.
Lấy các bài viết có id > 10.
Sắp xếp danh sách bài viết theo tiêu đề từ A → Z.
Hiển thị các bài viết mới nhất.
Phân trang với 5 bài viết trên mỗi trang.
Viết một truy vấn lấy các bài viết có status = 1, sắp xếp mới nhất và phân trang 10 bản ghi.
//01.Hiển thị tất cả bài viết có status = 1.
$posts = Post::where('status', 1)->get();
//02.Lấy các bài viết có id > 10.
$posts = Post::where('id', '>', 10)->get();
//03.Sắp xếp danh sách bài viết theo tiêu đề từ A → Z.
$posts = Post::orderBy('title')->get();
//04.Hiển thị các bài viết mới nhất.
$posts = Post::orderBy('created_at', 'desc')->get();
//hoặc
$posts = Post::latest()->get();
//05.Phân trang với 5 bài viết trên mỗi trang.
$posts = Post::paginate(5);
//trong view
@foreach($posts as $post)
@endforeach
{{ $posts->links() }}
//06.Viết một truy vấn lấy các bài viết có status = 1, sắp xếp mới nhất và phân trang 10 bản ghi.
$posts = Post::where('status', 1)
->latest()
->paginate(10);
Ở bài sau chúng ta sẽ tìm hiểu Relationship One To One, bước đầu xây dựng mối quan hệ giữa các Model trong Laravel.
Ở bài 13, khóa học sẽ chuyển sang một chủ đề rất quan trọng của Eloquent ORM: Relationship, bắt đầu với quan hệ One To One.
x1
Cập nhật: 2026-07-18T19:32:16.088+07:00
Ở bài trước, chúng ta đã tìm hiểu Model và cách Eloquent ORM ánh xạ giữa đối tượng và bảng dữ liệu.
Trong bài học này, chúng ta sẽ bắt đầu thao tác trực tiếp với cơ sở dữ liệu thông qua Eloquent mà không cần viết các câu lệnh SQL.
Đây là một trong những lý do khiến Laravel trở thành framework PHP được yêu thích nhất hiện nay.
CRUD là bốn thao tác cơ bản với dữ liệu:
| Chức năng | Ý nghĩa |
|---|---|
| Create | Thêm dữ liệu |
| Read | Đọc dữ liệu |
| Update | Cập nhật dữ liệu |
| Delete | Xóa dữ liệu |
Hầu hết các hệ thống quản lý như:
Blog
Website tin tức
Bán hàng
Quản lý nhân sự
Quản lý sinh viên
đều xoay quanh bốn thao tác này.
Ví dụ chúng ta có Model:
Post
tương ứng với bảng:
posts
và đã khai báo:
protected $fillable = [
'title',
'content',
'category_id'
];
Thêm dữ liệu mới:
Post::create([
'title' => 'Laravel 12',
'content' => 'Học Eloquent ORM',
'category_id' => 1
]);
Laravel sẽ tự động sinh câu lệnh SQL để thêm dữ liệu vào bảng posts.
Điều kiện để create() hoạt động là Model phải khai báo thuộc tính $fillable hoặc $guarded phù hợp.
Lấy toàn bộ dữ liệu:
$posts = Post::all();
Kết quả trả về là một Collection chứa tất cả bản ghi trong bảng.
Hiển thị:
foreach ($posts as $post) {
echo $post->title;
}
all() thích hợp với bảng có ít dữ liệu.
Nếu bảng có hàng nghìn hoặc hàng triệu bản ghi, nên sử dụng paginate() hoặc chunk() để tối ưu hiệu năng.
Lấy dữ liệu theo khóa chính.
Ví dụ:
$post = Post::find(1);
Laravel sẽ tìm bản ghi có:
id = 1
Nếu tìm thấy:
echo $post->title;
Nếu không tồn tại:
$post
sẽ nhận giá trị:
null
Lấy bản ghi đầu tiên:
$post = Post::first();
Hoặc:
$post = Post::latest()->first();
Thường dùng khi chỉ cần lấy một bản ghi duy nhất.
Cập nhật dữ liệu:
$post = Post::find(1);
$post->update([
'title' => 'Laravel 12 LTS'
]);
Laravel sẽ tự động cập nhật bản ghi có id = 1.
Có thể cập nhật nhiều cột cùng lúc:
$post->update([
'title' => 'Laravel',
'content' => 'Nội dung mới'
]);
Xóa dữ liệu:
$post = Post::find(1);
$post->delete();
Laravel sẽ xóa bản ghi tương ứng khỏi cơ sở dữ liệu.
Ngoài create(), có thể tạo đối tượng trước:
$post = new Post();
$post->title = "Laravel";
$post->content = "Bài viết mới";
$post->category_id = 1;
$post->save();
Phương thức:
save()
sẽ thêm dữ liệu nếu đối tượng chưa tồn tại.
Ví dụ:
$post = Post::find(1);
$post->title = "Laravel Framework";
$post->save();
save() sẽ tự động nhận biết đây là bản ghi đã tồn tại và thực hiện cập nhật.
Trước khi cập nhật hoặc xóa nên kiểm tra:
$post = Post::find(100);
if ($post) {
$post->delete();
}
Điều này giúp tránh lỗi khi bản ghi không tồn tại.
Laravel còn cung cấp:
$post = Post::findOrFail(1);
Nếu không tìm thấy dữ liệu, Laravel sẽ tự động trả về lỗi 404 Not Found.
Đây là cách được sử dụng rất nhiều trong các Controller.
use App\Models\Post;
// Thêm
Post::create([
'title' => 'Laravel 12',
'content' => 'Eloquent ORM',
'category_id' => 1
]);
// Lấy tất cả
$posts = Post::all();
// Lấy theo ID
$post = Post::find(1);
// Cập nhật
$post->update([
'title' => 'Laravel Framework'
]);
// Xóa
$post->delete();
Chỉ với vài dòng mã, chúng ta đã thực hiện đầy đủ các thao tác CRUD mà không cần viết SQL.
| Phương thức | Mục đích |
|---|---|
create() | Thêm dữ liệu nhanh |
all() | Lấy toàn bộ dữ liệu |
find() | Tìm theo khóa chính |
first() | Lấy bản ghi đầu tiên |
update() | Cập nhật dữ liệu |
save() | Thêm hoặc cập nhật đối tượng |
delete() | Xóa dữ liệu |
findOrFail() | Tự động trả lỗi 404 nếu không tìm thấy |
create() yêu cầu khai báo $fillable hoặc $guarded.
Không nên dùng all() với bảng có quá nhiều dữ liệu.
Luôn kiểm tra dữ liệu tồn tại trước khi cập nhật hoặc xóa, hoặc sử dụng findOrFail().
Ưu tiên sử dụng Eloquent thay vì viết SQL thủ công để mã nguồn dễ đọc và dễ bảo trì.
Trong bài học này, chúng ta đã thực hiện đầy đủ bốn thao tác CRUD bằng Eloquent ORM:
Thêm dữ liệu với create().
Lấy dữ liệu bằng all(), find() và first().
Cập nhật dữ liệu với update() và save().
Xóa dữ liệu bằng delete().
Xử lý trường hợp không tìm thấy dữ liệu với findOrFail().
Đến đây, bạn đã có thể thao tác với cơ sở dữ liệu theo phong cách hướng đối tượng mà không cần viết các câu lệnh SQL.
Ở bài tiếp theo, chúng ta sẽ học Query Builder, tìm hiểu các phương thức như where(), orWhere(), orderBy(), latest() và paginate() để xây dựng các truy vấn linh hoạt, tối ưu và phù hợp với những ứng dụng có lượng dữ liệu lớn.
x1
Cập nhật: 2026-07-17T11:50:00.116+07:00
Sau khi hoàn thành phần Database, chúng ta đã biết cách tạo bảng (Migration), thêm dữ liệu mẫu (Seeder) và sinh dữ liệu giả bằng Factory.
Tuy nhiên, cho đến thời điểm này chúng ta vẫn chưa thực sự làm việc với dữ liệu trong ứng dụng.
Trong Laravel, việc thao tác với cơ sở dữ liệu được thực hiện thông qua Eloquent ORM và thành phần quan trọng nhất chính là Model.
Model là lớp đại diện cho một bảng trong cơ sở dữ liệu.
Có thể hiểu đơn giản:
Một Model ↔ Một bảng (Table)
Một đối tượng Model ↔ Một bản ghi (Record)
Ví dụ:
| Model | Bảng |
|---|---|
| User | users |
| Post | posts |
| Category | categories |
Nhờ Model, chúng ta không cần viết các câu lệnh SQL thông thường mà vẫn có thể truy vấn và thao tác dữ liệu theo phong cách hướng đối tượng.
ORM (Object Relational Mapping) là kỹ thuật ánh xạ giữa đối tượng và cơ sở dữ liệu.
Thay vì viết:
SELECT * FROM posts;
Laravel cho phép:
Post::all();
Hay thay vì:
INSERT INTO posts (...)
chúng ta chỉ cần:
Post::create([
// dữ liệu
]);
Đây là lý do Eloquent trở thành một trong những điểm mạnh của Laravel.
Laravel hỗ trợ tạo Model bằng Artisan.
Ví dụ:
php artisan make:model Post
Laravel sẽ tạo:
app/
└── Models/
└── Post.php
Nếu muốn tạo luôn Migration và Factory:
php artisan make:model Post -mf
Hoặc tạo đầy đủ Controller, Migration, Factory và Seeder:
php artisan make:model Post -mfsc
Các tùy chọn này giúp tiết kiệm rất nhiều thời gian khi phát triển dự án.
Ví dụ Model Post:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
//
}
Model kế thừa từ:
Illuminate\Database\Eloquent\Model
Nhờ đó chúng ta có thể sử dụng toàn bộ tính năng của Eloquent ORM.
Laravel mặc định tự suy ra tên bảng từ tên Model.
Ví dụ:
| Model | Table |
|---|---|
| User | users |
| Post | posts |
| Category | categories |
Laravel sẽ tự động thêm chữ s ở cuối tên Model.
Vì vậy, Model Post sẽ làm việc với bảng posts mà không cần cấu hình thêm.
Trong một số trường hợp, tên bảng không theo quy ước của Laravel.
Ví dụ:
tbl_posts
Khi đó cần khai báo:
protected $table = 'tbl_posts';
Laravel sẽ sử dụng bảng này thay vì bảng mặc định.
Laravel mặc định sử dụng khóa chính:
id
Nếu bảng sử dụng khóa chính khác:
protected $primaryKey = 'post_id';
Eloquent sẽ tự động sử dụng khóa này trong các thao tác truy vấn.
Đây là một trong những thuộc tính quan trọng nhất của Model.
Ví dụ:
protected $fillable = [
'title',
'content',
'category_id'
];
fillable là danh sách các cột được phép gán dữ liệu hàng loạt (Mass Assignment).
Ví dụ:
Post::create([
'title' => 'Laravel 12',
'content' => '...',
'category_id' => 1
]);
Nếu một cột không nằm trong fillable, Laravel sẽ không cho phép ghi dữ liệu bằng create() hoặc update() theo dạng mảng.
Đây là cơ chế bảo vệ giúp tránh việc ghi nhầm hoặc ghi trái phép vào các cột quan trọng.
Ngược lại với fillable, thuộc tính guarded dùng để chỉ định những cột không được phép gán hàng loạt.
Ví dụ:
protected $guarded = [
'id'
];
Hoặc:
protected $guarded = [];
Điều này có nghĩa là tất cả các cột đều có thể được gán dữ liệu.
Cách này thường chỉ nên sử dụng trong các dự án nhỏ hoặc khi bạn hiểu rõ dữ liệu được xử lý.
Thông thường, bạn chỉ nên sử dụng một trong hai.
Ví dụ an toàn:
protected $fillable = [
'title',
'content',
'category_id'
];
Thay vì:
protected $guarded = [];
Trong các dự án thực tế, fillable thường được ưu tiên hơn vì giúp kiểm soát dữ liệu tốt hơn và giảm nguy cơ phát sinh lỗ hổng bảo mật.
class Post extends Model
{
protected $fillable = [
'title',
'content',
'category_id'
];
}
Đây là cấu hình phổ biến trong hầu hết các dự án Laravel.
Laravel mặc định:
Model nằm trong app/Models.
Tên Model viết ở dạng số ít (Post, User, Category).
Tên bảng ở dạng số nhiều (posts, users, categories).
Khóa chính là id.
Có hai cột thời gian:
created_at
updated_at
Nhờ các quy ước này, lập trình viên rất ít khi phải cấu hình thêm.
Trong bài học này, chúng ta đã tìm hiểu:
Model là gì.
Eloquent ORM hoạt động như thế nào.
Tạo Model bằng Artisan.
Quy ước tên bảng trong Laravel.
Khai báo bảng bằng $table.
Khai báo khóa chính bằng $primaryKey.
Thuộc tính $fillable.
Thuộc tính $guarded.
Khi nào nên dùng fillable và guarded.
Ở bài tiếp theo, chúng ta sẽ bắt đầu thực hiện CRUD bằng Eloquent, học cách thêm, lấy, cập nhật và xóa dữ liệu thông qua các phương thức như create(), all(), find(), update() và delete() mà không cần viết câu lệnh SQL.
x1
Cập nhật: 2026-07-16T07:30:00.116+07:00
Ở bài trước, chúng ta đã học cách sử dụng Seeder để thêm dữ liệu mẫu vào Database.
Tuy nhiên, nếu cần tạo hàng trăm hoặc hàng nghìn bản ghi thì việc tự viết từng dữ liệu sẽ rất mất thời gian.
Laravel cung cấp Factory kết hợp với Faker để sinh dữ liệu giả (Fake Data) một cách tự động.
Đây là công cụ được sử dụng rất phổ biến trong quá trình phát triển và kiểm thử ứng dụng.
Factory là lớp dùng để định nghĩa cách tạo dữ liệu mẫu cho một Model.
Thay vì tự nhập:
100 người dùng
500 bài viết
2.000 bình luận
chúng ta chỉ cần yêu cầu Factory tạo dữ liệu và Laravel sẽ tự động sinh các bản ghi với thông tin ngẫu nhiên.
Faker là thư viện được Laravel tích hợp sẵn để tạo dữ liệu giả.
Ví dụ Faker có thể sinh:
Họ tên
Địa chỉ
Số điện thoại
Ngày tháng
Văn bản ngẫu nhiên
Hình ảnh (URL)
Số tiền
Và nhiều loại dữ liệu khác
Nhờ Faker, dữ liệu mẫu trông giống dữ liệu thật hơn, giúp việc kiểm thử trở nên hiệu quả.
Laravel hỗ trợ tạo Factory bằng Artisan:
php artisan make:factory PostFactory
Nếu đã có Model, bạn nên tạo Factory cùng với Model:
php artisan make:model Post -mf
Tùy chọn:
-m: tạo Migration.
-f: tạo Factory.
Laravel sẽ tạo file:
database/
└── factories/
└── PostFactory.php
Ví dụ:
public function definition(): array
{
return [
'title' => fake()->sentence(),
'content' => fake()->paragraph(),
];
}
Trong đó:
sentence() tạo tiêu đề ngẫu nhiên.
paragraph() tạo đoạn văn bản.
fake() là đối tượng Faker được Laravel cung cấp.
Tên:
fake()->name()
Email:
fake()->email()
Tên người dùng:
fake()->userName()
Địa chỉ:
fake()->address()
Số điện thoại:
fake()->phoneNumber()
Tiêu đề:
fake()->sentence()
Đoạn văn:
fake()->paragraph()
Nhiều đoạn văn:
fake()->paragraphs(3, true)
Số ngẫu nhiên:
fake()->numberBetween(1,100)
Ngày:
fake()->date()
Boolean:
fake()->boolean()
Những hàm này đáp ứng hầu hết nhu cầu tạo dữ liệu mẫu trong quá trình phát triển.
Sau khi định nghĩa Factory, có thể tạo dữ liệu bằng Seeder:
Post::factory()->count(20)->create();
Laravel sẽ tự động tạo 20 bài viết và lưu vào Database.
Có thể tạo nhiều hơn:
User::factory()->count(100)->create();
Hoặc:
Category::factory()->count(10)->create();
Ví dụ:
public function run(): void
{
User::factory()->count(10)->create();
Category::factory()->count(5)->create();
Post::factory()->count(50)->create();
}
Sau đó chạy:
php artisan migrate:fresh --seed
Laravel sẽ:
Tạo lại Database.
Chạy Migration.
Sinh toàn bộ dữ liệu mẫu.
Đây là quy trình rất phổ biến trong các dự án thực tế.
Factory còn có thể tạo dữ liệu liên kết.
Ví dụ:
Post::factory()
->count(30)
->for(User::factory())
->create();
Laravel sẽ:
Tạo User.
Tạo 30 bài viết.
Tự động gán user_id.
Sau này khi học Relationship, chúng ta sẽ khai thác tính năng này nhiều hơn.
chính xác hơn là:
posts phải có cột user_id (khóa ngoại) thì mới dùng được ->for(User::factory()).
Ví dụ migration của posts:
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->string('title');
$table->text('content');
$table->timestamps();
});
// Post.php
public function user()
{
return $this->belongsTo(User::class);
}
// User.php
public function posts()
{
return $this->hasMany(Post::class);
}
Sau đó đoạn này sẽ hoạt động.
Nhưng tối ưu hơn mỗi post có user_id ngẫu nhiên.
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory Model
*/
class PostFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array string, mixed
*/
public function definition(): array
{
return [
//Định nghĩa dữ liệu mẫu
'title' => fake()->sentence(),
'content' => fake()->paragraph(),
'user_id' => fn () => User::query()->inRandomOrder()->value('id'),
];
}
}
và bỏ dòng
->for(User::factory())
Đôi khi cần tạo dữ liệu theo thứ tự thay vì hoàn toàn ngẫu nhiên.
Ví dụ:
User::factory()
->count(3)
->sequence(
['role' => 'Admin'],
['role' => 'Editor'],
['role' => 'User']
)
->create();
Factory sẽ lần lượt tạo các vai trò theo đúng thứ tự đã khai báo.
Factory chỉ nên dùng để tạo dữ liệu phục vụ phát triển và kiểm thử.
Không sử dụng dữ liệu giả trên hệ thống đang vận hành thực tế.
Có thể kết hợp Factory với Seeder để khởi tạo dữ liệu nhanh chóng.
Nên định nghĩa Factory cho các Model chính như User, Category, Post và Comment.
Trong bài học này, chúng ta đã tìm hiểu:
Factory là gì.
Faker là gì.
Tạo Factory bằng Artisan.
Định nghĩa dữ liệu mẫu.
Các hàm Faker phổ biến.
Sinh dữ liệu bằng Factory.
Kết hợp Factory với Seeder.
Tạo dữ liệu có quan hệ giữa các Model.
Sử dụng Sequence để tạo dữ liệu theo thứ tự.
Đến đây, chúng ta đã hoàn thành phần Database của khóa học.
Ở bài tiếp theo, chúng ta sẽ bước sang phần Eloquent ORM, tìm hiểu về Model, cách Laravel làm việc với bảng dữ liệu và cách thao tác với cơ sở dữ liệu theo phong cách hướng đối tượng thay vì viết các câu lệnh SQL thủ công.
💡 Gợi ý thực hành sau bài học
Tạo dữ liệu mẫu cho dự án Blog:
10 người dùng (User)
5 danh mục (Category)
100 bài viết (Post)
Mỗi bài viết được gán ngẫu nhiên cho một người dùng và một danh mục.
Sau đó chạy:
php artisan migrate:fresh --seed
Khi hoàn thành, học viên sẽ có một cơ sở dữ liệu đầy đủ dữ liệu mẫu để tiếp tục học Eloquent ORM, CRUD và Relationship mà không cần nhập dữ liệu thủ công.
x1
Cập nhật: 2026-07-16T04:57:17.324+07:00
Ở bài trước, chúng ta đã học cách tạo bảng bằng Migration.
Tuy nhiên, sau khi tạo xong Database, các bảng vẫn hoàn toàn trống.
Trong quá trình phát triển, việc nhập dữ liệu thủ công bằng phpMyAdmin hoặc viết từng câu lệnh SQL sẽ rất mất thời gian.
Laravel cung cấp Seeder để tự động thêm dữ liệu mẫu (Sample Data) vào cơ sở dữ liệu chỉ với một vài lệnh đơn giản.
Seeder là các lớp PHP dùng để chèn dữ liệu vào Database.
Seeder thường được sử dụng để:
Tạo dữ liệu mẫu phục vụ phát triển.
Khởi tạo dữ liệu mặc định cho hệ thống.
Tạo tài khoản quản trị đầu tiên.
Hỗ trợ kiểm thử ứng dụng.
Thay vì nhập từng bản ghi bằng tay, bạn chỉ cần chạy Seeder và Laravel sẽ tự động thêm dữ liệu.
Tất cả Seeder được lưu trong:
database/
└── seeders/
Ngay khi tạo dự án Laravel, bạn sẽ thấy sẵn file:
DatabaseSeeder.php
Đây là Seeder gốc, có nhiệm vụ gọi các Seeder khác.
Để tạo Seeder mới, sử dụng Artisan:
php artisan make:seeder CategorySeeder
Laravel sẽ tạo:
database/seeders/CategorySeeder.php
Bên trong file sẽ có phương thức:
public function run(): void
{
//
}
Mọi dữ liệu cần thêm vào Database sẽ được viết trong phương thức run().
Ví dụ tạo dữ liệu cho bảng categories:
use Illuminate\Support\Facades\DB;
public function run(): void
{
DB::table('categories')->insert([
'name' => 'Laravel',
'created_at' => now(),
'updated_at' => now(),
]);
}
Khi chạy Seeder, Laravel sẽ thêm một bản ghi vào bảng categories.
Có thể thêm nhiều dữ liệu cùng lúc:
DB::table('categories')->insert([
[
'name' => 'Laravel',
'created_at' => now(),
'updated_at' => now(),
],
[
'name' => 'PHP',
'created_at' => now(),
'updated_at' => now(),
],
[
'name' => 'MySQL',
'created_at' => now(),
'updated_at' => now(),
],
]);
Cách này nhanh hơn so với việc gọi insert() nhiều lần.
Nếu database chưa có bảng categories thì không được chạy Seeder trước.
Thứ tự đúng trong Laravel luôn là:
Migration → Migrate → Seeder
Tức là:
php artisan make:migration create_categories_table
public function up(): void { Schema::create('categories', function (Blueprint $table) { $table->id(); $table->string('name'); $table->timestamps(); }); }
php artisan migrate
Lúc này database mới có bảng categories.
php artisan db:seed --class=CategorySeeder
Laravel sẽ thực hiện phương thức run() trong CategorySeeder.
Nếu chạy thành công, dữ liệu sẽ xuất hiện trong bảng categories.
Thông thường, một dự án có rất nhiều Seeder như:
UserSeeder
CategorySeeder
PostSeeder
RoleSeeder
Thay vì chạy từng Seeder, chúng ta đăng ký chúng trong DatabaseSeeder.
Ví dụ:
public function run(): void
{
$this->call([
CategorySeeder::class,
UserSeeder::class,
PostSeeder::class,
]);
}
Sau đó chỉ cần chạy:
php artisan db:seed
Laravel sẽ tự động gọi toàn bộ Seeder đã khai báo.
Trong quá trình phát triển, chúng ta thường muốn:
Xóa toàn bộ bảng.
Tạo lại Database.
Thêm dữ liệu mẫu.
Laravel hỗ trợ chỉ với một lệnh:
php artisan migrate:fresh --seed
Lệnh này sẽ:
Xóa tất cả bảng.
Chạy lại toàn bộ Migration.
Chạy DatabaseSeeder.
Đây là lệnh được sử dụng rất thường xuyên trong quá trình phát triển.
Seeder thường được kết hợp với Faker để sinh dữ liệu ngẫu nhiên.
Ví dụ:
100 người dùng.
1.000 bài viết.
500 bình luận.
Trong bài học tiếp theo, chúng ta sẽ tìm hiểu Factory, công cụ giúp tạo dữ liệu giả một cách nhanh chóng và chuyên nghiệp.
Không nên sử dụng Seeder để nhập dữ liệu thực tế của khách hàng.
Chỉ thêm các dữ liệu mặc định hoặc dữ liệu phục vụ phát triển và kiểm thử.
Có thể sử dụng Seeder để tạo tài khoản quản trị mặc định cho dự án.
Khi làm việc nhóm, nên đưa Seeder vào hệ thống quản lý mã nguồn để mọi thành viên có cùng dữ liệu khởi tạo.
Trong bài học này, chúng ta đã tìm hiểu:
Seeder là gì.
Tạo Seeder bằng Artisan.
Thêm dữ liệu bằng DB::table()->insert().
Chạy Seeder riêng lẻ.
Quản lý nhiều Seeder với DatabaseSeeder.
Kết hợp Migration và Seeder bằng php artisan migrate:fresh --seed.
Vai trò của Seeder trong phát triển và kiểm thử ứng dụng.
Ở bài tiếp theo, chúng ta sẽ học Factory, sử dụng Faker để tạo hàng trăm hoặc hàng nghìn bản ghi dữ liệu ngẫu nhiên chỉ với vài dòng mã, giúp việc kiểm thử và phát triển ứng dụng trở nên nhanh chóng và hiệu quả hơn.
💡 Gợi ý thực hành sau bài học:
Cho học viên tạo 3 Seeder:
CategorySeeder → thêm 5 danh mục.
UserSeeder → thêm 1 tài khoản quản trị.
PostSeeder → thêm 10 bài viết mẫu.
Sau đó đăng ký cả 3 trong DatabaseSeeder và chạy:
php artisan migrate:fresh --seed
Đây là quy trình mà hầu hết các dự án Laravel thực tế đều sử dụng khi khởi tạo dữ liệu cho môi trường phát triển.
x1
Cập nhật: 2026-07-13T20:24:34.894+07:00
Ở bài trước, chúng ta đã kết nối thành công Laravel với MySQL và chạy các Migration mặc định của hệ thống.
Trong bài học này, chúng ta sẽ tìm hiểu sâu hơn về Migration – một trong những tính năng quan trọng nhất của Laravel.
Thay vì tạo bảng trực tiếp bằng phpMyAdmin, Laravel cho phép chúng ta quản lý toàn bộ cấu trúc cơ sở dữ liệu bằng mã nguồn.
Điều này giúp dự án dễ bảo trì, dễ chia sẻ và đồng bộ giữa các thành viên trong nhóm.
Migration là các file PHP dùng để tạo hoặc thay đổi cấu trúc cơ sở dữ liệu.
Có thể xem Migration như "lịch sử thay đổi" của Database. Mỗi khi cần tạo bảng mới, thêm cột hoặc xóa cột, chúng ta chỉ cần tạo một Migration mới thay vì chỉnh sửa trực tiếp trên cơ sở dữ liệu.
Nhờ vậy, mọi thay đổi đều được lưu lại và có thể hoàn tác khi cần.
Để tạo một Migration mới, sử dụng Artisan:
php artisan make:migration create_posts_table
Sau khi chạy lệnh, Laravel sẽ tạo một file trong thư mục:
database/
└── migrations/
Tên file sẽ có dạng:
2026_07_08_101530_create_posts_table.php
Phần thời gian ở đầu giúp Laravel biết thứ tự thực thi các Migration.
💡 Chú ý
Ở bước này chưa tạo Database (chưa chạy
php artisan migrate), nên nếu gõ sai tên migration (ví dụ thiếu chữstrongposts) thì bạn chỉ cần:
🗑️ Xóa file migration mà Laravel vừa tạo trong thư mục
database/migrations/.⌨️ Chạy lại đúng lệnh
php artisan make:migration ....Vì migration chưa được thực thi, bạn có thể xóa và tạo lại mà không ảnh hưởng đến cơ sở dữ liệu.
Một Migration gồm hai phương thức chính:
public function up(): void
{
//
}
public function down(): void
{
//
}
up(): Thực hiện thay đổi (tạo bảng, thêm cột...).
down(): Hoàn tác thay đổi (xóa bảng, xóa cột...).
Laravel sẽ gọi up() khi chạy Migration và gọi down() khi Rollback.
Ví dụ tạo bảng posts:
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->timestamps();
});
Ý nghĩa:
id() tạo khóa chính tự tăng.
string() tạo cột chuỗi.
text() dùng cho nội dung dài.
timestamps() tạo hai cột:
created_at
updated_at
Sau khi chạy Migration, Laravel sẽ tự động tạo bảng posts.
Laravel hỗ trợ rất nhiều kiểu dữ liệu.
Một số kiểu thường gặp:
$table->string('name');
$table->text('content');
$table->integer('price');
$table->boolean('status');
$table->date('birthday');
$table->timestamp('published_at');
$table->float('score');
$table->decimal('amount',10,2);
Việc lựa chọn đúng kiểu dữ liệu sẽ giúp cơ sở dữ liệu hoạt động hiệu quả hơn.
Trong các dự án thực tế, các bảng thường liên kết với nhau.
Ví dụ:
Một User có nhiều Post.
Một Category có nhiều Post.
Laravel hỗ trợ tạo khóa ngoại rất đơn giản:
$table->foreignId('user_id')
->constrained()
->cascadeOnDelete();
Lệnh trên tương đương với:
tạo cột user_id
tạo Foreign Key
tham chiếu đến bảng users
tự động xóa dữ liệu liên quan khi User bị xóa.
Nếu tham chiếu đến bảng khác:
$table->foreignId('category_id')
->constrained('categories');
Đây là cách được khuyến nghị trong các dự án Laravel hiện đại.
Sau khi hoàn thành Migration:
php artisan migrate
Laravel sẽ đọc file Migration mới và thực hiện các thay đổi lên Database.
Những Migration đã chạy sẽ không bị chạy lại.
Nếu tạo sai bảng hoặc cần quay lại trạng thái trước đó:
php artisan migrate:rollback
Laravel sẽ gọi phương thức:
down()
để hoàn tác Migration gần nhất.
Trong quá trình học tập, đôi khi chúng ta muốn xóa toàn bộ bảng và tạo lại từ đầu.
php artisan migrate:fresh
Lệnh này sẽ:
Xóa tất cả bảng.
Chạy lại toàn bộ Migration.
Nếu muốn tạo dữ liệu mẫu luôn:
php artisan migrate:fresh --seed
Lệnh này rất hữu ích trong quá trình phát triển.
Laravel có quy ước đặt tên Migration:
create_posts_table
create_categories_table
create_users_table
Khi thêm cột:
add_status_to_posts_table
Đặt tên đúng quy ước giúp người khác dễ hiểu mục đích của Migration.
Không chỉnh sửa trực tiếp Database nếu dự án đang quản lý bằng Migration.
Mỗi thay đổi nên tạo một Migration mới thay vì sửa Migration cũ đã được chia sẻ.
Thường xuyên sao lưu dữ liệu trước khi chạy các lệnh như migrate:fresh.
Kiểm tra kỹ khóa ngoại để tránh lỗi khi tạo bảng.
Trong bài học này, chúng ta đã tìm hiểu:
Migration là gì.
Cách tạo Migration bằng Artisan.
Cấu trúc của một file Migration.
Các kiểu dữ liệu thường dùng.
Tạo khóa ngoại với foreignId().
Chạy Migration.
Rollback Migration.
Làm mới toàn bộ Database.
Ở bài tiếp theo, chúng ta sẽ học Seeder, sử dụng Faker để tạo dữ liệu mẫu và tự động thêm dữ liệu vào cơ sở dữ liệu, giúp việc phát triển và kiểm thử ứng dụng trở nên nhanh chóng hơn.
x1
Cập nhật: 2026-07-12T12:04:42.232+07:00
Sau khi hoàn thành phần Routing, Controller và Blade, chúng ta đã có thể xây dựng giao diện cho ứng dụng.
Tuy nhiên, mọi website thực tế đều cần lưu trữ dữ liệu như người dùng, bài viết, danh mục hay đơn hàng.
Đó là lúc Database trở thành thành phần không thể thiếu.
Trong bài học này, chúng ta sẽ tìm hiểu cách kết nối Laravel với MySQL và chạy Migration đầu tiên để tạo cơ sở dữ liệu theo chuẩn của Laravel.
Laravel hỗ trợ nhiều hệ quản trị cơ sở dữ liệu như:
MySQL
MariaDB
PostgreSQL
SQLite
SQL Server
Trong khóa học này, chúng ta sẽ sử dụng MySQL vì đây là hệ quản trị phổ biến nhất trong các dự án PHP.
Trước tiên hãy tạo một database mới.
Ví dụ:
CREATE DATABASE laravel12;
Bạn có thể tạo bằng:
phpMyAdmin
MySQL Workbench
DBeaver
Hoặc sử dụng dòng lệnh MySQL.
.envLaravel sử dụng file .env để lưu các thông tin cấu hình của dự án.
Mở file:
.env
Tìm đến phần Database:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel12
DB_USERNAME=root
DB_PASSWORD=
Ý nghĩa của từng thông số:
DB_CONNECTION: Loại cơ sở dữ liệu.
DB_HOST: Địa chỉ máy chủ.
DB_PORT: Cổng kết nối.
DB_DATABASE: Tên cơ sở dữ liệu.
DB_USERNAME: Tài khoản đăng nhập.
DB_PASSWORD: Mật khẩu.
Laravel sẽ đọc các thông tin này mỗi khi kết nối Database.
Sau khi cấu hình xong, hãy khởi động ứng dụng:
php artisan serve
Nếu truy cập website không gặp lỗi kết nối Database, nghĩa là Laravel đã đọc đúng thông tin trong file .env.
Nếu cấu hình sai, bạn có thể gặp các lỗi như:
Access denied
Unknown database
Connection refused
Hãy kiểm tra lại tên database, tài khoản, mật khẩu hoặc dịch vụ MySQL đã được khởi động hay chưa.
Chú ý: phải Chạy Migration trước:
php artisan migrateTrong Laravel, chúng ta không tạo bảng trực tiếp bằng phpMyAdmin.
Thay vào đó, Laravel sử dụng Migration để quản lý cấu trúc cơ sở dữ liệu bằng mã nguồn.
Có thể hiểu Migration giống như "phiên bản hóa" (version control) cho Database.
Mỗi thay đổi về bảng dữ liệu đều được lưu thành một file Migration, giúp dễ dàng theo dõi, chia sẻ và đồng bộ giữa các thành viên trong nhóm.
Tất cả Migration được lưu tại:
database/
└── migrations/
Ngay khi tạo project Laravel, bạn sẽ thấy sẵn một số Migration như:
users
password_reset_tokens
cache
jobs
Đây là các bảng mặc định phục vụ hệ thống.
Laravel cung cấp Artisan để tạo toàn bộ bảng chỉ với một lệnh:
php artisan migrate
Khi chạy lệnh này, Laravel sẽ:
Đọc toàn bộ file Migration.
Tạo các bảng trong Database.
Ghi lại lịch sử Migration vào bảng migrations.
Nếu thành công, bạn sẽ thấy các bảng mặc định xuất hiện trong Database.
migrationsLaravel tự động tạo bảng:
migrations
Bảng này dùng để lưu:
Migration nào đã chạy.
Thời điểm chạy.
Thứ tự chạy.
Nhờ đó Laravel biết file nào cần thực thi ở những lần tiếp theo và tránh chạy lặp lại.
Mở phpMyAdmin hoặc công cụ quản lý Database, bạn sẽ thấy các bảng như:
users
password_reset_tokens
sessions
cache
cache_locks
jobs
job_batches
failed_jobs
migrations
(Tùy theo phiên bản Laravel và các tùy chọn khi tạo dự án, danh sách bảng mặc định có thể khác nhau.)
Điều này cho thấy Laravel đã kết nối thành công với MySQL và thực hiện Migration.
Chạy Migration:
php artisan migrate
Quay lại lần Migration gần nhất:
php artisan migrate:rollback
Làm mới toàn bộ Migration:
php artisan migrate:fresh
Làm mới và chạy Seeder:
php artisan migrate:fresh --seed
Những lệnh này sẽ được sử dụng thường xuyên trong quá trình phát triển ứng dụng.
Không chỉnh sửa trực tiếp cấu trúc bảng trên môi trường phát triển nếu dự án đang sử dụng Migration.
Mọi thay đổi về Database nên được quản lý bằng Migration để đảm bảo tính đồng bộ.
Không chia sẻ file .env vì có thể chứa thông tin nhạy cảm như tài khoản và mật khẩu Database.
Thêm .env vào .gitignore khi làm việc với Git.
Trong bài học này, chúng ta đã:
Hiểu vai trò của Database trong Laravel.
Tạo Database MySQL.
Cấu hình kết nối thông qua file .env.
Chạy Migration đầu tiên bằng Artisan.
Tìm hiểu bảng migrations.
Làm quen với các lệnh Migration cơ bản.
Ở bài tiếp theo, chúng ta sẽ đi sâu vào Migration, học cách tự tạo bảng, định nghĩa các kiểu dữ liệu, khóa ngoại (foreignId) và quản lý thay đổi cấu trúc cơ sở dữ liệu theo đúng quy trình phát triển chuyên nghiệp trong Laravel.
x1
Cập nhật: 2026-07-11T15:14:39.079+07:00
Ở bài trước, chúng ta đã học cách sử dụng Controller để xử lý logic của ứng dụng.
Tuy nhiên, nếu Controller vừa xử lý dữ liệu vừa chứa toàn bộ mã HTML thì mã nguồn sẽ rất khó đọc và khó bảo trì.
Laravel giải quyết vấn đề này bằng Blade Template Engine – hệ thống template mạnh mẽ, đơn giản và được tích hợp sẵn.
Blade là Template Engine của Laravel, giúp tách riêng phần giao diện (View) khỏi phần xử lý nghiệp vụ (Controller).
Mô hình hoạt động:
Request
↓
Route
↓
Controller
↓
Model (nếu có)
↓
Blade View
↓
HTML
Nhờ Blade, chúng ta có thể:
Viết giao diện sạch sẽ.
Tái sử dụng các thành phần giao diện.
Tránh lặp lại mã HTML.
Hiển thị dữ liệu một cách an toàn.
Trong Laravel, tất cả giao diện được lưu trong thư mục:
resources/
└── views/
Tạo file:
resources/views/home.blade.php
Nội dung:
<h1>Xin chào Laravel 12</h1>
Trong Controller:
public function index()
{
return view('home');
}
Laravel sẽ tự động tìm file:
resources/views/home.blade.php
Controller:
public function index()
{
$title = "Học Laravel 12";
return view('home', compact('title'));
}
Blade:
<h1>{{ $title }}</h1>
Ký hiệu:
{{ }}
được dùng để hiển thị dữ liệu và tự động chống XSS bằng cách escape HTML.
Blade hỗ trợ cú pháp ngắn gọn hơn PHP thuần.
Điều kiện:
@if($age >= 18)
Người lớn
@else
Trẻ em
@endif
Vòng lặp:
@foreach($posts as $post)
<p>{{ $post->title }}</p>
@endforeach
Lặp theo số lần:
@for($i = 1; $i <= 5; $i++)
{{ $i }}
@endfor
Một website thường có:
Header
Menu
Footer
Nội dung
Nếu mỗi trang đều viết lại những phần này sẽ rất mất thời gian.
Blade cho phép tạo Layout dùng chung.
Ví dụ:
resources/views/layouts/app.blade.php
<!DOCTYPE html>
<html>
<head>
<title>Laravel 12</title>
</head>
<body>
<header>
Header
</header>
@yield('content')
<footer>
Footer
</footer>
</body>
</html>
Trang Home:
@extends('layouts.app')
@section('content')
<h1>Trang chủ</h1>
@endsection
Laravel sẽ tự động chèn nội dung của @section vào vị trí @yield.
Đây là cách tổ chức giao diện phổ biến trong hầu hết các dự án Laravel.
Layout:
@yield('content')
View:
@section('content')
<h2>Xin chào</h2>
@endsection
Có thể tạo nhiều vùng nội dung như:
title
content
sidebar
scripts
Mỗi vùng sẽ được quản lý độc lập.
Những phần giao diện dùng nhiều lần nên tách thành các file riêng.
Ví dụ:
views/
├── partials/
│ ├── header.blade.php
│ ├── footer.blade.php
│ └── menu.blade.php
Trong Layout:
@include('partials.header')
@include('partials.menu')
@yield('content')
@include('partials.footer')
Việc chia nhỏ giao diện giúp dự án dễ bảo trì hơn rất nhiều.
Chú ý: tạo trước các file phải include
header.blade.php
<header> <h2>Laravel 12 Tutorial</h2> </header>
menu.blade.php
<nav> <a href="/">Home</a> | <a href="/about">About</a> </nav> <hr>
footer.blade.php
<hr> <footer> © {{ date('Y') }} </footer>
Đối với những thành phần giao diện có thể tái sử dụng như:
Button
Card
Alert
Modal
Navbar
Laravel khuyến khích sử dụng Component.
Tạo Component:
php artisan make:component Alert
Laravel sẽ tạo:
app/View/Components/
resources/views/components/
Sử dụng:
<x-alert>
Lưu dữ liệu thành công.
</x-alert>
Component giúp giao diện hiện đại, dễ mở rộng và giảm đáng kể lượng mã bị lặp.
Hãy mở file:
resources/views/components/alert.blade.php
Nếu bạn thấy:
<div> Breathing in, I calm body and mind. Breathing out, I smile. - Thich Nhat Hanh </div>
thì đây là nguyên nhân. Bạn đã xóa mất:
{{ $slot }}
$slot chính là nơi Laravel chèn nội dung nằm giữa:
Comment chỉ hiển thị trong mã nguồn:
{{-- Đây là comment Blade --}}
Khác với:
<!-- HTML Comment -->
Comment Blade sẽ không xuất hiện khi trình duyệt nhận HTML.
Blade mặc định bảo vệ khỏi XSS:
{{ $content }}
Nếu muốn hiển thị HTML:
{!! $content !!}
Chỉ nên sử dụng khi dữ liệu đã được kiểm soát để tránh lỗ hổng bảo mật.
resources/
└── views/
├── layouts/
│ └── app.blade.php
├── partials/
│ ├── header.blade.php
│ ├── footer.blade.php
│ └── menu.blade.php
├── components/
├── home.blade.php
└── about.blade.php
Đây là cách tổ chức được sử dụng phổ biến trong các dự án Laravel.
Chú ý: trong views tạo thêm file about.blade.php và trong HomeController sửa lại:
public function about()
{
return view('about');
}
Sau bài học này, bạn đã biết:
Blade Template Engine là gì.
Tạo View trong Laravel.
Truyền dữ liệu từ Controller sang View.
Hiển thị dữ liệu với {{ }}.
Sử dụng @if, @foreach, @for.
Tạo Layout với @extends, @section và @yield.
Tái sử dụng giao diện bằng @include.
Xây dựng Component để tạo các thành phần giao diện chuyên nghiệp.
Hiểu cách Blade hỗ trợ bảo mật thông qua cơ chế escape HTML.
Ở bài tiếp theo, chúng ta sẽ bắt đầu làm việc với cơ sở dữ liệu bằng cách cấu hình Database, kết nối MySQL và thực hiện Migration đầu tiên trong Laravel 12.
x1
Cập nhật: 2026-07-10T11:22:53.715+07:00
Ở bài trước chúng ta đã tìm hiểu về Routing – nơi tiếp nhận các yêu cầu (Request) từ người dùng.
Tuy nhiên, nếu viết toàn bộ logic ngay trong file routes/web.php thì dự án sẽ nhanh chóng trở nên khó đọc và khó bảo trì.
Đó chính là lý do Controller ra đời.
Controller là nơi tiếp nhận Request từ Route, xử lý nghiệp vụ và trả kết quả về cho người dùng. Có thể hiểu đơn giản:
Route → Controller → Model → View
Controller đóng vai trò trung gian giữa giao diện (View) và dữ liệu (Model), giúp mã nguồn được tổ chức rõ ràng theo mô hình MVC.
Laravel cung cấp Artisan CLI để tạo Controller chỉ với một lệnh:
php artisan make:controller HomeController
Sau khi chạy lệnh, Laravel sẽ tạo file:
app/
└── Http/
└── Controllers/
└── HomeController.php
Đây là nơi chúng ta viết toàn bộ logic xử lý cho từng chức năng.
Mỗi phương thức (method) trong Controller được gọi là một Action.
Ví dụ:
class HomeController extends Controller
{
public function index()
{
return "Xin chào Laravel 12";
}
public function about()
{
return "Trang giới thiệu";
}
}
Sau đó khai báo Route:
use App\Http\Controllers\HomeController;
Route::get('/', [HomeController::class, 'index']);
Route::get('/about', [HomeController::class, 'about']);
Khi người dùng truy cập URL, Laravel sẽ tự động gọi Action tương ứng.
Link chạy: http://localhost/blog/public/
Đối với các chức năng CRUD như Quản lý bài viết, Sản phẩm hay Danh mục, Laravel hỗ trợ Resource Controller.
Tạo Resource Controller:
php artisan make:controller PostController --resource
Laravel sẽ tạo sẵn các phương thức:
index()
create()
store()
show()
edit()
update()
destroy()
Đây là chuẩn được sử dụng trong hầu hết các dự án Laravel thực tế.
Controller không chỉ xử lý dữ liệu mà còn truyền dữ liệu sang Blade để hiển thị.
Ví dụ:
public function index()
{
$title = "Học Laravel 12";
return view('home', compact('title'));
}
Trong file Blade (tạo mới): resources/views/home.blade.php
<h1>{{ $title }}</h1>
Laravel sẽ tự động truyền biến từ Controller sang View một cách đơn giản và rõ ràng.
Khi xử lý nghiệp vụ.
Khi truy vấn cơ sở dữ liệu.
Khi gọi Model.
Khi trả về View hoặc JSON.
Khi muốn dự án dễ bảo trì và mở rộng.
Không nên viết quá nhiều logic trực tiếp trong Route vì sẽ khiến mã nguồn rối và khó quản lý.
Trong bài học này chúng ta đã tìm hiểu:
Controller là gì.
Cách tạo Controller bằng Artisan.
Action trong Controller.
Resource Controller.
Truyền dữ liệu từ Controller sang View.
Ở bài tiếp theo, chúng ta sẽ học Blade Template Engine để xây dựng giao diện động, tái sử dụng layout và tạo các component chuyên nghiệp trong Laravel 12.
x1
Cập nhật: 2026-07-09T11:48:04.620+07:00
Routing là một trong những thành phần quan trọng nhất của Laravel. Mọi yêu cầu (Request) từ trình duyệt đều đi qua hệ thống Routing trước khi được xử lý.
Hiểu Routing sẽ giúp bạn biết cách điều hướng người dùng đến đúng chức năng của ứng dụng.
Khi người dùng truy cập một địa chỉ URL, Laravel sẽ kiểm tra xem địa chỉ đó đã được khai báo trong hệ thống Route hay chưa.
Nếu có, Laravel sẽ thực thi đoạn mã hoặc Controller tương ứng.
Ví dụ:
https://example.com/
Laravel sẽ tìm Route cho đường dẫn /.
Nếu tồn tại:
Route::get('/', function () {
return 'Hello Laravel!';
});
Trình duyệt sẽ hiển thị:
Hello Laravel!
Các Route dành cho website được khai báo trong:
routes/
│
├── web.php
├── api.php
├── console.php
└── channels.php
Trong giai đoạn đầu học Laravel, bạn sẽ làm việc chủ yếu với:
routes/web.php 📌 Lưu ý
Vì ở bài trước chúng ta đã tạo và cài đặt dự án Blog, nên có 2 cách để xem ứng dụng Laravel:
🌐 Cách 1 — Truy cập trực tiếp qua Laragon
http://localhost/blog/publicPhù hợp khi dự án được đặt trong thư mục www của Laragon và sử dụng Apache/Nginx.
💻 Cách 2 — Chạy bằng Artisan
Mở Terminal trong Laragon, di chuyển vào thư mục dự án:
cd blog php artisan serveSau đó mở trình duyệt và truy cập:
http://127.0.0.1:8000Đây là cách được sử dụng phổ biến trong quá trình học tập và phát triển vì không cần cấu hình Virtual Host và hoạt động trên hầu hết các môi trường.
💡 Khuyến nghị: Trong khóa học này, chúng ta sẽ ưu tiên sử dụng php artisan serve để đảm bảo mọi học viên đều thực hiện giống nhau, dù đang dùng Laragon, XAMPP, WAMP hay các môi trường phát triển khác.
Ví dụ:
<?php
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});
GET là phương thức dùng để lấy dữ liệu hoặc hiển thị trang.
Ví dụ:
Route::get('/about', function () {
return 'Trang giới thiệu';
});
Truy cập:
http://127.0.0.1:8000/about
Kết quả:
Trang giới thiệu
POST dùng để gửi dữ liệu lên máy chủ.
Ví dụ:
Route::post('/save', function () {
return 'Đã lưu dữ liệu';
});
POST thường được sử dụng khi:
Đăng nhập
Đăng ký
Gửi biểu mẫu
Tạo dữ liệu mới
PUT dùng để cập nhật toàn bộ dữ liệu.
Ví dụ:
Route::put('/user', function () {
return 'Cập nhật người dùng';
});
Trong Laravel, PUT thường dùng để cập nhật bản ghi.
DELETE dùng để xóa dữ liệu.
Ví dụ:
Route::delete('/user', function () {
return 'Đã xóa';
});
Thông thường sẽ dùng trong chức năng:
Xóa bài viết
Xóa sản phẩm
Xóa người dùng
Laravel cho phép truyền dữ liệu trực tiếp trên URL.
Ví dụ:
Route::get('/user/{id}', function ($id) {
return "User ID: $id";
});
Truy cập:
/user/10
Kết quả:
User ID: 10
Có thể truyền nhiều tham số:
Route::get('/product/{category}/{id}', function ($category, $id) {
return "$category - $id";
});
Ví dụ:
/product/phone/25
Kết quả:
phone - 25
Đặt dấu ? sau tên tham số:
Route::get('/hello/{name?}', function ($name = 'Guest') {
return "Hello $name";
});
Nếu truy cập:
/hello
Kết quả:
Hello Guest
Nếu truy cập:
/hello/Laravel
Kết quả:
Hello Laravel
Laravel cho phép đặt tên cho Route để sử dụng thuận tiện hơn.
Ví dụ:
Route::get('/dashboard', function () {
return 'Dashboard';
})->name('dashboard');
Lấy URL bằng:
route('dashboard');
Kết quả:
http://localhost:8000/dashboard
Ưu điểm:
Không cần ghi cứng URL.
Dễ bảo trì khi thay đổi đường dẫn.
Thường dùng trong Blade và Controller.
Laravel hỗ trợ lệnh Artisan để xem toàn bộ Route.
php artisan route:list
Ví dụ kết quả:
GET /
GET /about
POST /save
PUT /user
DELETE /user
Đây là lệnh rất hữu ích khi dự án có nhiều Route.
Không khai báo hai Route trùng URL và cùng phương thức.
Nên đặt tên Route cho các chức năng quan trọng.
Mỗi Route nên thực hiện một nhiệm vụ rõ ràng.
Khi dự án lớn, nên chuyển logic sang Controller thay vì viết trực tiếp trong Route.
Sau bài học này, bạn đã nắm được những kiến thức nền tảng về Routing trong Laravel:
✅ Hiểu vai trò của Routing trong ứng dụng Laravel.
✅ Biết cách khai báo Route trong routes/web.php.
✅ Sử dụng các phương thức GET, POST, PUT và DELETE.
✅ Truyền tham số qua URL bằng Route Parameters.
✅ Tạo Named Route để quản lý đường dẫn hiệu quả.
✅ Kiểm tra toàn bộ Route bằng lệnh php artisan route:list.
Trong bài tiếp theo, chúng ta sẽ chuyển sang Controller, nơi chứa toàn bộ logic xử lý của ứng dụng và giúp mã nguồn trở nên gọn gàng, dễ bảo trì hơn.
╭──────────────────────────────╮
│ 🤖 Made by AI • Precision & Logic │
╰──────────────────────────────╯
x1
Cập nhật: 2026-07-08T12:08:04.807+07:00
Mục tiêu bài học
Sau bài này, bạn sẽ:
✅ Cài đặt đầy đủ môi trường phát triển Laravel.
✅ Hiểu vai trò của Composer và Laravel Installer.
✅ Tạo dự án Laravel đầu tiên.
✅ Khởi chạy ứng dụng bằng Artisan.
✅ Cấu hình Visual Studio Code để lập trình hiệu quả.
Trước khi cài Laravel, hãy đảm bảo máy tính của bạn đã có các thành phần sau:
| 🔢 | 🛠️ Thành phần | 📌 Phiên bản khuyến nghị |
|---|---|---|
| 1️⃣ | 🐘 PHP | 8.2 trở lên |
| 2️⃣ | 📦 Composer | Phiên bản mới nhất |
| 3️⃣ | 🗄️ MySQL hoặc MariaDB | Phiên bản hiện hành |
| 4️⃣ | 📝 Visual Studio Code | Mới nhất |
| 5️⃣ | 🌐 Trình duyệt | Edge, Chrome hoặc Firefox |
💡 Nếu bạn đã hoàn thành khóa PHP Core, rất có thể các công cụ trên đã được cài đặt sẵn.
Composer là trình quản lý thư viện (Dependency Manager) của PHP.
Laravel sử dụng Composer để:
📥 Cài đặt Framework
🔄 Cập nhật thư viện
📚 Quản lý các package
⚙️ Tự động nạp (Autoload)
Kiểm tra Composer:
composer --version
Nếu hiển thị phiên bản, nghĩa là Composer đã sẵn sàng.
Ví dụ:
Composer version 2.x.x
Ngoài cách tạo dự án trực tiếp bằng Composer, Laravel còn cung cấp Laravel Installer.
Cài đặt:
composer global require laravel/installer
Sau khi cài thành công:
laravel --version
Ví dụ:
Laravel Installer 6.x
Có hai cách phổ biến.
composer create-project laravel/laravel blog
Sau vài phút, Composer sẽ tải toàn bộ thư viện cần thiết.
laravel new blog
Laravel Installer sẽ tự động tạo cấu trúc dự án hoàn chỉnh.
Ví dụ:
blog/
│
├── app/
├── bootstrap/
├── config/
├── database/
├── public/
├── resources/
├── routes/
├── storage/
├── vendor/
├── .env
├── artisan
└── composer.json
Đừng lo nếu bạn chưa hiểu hết các thư mục này. Chúng ta sẽ tìm hiểu chi tiết ở các bài tiếp theo.
Di chuyển vào thư mục dự án:
cd blog
Khởi động máy chủ phát triển:
php artisan serve
Nếu thành công, màn hình sẽ hiển thị:
INFO Server running on http://127.0.0.1:8000
Mở trình duyệt và truy cập:
http://127.0.0.1:8000
Nếu thấy trang chào mừng của Laravel, bạn đã cài đặt thành công.
Artisan là công cụ dòng lệnh tích hợp trong Laravel.
Một số lệnh thường dùng:
| 🔢 | 💻 Lệnh | 📖 Chức năng |
|---|---|---|
| 1️⃣ | php artisan serve | Khởi động máy chủ phát triển |
| 2️⃣ | php artisan list | Hiển thị tất cả lệnh |
| 3️⃣ | php artisan help | Xem hướng dẫn |
| 4️⃣ | php artisan about | Thông tin dự án |
| 5️⃣ | php artisan optimize:clear | Xóa cache của ứng dụng |
Ví dụ:
php artisan about
Lệnh này hiển thị thông tin như:
Phiên bản Laravel
Phiên bản PHP
Driver cơ sở dữ liệu
Cache
Queue
Hệ điều hành
Đây là một lệnh rất hữu ích khi kiểm tra môi trường làm việc.
Di chuyển vào thư mục dự án:
cd blog
Mở VS Code:
code .
Nếu lệnh code chưa hoạt động, hãy bật tính năng thêm VS Code vào biến môi trường (PATH) theo hướng dẫn của Visual Studio Code.
Để lập trình Laravel thuận tiện hơn, bạn nên cài một số tiện ích mở rộng:
| 🔢 | 🧩 Extension | 💖 Lợi ích |
|---|---|---|
| 1️⃣ | PHP Intelephense | Gợi ý mã và kiểm tra lỗi PHP |
| 2️⃣ | Laravel Extra Intellisense | Hỗ trợ nhận diện các thành phần của Laravel |
| 3️⃣ | DotENV | Tô màu và hỗ trợ tệp .env |
| 4️⃣ | Error Lens | Hiển thị lỗi trực tiếp trong mã nguồn |
| 5️⃣ | EditorConfig | Đồng bộ định dạng mã nguồn |
Trong quá trình học, bạn sẽ thường xuyên làm việc với:
| 🔢 | 📄 Tệp | 📖 Vai trò |
|---|---|---|
| 1️⃣ | .env | Cấu hình môi trường |
| 2️⃣ | composer.json | Quản lý thư viện |
| 3️⃣ | artisan | Điểm vào của Artisan CLI |
| 4️⃣ | routes/web.php | Khai báo Route |
| 5️⃣ | resources/views | Chứa giao diện Blade |
composer is not recognized...
📌 Nguyên nhân:
Composer chưa được cài đặt.
Chưa thêm Composer vào biến môi trường (PATH).
php is not recognized...
📌 Nguyên nhân:
PHP chưa được thêm vào PATH.
Nếu cổng mặc định đã có ứng dụng khác sử dụng, bạn có thể chạy:
php artisan serve --port=8080
Sau đó truy cập:
http://127.0.0.1:8080
📂 Đặt tất cả dự án Laravel trong một thư mục riêng (ví dụ: Projects hoặc Workspace) để dễ quản lý.
🧾 Không chỉnh sửa thư mục vendor vì đây là mã nguồn do Composer quản lý.
🔄 Sau khi thay đổi thư viện, chạy composer install hoặc composer update theo nhu cầu.
📖 Thường xuyên dùng php artisan about để kiểm tra trạng thái môi trường.
| 🔢 | 📚 Nội dung | ✅ Ghi nhớ |
|---|---|---|
| 1️⃣ | 📦 Composer | Quản lý thư viện PHP |
| 2️⃣ | 🚀 Laravel Installer | Công cụ tạo dự án nhanh |
| 3️⃣ | 📁 laravel new | Tạo dự án bằng Installer |
| 4️⃣ | ⚙️ composer create-project | Tạo dự án bằng Composer |
| 5️⃣ | ▶️ php artisan serve | Chạy máy chủ phát triển |
| 6️⃣ | 🛠️ Artisan CLI | Công cụ dòng lệnh của Laravel |
| 7️⃣ | 📝 VS Code | Môi trường phát triển được khuyến nghị |
Đến đây, bạn đã hoàn thành việc chuẩn bị môi trường để phát triển ứng dụng với Laravel 12. Bạn đã biết cách tạo dự án mới bằng Composer hoặc Laravel Installer, khởi động máy chủ phát triển bằng Artisan, đồng thời thiết lập Visual Studio Code để sẵn sàng viết mã.
➡️ Ở bài tiếp theo, chúng ta sẽ tìm hiểu Routing — cơ chế định tuyến của Laravel, học cách xử lý các yêu cầu HTTP như GET, POST, PUT, DELETE, làm việc với Route Parameters và Named Routes, nền tảng cho mọi ứng dụng Laravel.
x1
Cập nhật: 2026-07-07T10:40:20.930+07:00
Mục tiêu bài học
Sau bài này, bạn sẽ:
✅ Hiểu Laravel là gì và tại sao nó được tạo ra.
✅ Biết mô hình MVC trong Laravel.
✅ Hiểu vai trò của Composer.
✅ Làm quen với Artisan CLI.
✅ Nắm được cấu trúc thư mục của một dự án Laravel.
Laravel là 01 PHP Framework mã nguồn mở được xây dựng để giúp lập trình viên phát triển các ứng dụng web nhanh hơn, dễ bảo trì hơn và an toàn hơn.
Laravel cung cấp sẵn rất nhiều thành phần cần thiết cho một website hiện đại như:
🛣️ Routing
🗄️ ORM (Eloquent)
🔐 Authentication
📝 Template Engine (Blade)
📂 Upload File
⚡ Queue
📦 Cache
🌐 REST API
🧪 Testing
Thay vì phải tự viết mọi thứ từ đầu bằng PHP thuần, Laravel đã chuẩn hóa và đóng gói thành các công cụ mạnh mẽ.
Trước khi Laravel xuất hiện, rất nhiều lập trình viên viết website bằng PHP Core.
Một dự án PHP thuần thường gặp các vấn đề:
❌ Code lặp lại nhiều.
❌ Khó bảo trì khi dự án lớn.
❌ Không có cấu trúc thống nhất.
❌ Tự viết đăng nhập, phân quyền, upload...
❌ Dễ phát sinh lỗi bảo mật nếu không cẩn thận.
Laravel ra đời để giải quyết những hạn chế đó.
| 🔢 | ⭐ Tính năng | 📖 Mô tả |
|---|---|---|
| 1️⃣ | 🗂️ Cấu trúc rõ ràng | Tổ chức mã nguồn theo chuẩn MVC |
| 2️⃣ | ⚡ Phát triển nhanh | Nhiều tính năng có sẵn |
| 3️⃣ | 🔒 Bảo mật | Hỗ trợ CSRF, XSS, Hash Password, Validation... |
| 4️⃣ | 🗄️ Eloquent ORM | Làm việc với cơ sở dữ liệu bằng đối tượng |
| 5️⃣ | 🎨 Blade Template | Tách giao diện khỏi xử lý nghiệp vụ |
| 6️⃣ | 📦 Composer | Quản lý thư viện dễ dàng |
| 7️⃣ | 🛠️ Artisan CLI | Sinh mã nguồn và quản lý dự án bằng dòng lệnh |
| 8️⃣ | 🌍 Cộng đồng lớn | Nhiều tài liệu và gói mở rộng |
Một yêu cầu từ trình duyệt sẽ đi qua các bước sau:
Người dùng
│
▼
Route
│
▼
Controller
│
▼
Model
│
▼
Database
│
▼
Controller
│
▼
Blade View
│
▼
Trình duyệt
Đây chính là cách Laravel triển khai mô hình MVC.
MVC là viết tắt của:
Model
View
Controller
Ba thành phần này giúp tách biệt dữ liệu, giao diện và xử lý nghiệp vụ.
Model chịu trách nhiệm làm việc với cơ sở dữ liệu.
Ví dụ:
Lấy danh sách sản phẩm
Thêm người dùng
Cập nhật bài viết
Xóa dữ liệu
Ví dụ:
User::all();
View là phần giao diện người dùng.
Laravel sử dụng Blade Template Engine.
Ví dụ:
<h1>Xin chào Laravel</h1>
View chỉ hiển thị dữ liệu, không xử lý nghiệp vụ.
Controller là nơi nhận yêu cầu từ người dùng.
Nó sẽ:
nhận Request
gọi Model
xử lý dữ liệu
trả về View
Ví dụ:
public function index()
{
return view('home');
}
Browser
│
▼
Route
│
▼
Controller
│
▼
Model
│
Database
│
▼
Controller
│
▼
View
│
Browser
Nhờ cách tổ chức này, dự án dễ mở rộng và bảo trì hơn.
Composer là trình quản lý thư viện (Dependency Manager) dành cho PHP.
Nó giúp:
📥 Cài đặt thư viện
🔄 Cập nhật thư viện
🗑️ Gỡ bỏ thư viện
🔗 Tự động nạp (Autoload) các lớp
Ví dụ cài Laravel:
composer create-project laravel/laravel myapp
Composer sẽ tự động tải tất cả các thư viện mà Laravel cần.
Artisan là công cụ dòng lệnh đi kèm Laravel.
Thay vì tự tạo từng tệp bằng tay, Artisan có thể sinh mã nguồn chỉ với một lệnh.
Ví dụ:
Khởi động máy chủ phát triển:
php artisan serve
Tạo Controller:
php artisan make:controller ProductController
Tạo Model:
php artisan make:model Product
Tạo Migration:
php artisan make:migration create_products_table
Tạo Seeder:
php artisan make:seeder ProductSeeder
Artisan còn hỗ trợ hàng trăm lệnh khác giúp tăng tốc quá trình phát triển.
Sau khi tạo dự án, bạn sẽ thấy cấu trúc tương tự:
app/
bootstrap/
config/
database/
public/
resources/
routes/
storage/
tests/
vendor/
.env
artisan
composer.json
Chứa phần lớn mã nguồn của ứng dụng.
Ví dụ:
Controllers
Models
Middleware
Providers
Định nghĩa các tuyến đường (Route).
Các tệp phổ biến:
web.php
api.php
console.php
Chứa tài nguyên của dự án.
Bao gồm:
Blade View
CSS
JavaScript
Hình ảnh (tùy cấu hình dự án)
Đây là thư mục truy cập từ trình duyệt.
Thường chứa:
index.php
favicon
ảnh công khai
tệp CSS và JavaScript sau khi build
Chứa các tệp liên quan đến cơ sở dữ liệu:
Migration
Seeder
Factory
Lưu trữ dữ liệu phát sinh trong quá trình chạy:
Log
Cache
Session
Tệp người dùng tải lên (tùy cấu hình)
Đây là nơi Composer cài đặt toàn bộ thư viện phụ thuộc.
⚠️ Không nên chỉnh sửa trực tiếp các tệp trong thư mục này.
Lưu cấu hình của ứng dụng, ví dụ:
Kết nối cơ sở dữ liệu
Khóa ứng dụng
Cache
Queue
Tệp này thường không được đưa lên kho mã nguồn công khai.
| 🔢 | 📚 Nội dung | ✅ Ghi nhớ |
|---|---|---|
| 1️⃣ | 🌱 Laravel | Framework PHP hiện đại để phát triển ứng dụng web |
| 2️⃣ | 🏗️ MVC | Tách Model, View và Controller |
| 3️⃣ | 📦 Composer | Quản lý thư viện và tự động nạp lớp |
| 4️⃣ | ⚙️ Artisan | Công cụ dòng lệnh hỗ trợ phát triển |
| 5️⃣ | 📁 Cấu trúc thư mục | Mỗi thư mục đảm nhiệm một vai trò riêng |
Laravel giúp quá trình phát triển ứng dụng web trở nên nhanh hơn, có cấu trúc hơn và dễ bảo trì hơn so với việc xây dựng hoàn toàn bằng PHP thuần. Việc hiểu rõ các khái niệm nền tảng như MVC, Composer, Artisan và cấu trúc thư mục sẽ giúp bạn tiếp cận những bài học tiếp theo một cách thuận lợi.
➡️ Ở bài tiếp theo, chúng ta sẽ cài đặt Laravel 12, thiết lập môi trường làm việc và chạy ứng dụng đầu tiên trên máy tính.
Cập nhật: 2026-07-06T10:07:54.240+07:00
Nếu cập nhật theo Laravel 12 LTS (2026) thì mình sẽ chia thành các phần như sau để người học đi từ PHP Core → Laravel → Triển khai dự án thực tế.
Tiếp nối khóa "PHP Core 8.2 — Tự học PHP từ ZERO đến làm web động"
Vì sao Laravel ra đời
MVC trong Laravel
Composer
Artisan CLI
Cấu trúc thư mục
Composer
Laravel Installer
laravel new
php artisan serve
Cấu hình VS Code
routes/web.php
GET
POST
PUT
DELETE
Route Parameters
Named Route
Tạo Controller
Action
Resource Controller
Truyền dữ liệu
Blade
Layout
Include
Section
Yield
Component
.env
MySQL
php artisan migrate
Tạo bảng
Kiểu dữ liệu
foreignId
rollback
Seeder
Faker
DatabaseSeeder
Factory
Fake Data
Model
Table
Fillable
Guarded
Bài 11 — CRUD bằng Eloquent
create()
all()
find()
update()
delete()
Bài 12 — Query Builder
where
orWhere
orderBy
latest
paginate
Bài 13 — One To One
Bài 14 — One To Many
Bài 15 — Many To Many
Bài 16 — Has Many Through
Bài 17 — Polymorphic
Bài 18 — Request
Bài 19 — Validation
Bài 20 — Upload File
Bài 21 — Laravel Breeze
Bài 22 — Login
Bài 23 — Register
Bài 24 — Middleware
Bài 25 — Authorization
Bài 26 — CRUD Posts
Bài 27 — CRUD Categories
Bài 28 — CRUD Users
Bài 29 — Search
Bài 30 — Pagination
Bài 31 — Soft Delete
Bài 32 — Accessor & Mutator
Bài 33 — Scope
Bài 34 — Observer
Bài 35 — Event & Listener
Bài 36 — Queue
Bài 37 — Mail
Bài 38 — Notification
Bài 39 — Cache
Bài 40 — Storage
Bài 41 — REST API
Bài 42 — API Resource
Bài 43 — Sanctum
Bài 44 — API Authentication
Bài 45 — Deploy Shared Hosting
Bài 46 — Deploy VPS
Bài 47 — Nginx
Bài 48 — Queue Worker
Bài 49 — Scheduler
Bài 50 — Production Tips
Login
Dashboard
CRUD Posts
CRUD Categories
Upload Image
Search
Pagination
Soft Delete
Roles
Permissions
REST API
✅ Thành thạo Laravel 12
✅ Hiểu Eloquent ORM
✅ Biết Authentication hiện đại (Breeze)
✅ Viết REST API chuẩn
✅ Deploy lên VPS/Hosting
✅ Đọc và bảo trì source Laravel thực tế
✅ Đủ nền tảng để học tiếp:
Livewire 3
Inertia.js
Vue.js
React
Filament
Docker
CI/CD
Microservices
Đây là lộ trình khoảng 50 bài, rất phù hợp để tiếp nối ngay sau khóa 35 bài PHP Core.
Tổng cộng khoảng 85 bài sẽ đưa người học từ ZERO → PHP Developer → Laravel Developer theo đúng xu hướng năm 2026.
Cập nhật: 2026-07-16T20:46:59.695+07:00
Trong ví dụ này, chúng ta xây dựng một ứng dụng PHP theo mô hình MVC (Model - View - Controller) mà không sử dụng framework.
project/
│
├── app/
│ ├── controllers/
│ │ └── ProductController.php
│ │
│ ├── models/
│ │ └── ProductModel.php
│ │
│ └── views/
│ └── home.php
│
├── config/
│ └── Database.php
│
└── public/
└── index.php
File:
config/Database.php
<?php
class Database
{
public static function connect()
{
return mysqli_connect(
"localhost",
"root",
"",
"shop_dienthoai"
);
}
}
Kết nối MySQL.
Trả về đối tượng kết nối.
Các Model sẽ dùng chung class này.
phpMyadmin tạo database shop_dienthoai trước.-- Tạo database
CREATE DATABASE IF NOT EXISTS shop_dienthoai
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
-- Chọn database
USE shop_dienthoai;
-- Tạo bảng products
CREATE TABLE products (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL
);
-- Dữ liệu mẫu
INSERT INTO products (name) VALUES
('iPhone 16 Pro Max'),
('Samsung Galaxy S25 Ultra'),
('Xiaomi 15 Pro'),
('OPPO Find X8 Pro'),
('Google Pixel 10');
File:
app/models/ProductModel.php
<?php
class ProductModel
{
private $conn;
public function __construct()
{
$this->conn = Database::connect();
}
public function getAll()
{
$result = mysqli_query($this->conn, "SELECT * FROM products");
$products = [];
while ($row = mysqli_fetch_assoc($result)) {
$products[] = $row;
}
return $products;
}
}
Model chỉ làm việc với dữ liệu.
Trong ví dụ trên:
Kết nối database.
Thực hiện câu lệnh SQL.
Trả về mảng sản phẩm.
Model không hiển thị HTML và không xử lý giao diện.
File:
app/controllers/ProductController.php
<?php
class ProductController
{
public function index()
{
$model = new ProductModel();
$products = $model->getAll();
include ROOT . "/app/views/home.php";
}
}
Controller là trung gian giữa Model và View.
Quy trình:
Tạo Model.
Gọi Model lấy dữ liệu.
Đưa dữ liệu sang View.
View hiển thị kết quả.
Controller không viết SQL và không tạo HTML.
File:
app/views/home.php
<h1>Danh sách sản phẩm</h1>
<?php foreach($products as $row): ?>
<p><?= $row["name"] ?></p>
<?php endforeach; ?>
View chỉ nhận dữ liệu từ Controller rồi hiển thị.
Trong ví dụ này:
Không kết nối database.
Không chạy SQL.
Chỉ lặp mảng $products.
File:
public/index.php
<?php
define('ROOT', dirname(__DIR__));
require_once ROOT . '/config/Database.php';
require_once ROOT . '/app/models/ProductModel.php';
require_once ROOT . '/app/controllers/ProductController.php';
$controller = new ProductController();
$controller->index();
Đây là điểm bắt đầu của toàn bộ ứng dụng.
Nó thực hiện:
Khai báo hằng số ROOT.
Nạp các class cần thiết.
Khởi tạo Controller.
Gọi action index().
Trình duyệt
│
▼
public/index.php
│
▼
ProductController
│
▼
ProductModel
│
▼
Database
│
▼
MySQL
│
▼
ProductModel
│
▼
ProductController
│
▼
View (home.php)
│
▼
Hiển thị HTML
| Thành phần | Chức năng |
|---|---|
| Database | Kết nối MySQL |
| Model | Xử lý dữ liệu |
| Controller | Điều phối chương trình |
| View | Hiển thị giao diện |
| index.php | Điểm vào của ứng dụng |
Tách biệt giao diện và dữ liệu.
Code dễ đọc.
Dễ bảo trì.
Có thể mở rộng thành Router.
Dễ chuyển sang Framework như Laravel hoặc CodeIgniter.
require_onceTrong ví dụ trên, tất cả các class được nạp thủ công bằng:
require_once ...
Cách này phù hợp với dự án nhỏ, nhưng khi số lượng Controller và Model tăng lên sẽ phát sinh một số bất tiện:
Phải tự thêm require_once mỗi khi tạo class mới.
Nếu đổi tên file hoặc namespace thì phải sửa nhiều nơi.
Một số môi trường (đặc biệt khi dùng OPcache hoặc cấu hình Apache) có thể khiến việc đổi tên file, thêm class hoặc thay đổi đường dẫn chưa được nhận ngay, dẫn đến cảm giác phải Reload/Restart Apache mới hoạt động đúng.
Trong các dự án lớn, người ta thường sử dụng Autoload (ví dụ spl_autoload_register() hoặc Composer PSR-4) để PHP tự động nạp class khi cần. Khi đó, gần như không còn phải viết require_once cho từng Controller hoặc Model nữa và việc phát triển trở nên thuận tiện hơn rất nhiều.
p/S: xem thêm MVC viết theo phong cách API tại đây.
(chỉ cần link API là phần view lấy được dữ liệu dù bất kỳ ngôn ngữ nào)
Cập nhật: 2026-07-04T22:15:50.011+07:00
Sau khi đã học xong toàn bộ kiến thức PHP cơ bản, CRUD MySQL, OOP và mô hình MVC, bạn đã có nền tảng rất tốt để bước sang một Framework chuyên nghiệp.
Framework phổ biến nhất hiện nay trong cộng đồng PHP chính là Laravel.
Laravel là 01 PHP Framework mã nguồn mở giúp lập trình viên xây dựng website và ứng dụng web nhanh hơn, gọn hơn và bảo trì dễ hơn.
Thay vì tự viết mọi thứ từ đầu, Laravel đã chuẩn bị sẵn rất nhiều công cụ mạnh mẽ.
Ví dụ:
✅ Routing
✅ MVC
✅ Authentication
✅ ORM (Eloquent)
✅ Migration
✅ Validation
✅ Session
✅ Cache
✅ Queue
✅ API
...
Laravel giúp lập trình viên tập trung vào nghiệp vụ thay vì phải xây dựng lại những chức năng cơ bản.
Laravel?Nếu chỉ dùng PHP thuần, một dự án lớn sẽ gặp nhiều khó khăn:
❌ Code lặp lại
❌ Khó bảo trì
❌ Khó mở rộng
❌ Dễ phát sinh lỗi
Laravel giải quyết hầu hết các vấn đề này.
Ưu điểm:
✅ Code sạch
✅ Cấu trúc rõ ràng
✅ Bảo mật tốt
✅ Tốc độ phát triển nhanh
✅ Cộng đồng rất lớn
✅ Tài liệu đầy đủ
Laravel hoạt động theo MVCTrong bài trước chúng ta đã học MVC.
Laravel cũng sử dụng mô hình này.
Request
↓
Route
↓
Controller
↓
Model
↓
Database
↓
View
↓
Response
Mọi thành phần đều được tổ chức rất khoa học.
LaravelMột project Laravel thường có:
app/
bootstrap/
config/
database/
public/
resources/
routes/
storage/
tests/
vendor/
Trong đó:
app/
Chứa:
Controller
Model
Logic xử lý
resources/views
Chứa giao diện.
routes
Chứa các URL.
public
Là thư mục web server truy cập.
Laravel sử dụng ComposerKhác với PHP thuần, Laravel được cài bằng Composer.
Ví dụ:
composer create-project laravel/laravel demo
Composer sẽ tự động tải:
Framework
Thư viện
Dependency
Không cần tải thủ công.
Laravel có một công cụ cực mạnh:
php artisan
Ví dụ:
Tạo Controller
php artisan make:controller ProductController
Tạo Model
php artisan make:model Product
Tạo Migration
php artisan make:migration
Chạy server
php artisan serve
Laravel sẽ tự tạo rất nhiều mã nguồn chỉ bằng một câu lệnh.
Nếu PHP thuần:
SELECT * FROM users
Laravel:
User::all();
Hoặc:
User::find(5);
Hoặc:
User::where("age", ">", 18)->get();
Không cần viết SQL trong rất nhiều trường hợp.
PHP thuần:
if(...)
trim()
filter_var()
Laravel:
$request->validate([
"name"=>"required",
"email"=>"required|email"
]);
Ngắn gọn hơn rất nhiều.
Laravel có thể tạo:
Đăng nhập
Đăng ký
Quên mật khẩu
Reset Password
Xác thực Email
Phân quyền
một cách rất nhanh.
PHP thuần:
product.php?id=10
Laravel:
Route::get("/products", ...);
Đường dẫn đẹp và dễ quản lý hơn.
Laravel có hệ thống giao diện riêng:
Blade.
Ví dụ:
<h1>{{ $title }}</h1>
Điều kiện:
@if($age>=18)
@endif
Vòng lặp:
@foreach($users as $user)
@endforeach
Viết giao diện rất gọn.
Laravel được dùng ở đâu?Laravel thường được sử dụng để xây dựng:
Website doanh nghiệp
Website thương mại điện tử
Blog
CRM
ERP
Quản lý bán hàng
Quản lý nhân sự
API
Hệ thống quản trị
SaaS
Dashboard
Laravel?Có.
Laravel không thay thế PHP.
Laravel được xây dựng trên nền PHP.
Muốn học Laravel tốt, bạn nên nắm chắc:
✅ Biến
✅ Hàm
✅ Mảng
✅ OOP
✅ MVC
✅ Form
✅ Session
✅ Cookie
✅ CRUD
✅ MySQL
Những kiến thức đó chính là nền tảng của Laravel.
Lộ trình gợi ý:
PHP Core
↓
MySQL
↓
OOP
↓
MVC
↓
Laravel
↓
REST API
↓
Authentication
↓
Deployment
↓
Dự án thực tế
Đây là con đường phổ biến của nhiều lập trình viên PHP.
Qua bài học này, bạn đã biết:
✅ Laravel là gì
✅ Vì sao Laravel được sử dụng rộng rãi
✅ Mô hình MVC trong Laravel
✅ Composer và Artisan
✅ Eloquent ORM
✅ Blade Template
✅ Routing
✅ Validation
✅ Authentication
Đến đây, bạn đã hoàn thành chặng đường PHP Core 8.2 – Cấp độ Trứng 🥚.
Với nền tảng này, bạn có thể tự xây dựng các website động bằng PHP, làm việc với cơ sở dữ liệu MySQL và sẵn sàng bước sang thế giới của các framework hiện đại như Laravel, cũng như tiếp tục khám phá WordPress, Flarum hoặc phát triển các dự án web thực tế.
x1
Cập nhật: 2026-07-04T11:01:42.907+07:00
Ở những bài trước, chúng ta đã biết cách:
✅ Kết nối MySQL
✅ CRUD dữ liệu
✅ Chia Header / Footer bằng include
✅ Hash mật khẩu
✅ Filter dữ liệu
✅ Làm quen với OOP
Website đã chạy được.
Nhưng nếu dự án có hàng trăm file thì sao?
Ví dụ:
Trang chủ
Danh sách sản phẩm
Tin tức
Đăng nhập
Quản lý người dùng
Dashboard
Nếu tất cả đều viết trong một file PHP thì sẽ rất khó bảo trì.
Đó là lý do MVC ra đời.
MVC là viết tắt của:
M → Model
V → View
C → Controller
MVC giúp chia chương trình thành nhiều phần riêng biệt.
Người dùng
│
▼
Controller
│
▼
Model
│
▼
Database
▲
│
View ◄────────────
Mỗi thành phần chỉ làm đúng nhiệm vụ của mình.
Model chịu trách nhiệm làm việc với dữ liệu.
Ví dụ:
Kết nối MySQL
INSERT
UPDATE
DELETE
SELECT
Ví dụ:
class ProductModel
{
public function getAll()
{
return mysqli_query(
$GLOBALS["conn"],
"SELECT * FROM products"
);
}
}
Model KHÔNG hiển thị HTML.
Model chỉ xử lý dữ liệu.
View là giao diện.
Ví dụ:
<h1>Danh sách sản phẩm</h1>
<?php foreach($products as $item): ?>
<p><?= $item["name"] ?></p>
<?php endforeach; ?>
View chỉ hiển thị dữ liệu.
Không nên viết SQL trong View.
❌ Sai:
mysqli_query(...);
Controller là "người điều phối".
Controller nhận request từ người dùng.
Ví dụ:
Người dùng mở:
products.php
Controller sẽ:
↓
gọi Model
↓
lấy dữ liệu
↓
đưa sang View
↓
hiển thị
Ví dụ:
$model = new ProductModel();
$products = $model->getAll();
include "views/products.php";
Browser
↓
Controller
↓
Model
↓
Database
↓
Model
↓
Controller
↓
View
↓
Browser
Đây là quy trình hoạt động của hầu hết framework hiện đại.
Ví dụ:
project/
controllers/
models/
views/
config/
public/
index.php
Trong đó:
controllers/
Chứa Controller.
models/
Chứa Model.
views/
Chứa giao diện.
config/
File cấu hình.
public/
CSS
JS
Image
controllers/
HomeController.php
models/
Product.php
views/
home.php
Controller:
require "models/Product.php";
$model = new Product();
$data = $model->all();
include "views/home.php";
Model:
class Product
{
public function all()
{
return mysqli_query(
$GLOBALS["conn"],
"SELECT * FROM products"
);
}
}
View:
<?php foreach($data as $row): ?>
<p><?= $row["name"] ?></p>
<?php endforeach; ?>
Mỗi phần đều có nhiệm vụ riêng.
✅ Code gọn gàng
✅ Dễ mở rộng
✅ Dễ bảo trì
✅ Dễ làm việc nhóm
✅ Không trùng lặp code
✅ Tách giao diện và xử lý dữ liệu
PHP
↓
HTML
↓
SQL
↓
PHP
↓
HTML
↓
SQL
Mọi thứ lẫn vào nhau.
Sau vài nghìn dòng code sẽ rất khó sửa.
Controller
↓
Model
↓
Database
↓
Controller
↓
View
Mỗi file làm đúng một nhiệm vụ.
Không.
Bạn vẫn có thể viết website bằng PHP thuần.
Nhưng khi dự án lớn lên, MVC gần như là lựa chọn tiêu chuẩn để quản lý mã nguồn hiệu quả.
Hầu hết framework PHP nổi tiếng đều sử dụng hoặc dựa trên kiến trúc MVC:
Laravel
CodeIgniter
CakePHP
Yii
Phalcon
Nếu hiểu MVC, bạn sẽ học các framework này nhanh hơn rất nhiều.
Sau bài này bạn đã biết:
MVC là gì
Vai trò của Model
Vai trò của View
Vai trò của Controller
Luồng hoạt động của MVC
Lợi ích của việc tách code theo MVC
🎉 Ở bài tiếp theo, chúng ta sẽ bước sang framework PHP phổ biến nhất hiện nay: Laravel, nơi mô hình MVC được áp dụng một cách đầy đủ và mạnh mẽ.
Xem toàn bộ mã nguồn 01 mô hình MVC đơn giản tại đây.
Cập nhật: 2026-07-04T11:21:22.987+07:00