In Laravel, how do you check which named route handled the current request, for example to highlight the active admin menu item?
answer
- request()->routeIs() with wildcards
- Route::currentRouteName() may be null
- Route::is is an alias of currentRouteNamed
- request()->is() checks the path
- no route: checks return false
basics
~10 sUse request()->routeIs('admin.orders.'), which matches the current route's name with * wildcards, or Route::currentRouteName() for the name itself; request()->is('admin/') checks the path instead, and both name checks are false or null when no route matched.
solid answer
~30 sThe request knows its matched route, so `request()->routeIs('admin.orders.*')` returns `true` for `admin.orders.index` and `admin.orders.show`; it accepts several patterns and uses `*` wildcards. The `Route` facade offers the same from the router: `Route::currentRouteName()` returns the name or `null`, `Route::current()` returns the `Illuminate\Routing\Route` or `null`, and `Route::is(...)` is an alias of `Route::currentRouteNamed(...)`. Inside middleware, `$request->route()->named('profile')` works on the route object. Do not confuse these with `request()->is('admin/*')`, which matches the **path**. When no route matched, such as while rendering a 404 for an unknown URL, `routeIs()` returns `false` and `currentRouteName()` returns `null`, while `$request->route()->named()` would fail on `null`.
code
php · 19 lines<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class TagFranchiseArea
{
public function handle(Request $request, Closure $next): Response
{
if ($request->routeIs('admin.*')) {
$request->attributes->set('area', 'admin');
}
return $next($request);
}
}go deeper
Know request()->routeIs() with wildcards and Route::currentRouteName(), and use them for active menu links.
Explain the difference between routeIs() and is(), the aliases on the Route facade, and when the current route is null.
Keep layouts shared with error pages null-safe, and prefer name checks over path checks so URL changes do not break navigation.
Treat route names as an internal contract that navigation, analytics and authorization rely on, and govern renames accordingly.
## Why check the current route Layouts often need to know where the user is: highlight the active menu entry, show a breadcrumb, or skip a banner on checkout pages. Checking the route **name** is sturdier than checking the URL, because names survive URI changes and group prefixes. ## The methods | Call | Returns | Notes | |---|---|---| | `request()->routeIs('admin.orders.*')` | bool | wildcard patterns, several allowed; false when no route | | `Route::currentRouteName()` | string or null | null when the route has no name or nothing matched | | `Route::is('admin.orders.*')` | bool | alias of `Route::currentRouteNamed()` | | `Route::current()` | `Illuminate\Routing\Route` or null | the full route object | | `$request->route()` | route object or null | with an argument, returns a route parameter | | `$request->route()->named('profile')` | bool | the method the docs show in middleware | | `Route::currentRouteAction()` | string or null | `Controller@method` of the current route | All the name checks match patterns with the framework's `Str::is()` rules, so `*` matches any run of characters, including dots. ## Name versus path Two methods look alike and do different things: - **`request()->routeIs('admin.orders.*')`** compares the current route's **name**. - **`request()->is('admin/orders/*')`** compares the **decoded path** of the URL. The name check keeps working if the franchise dashboard moves from `/admin/orders` to `/manage/orders`; the path check silently stops matching. Prefer names wherever routes are named. ## Highlighting the active menu item In a Blade layout, the `@class` directive and `routeIs()` combine neatly: ```html <nav> <a href="{{ route('admin.orders.index') }}" @class(['nav-link', 'active' => request()->routeIs('admin.orders.*')])>Orders</a> <a href="{{ route('admin.stores.index') }}" @class(['nav-link', 'active' => request()->routeIs('admin.stores.*')])>Stores</a> </nav> ``` Each link lights up for every route in its area: the list, a single order, the edit form. ## When there is no current route The router sets its current route only after a successful match. So during: 1. rendering of a 404 page for an unmatched URL, 2. Artisan commands and queued jobs, 3. code that runs in global middleware before matching, `Route::current()` and `$request->route()` are `null`. Consequences: - `request()->routeIs(...)` and `Route::is(...)` return `false`; they check for a route first. - `Route::currentRouteName()` returns `null`. - `$request->route()->named(...)` throws an error on `null`, which is why a shared layout that is also used by error pages should call `routeIs()`. ## Several patterns at once Every name check accepts more than one pattern and returns `true` if any matches: ```php request()->routeIs('admin.orders.*', 'admin.refunds.*'); Route::is('admin.dashboard', 'admin.reports.*'); ``` This keeps menu logic short when one navigation entry covers several areas, for example an "Orders" tab that should stay active on refund pages. ## Middleware and other consumers Inside route middleware the route has matched, so `$request->route()->named('franchise.*')` is safe and is the form the routing docs demonstrate. Policies, view composers and logging can read `Route::currentRouteName()` to tag work with the route that triggered it. ## Where the current route comes from When the router matches a request, it stores the route as its **current route** and gives the request a **route resolver** that returns it. Everything above reads one of those two: - `Route::current()`, `Route::currentRouteName()`, `Route::is()` and `Route::currentRouteAction()` ask the router. - `$request->route()` and `$request->routeIs()` ask the request's resolver. Both are filled at the same moment, right after matching and before route middleware and the controller run, which is why the checks are reliable in route middleware, controllers, views and view composers, and empty in global middleware and error pages for unmatched URLs. ## Pitfalls interviewers probe - **Using `request()->is()` with a route name**, as in `request()->is('admin.orders.*')`: it compares the path, so it never matches. - **Calling `->named()` on a null route** in layouts shared with error pages. - **Assuming `currentRouteName()` returns an empty string** for unnamed routes: it returns `null`. - **Forgetting the wildcard**: `routeIs('admin.orders')` matches only that exact name.
- Why can a shared Laravel layout crash on 404 pages when it calls $request->route()->named('admin.*')?For an unmatched URL the router never sets a current route, so `$request->route()` returns `null` and calling `named()` on it throws an error while the 404 page renders. `request()->routeIs('admin.*')` checks for a route first and returns `false`, so it is safe in layouts shared with error pages.
- Which Laravel call tells you the controller action of the current route?`Route::currentRouteAction()` returns the action string, such as `App\Http\Controllers\OrderController@show`, or `null` when there is no current route or the route is a closure. It is useful in logging and debugging; for branching logic, route names are more stable.
Checking routeIs() is like reading the name on a meeting-room door rather than counting doors along the corridor: if the rooms are renumbered after a refit, the name still tells you where you are.
saying these in an interview costs you the question
- request()->is('admin.orders.*') checks the route name
- Route::currentRouteName() returns an empty string for unnamed routes
- routeIs('admin.orders') also matches admin.orders.show
- Route::current() always returns a route inside a request
- Checking the URL path is sturdier than checking the route name