+3

Tránh thảm họa "Route Not Found": Bí kíp sinh tồn với \Route::has() trong Laravel

Chào anh em Viblo, lại là mình đây!

Chắc hẳn anh em làm Laravel ai cũng từng trải qua cái cảm giác "đứng tim" thế này: Code chạy ngon lành dưới local, đẩy lên Production, sếp vào test thử và... BÙM! Màn hình trắng bóc hoặc trang báo lỗi 500 đỏ lòm với dòng chữ vô tình: RouteNotFoundException: Route [abc.xyz] not defined.

Nguyên nhân thì vô cùng lãng xẹt. Có thể là do bạn tạm thời comment tắt một route trong file web.php vì tính năng đó chưa hoàn thiện, hoặc bạn đang làm việc trong một hệ thống chia module và module đó đang bị disable. Thế nhưng, trong file giao diện (sidebar.blade.php), bạn lại lỡ quên xóa cái dòng gọi hàm {{ route('abc.xyz') }}.

Trong Laravel, hàm route() cực kỳ "cục súc". Chỉ cần bạn gọi tên một route không tồn tại, nó sẽ ném ra Exception và đập chết toàn bộ trang web ngay lập tức thay vì chỉ render ra một cái link rỗng.

Và để cứu rỗi những pha "não cá vàng" đó, Laravel cung cấp cho chúng ta một vị cứu tinh thầm lặng: \Route::has('...').

1. \Route::has() thực chất là gì?

Đúng như tên gọi của nó, \Route::has('tên-route') là một phương thức giúp bạn kiểm tra xem một Named Route (Route đã được đặt tên bằng hàm ->name()) có đang tồn tại trong hệ thống (Route Collection) hay không. Nó sẽ trả về true nếu route tồn tại, và false nếu không.

Lưu ý cực kỳ quan trọng: Hàm này dùng để kiểm tra TÊN ROUTE, chứ không phải kiểm tra URL. Ví dụ, bạn có route: Route::get('/he-thong/quan-ly-user', [UserController::class, 'index'])->name('users.index'); Thì bạn phải kiểm tra Route::has('users.index'), chứ không phải là Route::has('/he-thong/quan-ly-user').

2. "Đất diễn" quen thuộc nhất: Blade Templates

Nơi mà Route::has() tỏa sáng nhất chính là ở tầng View. Thay vì nhắm mắt nhắm mũi gọi hàm route(), một lập trình viên cẩn thận sẽ bọc nó trong một câu điều kiện.

Nếu anh em từng cài các starter kit của Laravel như Breeze hay Jetstream, anh em sẽ thấy ở trang chủ welcome.blade.php, Laravel luôn viết code như thế này:

@if (Route::has('login'))
    <div class="top-right links">
        @auth
            <a href="{{ url('/home') }}">Home</a>
        @else
            <a href="{{ route('login') }}">Login</a>

            @if (Route::has('register'))
                <a href="{{ route('register') }}">Register</a>
            @endif
        @endauth
    </div>
@endif

Phân tích đoạn code trên: Giả sử dự án của bạn là một hệ thống nội bộ, sếp yêu cầu: "Chỉ admin mới được tạo tài khoản cho nhân viên, tắt tính năng tự do đăng ký đi". Bạn chỉ việc vào file web.php và xóa (hoặc comment) cái route tên là register. Lúc này, hàm Route::has('register') sẽ trả về false, và toàn bộ khối HTML chứa nút "Register" sẽ tự động biến mất khỏi màn hình mà không hề gây ra bất kỳ lỗi 500 sập trang nào. Giao diện của bạn trở nên vô cùng linh hoạt!

3. Trợ thủ đắc lực cho các hệ thống Modular / Dynamic Menus

Khi mình xây dựng các hệ thống ERP hay SaaS lớn, sidebar menu thường không được code cứng (hard-code) bằng HTML, mà được render động từ một mảng cấu hình hoặc từ Database.

Có những khách hàng mua gói Premium thì có module "Báo cáo doanh thu" (route: reports.revenue), khách mua gói Basic thì không có module đó (route không được load).

Lúc này, vòng lặp render Menu của mình sẽ dùng Route::has() để làm chốt chặn cuối cùng:

$menus = [
    ['title' => 'Dashboard', 'route' => 'dashboard'],
    ['title' => 'Quản lý Users', 'route' => 'users.index'],
    ['title' => 'Báo cáo doanh thu', 'route' => 'reports.revenue'], // Module này có thể bị tắt
];

// Trong Blade file
<ul class="sidebar">
    @foreach ($menus as $menu)
        {{-- Chỉ hiển thị menu nếu route này thực sự đang tồn tại trong hệ thống --}}
        @if (Route::has($menu['route']))
            <li>
                <a href="{{ route($menu['route']) }}">
                    {{ $menu['title'] }}
                </a>
            </li>
        @endif
    @endforeach
</ul>

Nhờ đoạn code nhỏ này, mình có thể tự do bật/tắt các module ở tầng backend, mà không bao giờ lo lắng việc front-end sẽ render ra những đường link chết (Broken links) hay làm crash ứng dụng.

Lời kết

Trong lập trình, "Phòng bệnh hơn chữa bệnh" luôn là chân lý. Việc sử dụng \Route::has() trước khi render một đường link tuy chỉ tốn thêm của bạn 2 giây gõ phím, nhưng nó thể hiện sự cẩn thận và tư duy "phòng thủ" của một người kỹ sư dày dạn kinh nghiệm. Nó giúp hệ thống của bạn dẻo dai hơn, chống chịu tốt hơn trước những thay đổi về logic hoặc cấu hình.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí