Lập trình · 22/09/2026

Học Laravel 13 – Bài 03: Cấu trúc dự án và vòng đời request Laravel 13 qua TaskFlow

Bài 3 — TaskFlow: hiểu nơi đặt code và lần theo một request trước khi xây CRUD. Sau bài cài đặt Laravel 13, bạn đã có skeleton chạy được. Bài này thêm trang /taskflow rất nhỏ để mọi bước có thể quan sát, không cần database nghiệp vụ hay đăng nhập.

Cấu trúc dự án và vòng đời request Laravel 13 qua TaskFlow

Bài 3 — TaskFlow: hiểu nơi đặt code và lần theo một request trước khi xây CRUD. Sau bài cài đặt Laravel 13, bạn đã có skeleton chạy được. Bài này thêm trang /taskflow rất nhỏ để mọi bước có thể quan sát, không cần database nghiệp vụ hay đăng nhập.

1. Đọc project theo nhiệm vụ, không học thuộc mọi thư mục

Mở các file thực tế của project trước khi làm theo một sơ đồ trên mạng. Skeleton dùng trong khóa có cấu hình routing tại bootstrap/app.php; không cần tạo app/Http/Kernel.php chỉ vì thấy một bài hướng dẫn phiên bản cũ nhắc tới nó. Framework vẫn có HTTP kernel nội bộ, nhưng vị trí cấu hình ở ứng dụng đã khác.

Nơi xemCâu hỏi cần trả lời trong TaskFlow
routes/web.phpURL nào dẫn đến trang tổng quan?
resources/viewsHTML nào hiển thị dữ liệu?
app/Http/ControllersSau này logic điều phối request nằm ở đâu?
app/ModelsModel nào đại diện dữ liệu đã lưu?
database/migrationsSchema được thay đổi bằng lịch sử nào?
configỨng dụng đọc tùy chọn vận hành ở đâu?
bootstrap/app.phpRoute, middleware và exception được cấu hình ra sao?
bootstrap/providers.phpProvider của ứng dụng được đăng ký ở đâu?
tests/FeatureHành vi HTTP được kiểm tra như thế nào?
storageLog, compiled view và dữ liệu runtime nằm đâu?

Trong skeleton hiện tại, chưa có routes/api.php. Đó không phải lỗi cài đặt; chưa cần bật API ở bài này. Không sửa vendor để thêm chức năng và không đặt file .env hay database vào public. Web server production phải phục vụ từ public, không phải thư mục gốc project. Xem thêm cấu trúc thư mục chính thức.

2. Một request đi qua những đâu?

GET /taskflow
  → public/index.php
  → Composer autoload + bootstrap/app.php
  → bootstrap framework, providers, middleware
  → router chọn route phù hợp
  → route trả view cùng dữ liệu
  → response đi trở ra qua middleware
  → trình duyệt nhận HTML

Đây là sơ đồ khái quát, không phải thứ tự gọi mọi method nội bộ. Middleware có thể trả response sớm, chẳng hạn chuyển tới trang đăng nhập; khi đó code trong route không chạy. Exception cũng có thể đổi đường xử lý. Provider chuẩn bị các dịch vụ cho ứng dụng; route quyết định xử lý URL cụ thể. Bạn không cần sửa public/index.php để thêm một màn hình mới. Tham khảo request lifecycle của Laravel.

3. Thêm route có tên

Trong routes/web.php, giữ route welcome hiện có và thêm đoạn sau. Nếu file đã import Route thì không lặp dòng use:

use Illuminate\Support\Facades\Route;

Route::get('/taskflow', function () {
    return view('taskflow.overview', [
        'projectName' => 'TaskFlow',
        'milestone' => 'Request lifecycle',
    ]);
})->name('taskflow.overview');

URL là /taskflow, còn taskflow.overview là tên route để tạo URL trong code. Hai giá trị có thể khác nhau. Closure này chỉ truyền hai chuỗi cố định cho view; chưa truy vấn database, chưa kiểm tra quyền và chưa trả danh sách task. Trong bài routing tiếp theo, chúng ta sẽ chuyển trách nhiệm điều phối sang controller khi cần.

4. Tạo view và theo dõi dữ liệu

Tạo resources/views/taskflow/overview.blade.php với nội dung dưới đây. Tên view taskflow.overview ánh xạ đến đường dẫn đó:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>{{ $projectName }}</title>
</head>
<body>
    <main>
        <h1>{{ $projectName }}</h1>
        <p>Milestone: {{ $milestone }}</p>
        <p>No tasks have been loaded yet.</p>
    </main>
</body>
</html>

Hai khóa projectName và milestone từ route trở thành biến trong Blade. Dấu {{ }} escape nội dung trước khi đưa vào HTML; không đổi sang cú pháp xuất HTML thô chỉ để làm mất lỗi hiển thị. Bài này dùng HTML tối thiểu, chưa có asset cần Vite để bạn tập trung vào đường truyền dữ liệu.

php artisan route:list --path=taskflow -v
php artisan serve --host=127.0.0.1 --port=8000

Mở /taskflow và kiểm tra tiêu đề TaskFlow cùng dòng Milestone: Request lifecycle. Route list phải cho thấy GET|HEAD và tên taskflow.overview. Trong DevTools, xem request document thay vì chỉ nhìn trang: status, Content-Type và response body cho biết server thực sự trả gì.

5. Viết kiểm thử cho hành vi, không chỉ kiểm tra có file

Tạo tests/Feature/TaskFlowOverviewTest.php:

<?php

namespace Tests\Feature;

use Tests\TestCase;

class TaskFlowOverviewTest extends TestCase
{
    public function test_overview_passes_data_to_the_expected_view(): void
    {
        $this->get(route('taskflow.overview', absolute: false))
            ->assertOk()
            ->assertViewIs('taskflow.overview')
            ->assertViewHas('projectName', 'TaskFlow')
            ->assertSeeText('Request lifecycle');
    }

    public function test_an_unknown_taskflow_route_returns_not_found(): void
    {
        $this->get('/taskflow/not-a-route')->assertNotFound();
    }

    public function test_overview_rejects_an_unsupported_method(): void
    {
        $this->post('/taskflow')->assertStatus(405);
    }
}
php artisan test --filter=TaskFlowOverviewTest
php artisan test

Test thứ nhất kiểm tra response, tên view, dữ liệu và nội dung. Hai test còn lại phân biệt URL không tồn tại (404) với HTTP method không được route hỗ trợ (405). Laravel bỏ qua kiểm tra CSRF trong môi trường test thông thường; vì thế test POST này không chứng minh một form trình duyệt đã cấu hình CSRF đúng. Phần form và bảo vệ CSRF sẽ có bài riêng.

Feature test chạy qua ứng dụng trong tiến trình test, không cần server Artisan đang mở. Nó không kiểm tra Nginx, DNS hay TLS của production. Muốn xác minh toàn tuyến mạng, vẫn phải truy cập bằng HTTP thực tế. Đây là lý do không dùng một test xanh để kết luận mọi tầng triển khai đều tốt.

6. Chẩn đoán theo điểm đứt của request

  • Không thấy route trong route:list: kiểm tra đúng project, đúng file và cấu hình withRouting. Nếu đã cache route ở local, dùng route:clear rồi kiểm tra lại.
  • View not found: kiểm tra tên thư mục, dấu chấm trong view name và phần mở rộng .blade.php; chú ý phân biệt hoa thường khi chuyển sang Linux.
  • Undefined variable: so tên khóa truyền từ route với biến trong view, không sửa bằng cách tắt báo lỗi.
  • 404: so path, method và route table trước khi nghi database.
  • 500: đọc exception và log; không thêm try/catch trả 200 để che lỗi.
  • Code mới không xuất hiện: kiểm tra URL đang truy cập có đúng server của project vừa sửa không.

7. Bài tập tự kiểm chứng

Đổi milestone thành một giá trị khác và cập nhật kỳ vọng test. Sau đó cố ý đổi tên view sai để quan sát test thất bại, rồi khôi phục. Cuối cùng giải thích bằng lời: file nào chọn URL, file nào nhận dữ liệu, file nào tạo HTML, và tại sao không cần sửa public/index.php.

Điều hướng: Bài 2 — Cài đặt · Lộ trình toàn khóa. Bài tiếp theo chuẩn hóa cấu hình môi trường và logging cho TaskFlow.

Điều hướng khóa học Laravel 13

Bài trước (02) · Bài sau (04) · Mục lục trọn bộ 37 bài

Thảo luận

Bình luận 0

Đăng nhập để bình luận

Bạn cần có tài khoản để tham gia thảo luận và trả lời độc giả khác.

Đăng nhậpĐăng ký

Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.