Ở bài trước TaskFlow đã có giao diện với Blade component và Tailwind, nhưng mới chỉ hiển thị dữ liệu. Tiếp tục với series, bài này mình sẽ giới thiệu với mọi người về request và response trong Laravel 13, session, flash data và làm form tạo project.
1. Request trong Laravel.
Request là object chứa toàn bộ thông tin của HTTP request hiện tại: input, query string, header, cookie, file... Đây là object của class Illuminate\Http\Request.
Để lấy request, các bạn khai báo tham số kiểu Request ở closure của route hoặc method của controller, Laravel sẽ tự inject vào như ở Bài 5:
use Illuminate\Http\Request;
Route::get('/search', function (Request $request) {
// dùng $request ở đây
});
2. Lấy dữ liệu input.
Dữ liệu gửi lên từ form hay query string đều lấy qua các method sau:
input('key', $default)lấy giá trị từ form hoặc query string,query('key', $default)chỉ lấy từ query string.all()trả về mảng toàn bộ input,only([...])chỉ lấy các key liệt kê (key không có trong request bị bỏ qua),except([...])lấy tất cả trừ các key liệt kê.has('key')kiểm tra key có trong request không,filled('key')kiểm tra key có và giá trị không rỗng.integer(),boolean(),date()lấy giá trị và ép sang số nguyên,bool(truevới1,"true","on","yes") và object ngày tháng Carbon (nullnếu không có).
VD:
Route::get('/search', function (Request $request) {
return [
'keyword' => $request->input('keyword'),
'page' => $request->integer('page', 1),
'done' => $request->boolean('done'),
'due' => $request->date('due')?->format('d-m-Y'),
'has_status' => $request->has('status'),
'filled_status' => $request->filled('status'),
];
});
// /search?keyword=blade&page=2&done=on&due=2026-12-01&status=
// {"keyword":"blade","page":2,"done":true,"due":"01-12-2026","has_status":true,"filled_status":false}
// /search?keyword=blade
// {"keyword":"blade","page":1,"done":false,"due":null,"has_status":false,"filled_status":false}
status rỗng nên has() trả về true còn filled() trả về false. Mặc định Laravel tự trim chuỗi input và đổi chuỗi rỗng thành null.
Lưu ý: File upload không lấy bằng input() mà bằng $request->file('tên'), cách upload và lưu file mình sẽ nói ở Bài 20.
3. Thông tin URL, method và header.
Request còn cho biết URL, method và header, VD với request sau:
// GET http://localhost:8000/projects/1?tab=tasks, header Accept-Language: vi
$request->path(); // projects/1
$request->url(); // http://localhost:8000/projects/1
$request->fullUrl(); // http://localhost:8000/projects/1?tab=tasks
$request->method(); // GET
$request->is('projects/*'); // true
$request->routeIs('projects.*'); // true
$request->header('Accept-Language'); // vi
$request->header('X-Foo', 'default'); // default
is() so khớp path, routeIs() so khớp tên route, cả hai dùng được ký tự đại diện *. header() trả về null hoặc giá trị mặc định khi không có header đó.
4. Response.
Như ở Bài 3, route hay controller trả về chuỗi thì Laravel tạo response HTML, trả về mảng thì thành JSON, còn view() thì thành trang HTML. Khi cần đổi status code hay thêm header, các bạn dùng hàm response():
Route::get('/hello', function () {
return response('Xin chào TaskFlow', 201)
->header('Content-Type', 'text/plain')
->header('X-App', 'TaskFlow');
});
// HTTP/1.1 201 Created
// Content-Type: text/plain; charset=utf-8
// X-App: TaskFlow
//
// Xin chào TaskFlow
Tham số đầu là nội dung, tham số thứ hai là status code (mặc định 200). Để trả về JSON kèm status, các bạn dùng response()->json(), header Content-Type: application/json được thêm tự động:
return response()->json(['id' => 3, 'name' => 'TaskFlow API'], 201);
// {"id":3,"name":"TaskFlow API"}
Redirect.
Response chuyển hướng (status 302) được tạo bằng các helper sau:
return redirect('/projects'); // đến một URL
return to_route('projects.show', ['id' => 1]); // đến route có tên
return back(); // về trang trước đó
return to_route('projects.index')->with('status', 'Đã lưu!'); // kèm flash data
with() lưu dữ liệu vào session dưới dạng flash data, mình giải thích ngay ở phần sau.
5. Session và flash data.
HTTP không lưu trạng thái giữa các request, session giúp lưu thông tin của người dùng qua nhiều request. Mặc định Laravel 13 lưu session trong database (bảng sessions được tạo khi cài đặt ở Bài 2), đổi được bằng biến SESSION_DRIVER trong .env.
Các bạn làm việc với session qua $request->session() hoặc helper session(), hai cách tương đương:
Route::get('/counter', function (Request $request) {
$count = $request->session()->get('count', 0) + 1; // lấy, kèm giá trị mặc định
$request->session()->put('count', $count); // lưu
return 'Lần truy cập thứ '.session('count');
});
// lần 1: Lần truy cập thứ 1
// lần 2: Lần truy cập thứ 2
session(['theme' => 'dark']); // lưu, giống put()
session('theme', 'light'); // dark, giống get()
session()->forget('theme'); // xóa
session()->flash('status', 'Đã lưu!'); // flash data
Flash data chỉ tồn tại đến hết request kế tiếp rồi tự xóa, hợp cho các thông báo kiểu "Đã lưu!" sau khi redirect. Tương tự, withInput() flash toàn bộ input để ở request sau hàm old('tên') lấy lại giá trị đã nhập khi quay lại form.
6. Form tạo project cho TaskFlow.
Route projects.create (GET /projects/create) và projects.store (POST /projects) đã có từ resource controller ở Bài 5, chỉ cần viết view và hai method tương ứng.
- resources/views/projects/create.blade.php
<x-layout title="Tạo project">
<h1 class="mb-4 text-2xl font-bold">Tạo project</h1>
@if (session('error'))
<x-alert type="error" class="mb-4">{{ session('error') }}</x-alert>
@endif
<form method="POST" action="{{ route('projects.store') }}" class="space-y-4">
@csrf
<input type="text" name="name" value="{{ old('name') }}" placeholder="Tên project" class="w-full rounded border p-2">
<textarea name="description" placeholder="Mô tả" class="w-full rounded border p-2">{{ old('description') }}</textarea>
<button type="submit" class="rounded bg-blue-600 px-4 py-2 text-white">Tạo project</button>
</form>
</x-layout>
Directive @csrf in ra input ẩn <input type="hidden" name="_token" value="..."> chứa CSRF token. Như đã nói ở Bài 3, form POST thiếu token sẽ nhận lỗi 419, cơ chế chống CSRF mình sẽ nói kỹ ở Bài 9.
Chưa có database (Bài 12), nên mình tạm lưu project mới vào session trong ProjectRepository bằng push() (thêm phần tử vào mảng trong session), mảng mẫu cũ chuyển sang method samples():
- app/Repositories/ProjectRepository.php
public function all(): array
{
// project mẫu + các project vừa tạo được lưu trong session
return array_merge($this->samples(), session('projects', []));
}
public function add(string $name, ?string $description): array
{
$project = [
'id' => count($this->all()) + 1,
'name' => $name,
'description' => $description,
'tasks' => [],
];
session()->push('projects', $project);
return $project;
}
- app/Http/Controllers/ProjectController.php
use Illuminate\Http\RedirectResponse;
public function create(): View
{
return view('projects.create');
}
public function store(Request $request): RedirectResponse
{
// kiểm tra tạm thời, Bài 10 sẽ thay bằng validation
if (! $request->filled('name')) {
return back()
->withInput()
->with('error', 'Các bạn chưa nhập tên project.');
}
$project = $this->projects->add(
$request->input('name'),
$request->input('description'),
);
return to_route('projects.show', ['id' => $project['id']])
->with('status', 'Đã tạo project "'.$project['name'].'".');
}
Mình lấy từng input bằng input() thay vì all(), vì all() chứa cả _token. Cuối cùng thêm vào components/layout.blade.php, ngay đầu thẻ <main>, đoạn hiển thị flash status cho mọi trang:
@if (session('status'))
<x-alert class="mb-4">{{ session('status') }}</x-alert>
@endif
Và link "+ Tạo project" dưới thẻ <h1> của trang danh sách:
- resources/views/projects/index.blade.php
<a href="{{ route('projects.create') }}" class="mb-4 inline-block text-blue-600">+ Tạo project</a>
Lúc này gửi form với tên trống sẽ quay lại form kèm thông báo đỏ, mô tả đã nhập vẫn còn. Nhập tên "Blog cá nhân" sẽ chuyển sang /projects/3 với thông báo "Đã tạo project "Blog cá nhân".", tải lại trang thì thông báo biến mất. Project mới chỉ nằm trong session nên trình duyệt khác không thấy.
7. Lời kết.
Như vậy chúng ta đã tìm hiểu xong request và response trong Laravel 13: đọc input, URL, header, trả về response, JSON, redirect, session và flash data. Các bạn có thể xem thêm tại tài liệu chính thức. Bài sau mình sẽ giới thiệu về middleware, nơi xử lý request trước khi nó đến controller, cùng với cơ chế chống CSRF.
Đăng ký nhận tin.
Chúng tôi chỉ gửi tối đa 2 lần trên 1 tháng. Tuyên bố không spam mail!





0 Comments