分组中的分组
在路由中,你可以在分组中创建分组,来实现仅仅为父分组中的某些路由分配中间件。
复制 Route :: group ( [ 'prefix' => 'account' , 'as' => 'account.' ] , function () {
Route :: get ( 'login' , 'AccountController@login' ) ;
Route :: get ( 'register' , 'AccountController@register' ) ;
Route :: group ( [ 'middleware' => 'auth' ] , function () {
Route :: get ( 'edit' , 'AccountController@edit' ) ;
} ) ;
} ) ;
通配符子域名
你可以在分组中定义变量,来创建动态子域名分组,然后将这个变量传递给每一个子路由。
复制 Route :: domain ( '{username}.workspace.com' ) -> group ( function () {
Route :: get ( 'user/{id}' , function ($username , $id) {
//
} ) ;
} ) ;
routes 调用之后是什么
若你使用 Laravel UI package , 你可能想知道 Auth::routes()
定义之后真正的路由是什么?
查看 /vendor/laravel/ui/src/AuthRouteMethods.php
.
复制 public function auth ()
{
return function ($options = []) {
// Authentication Routes...
$this -> get ( 'login' , 'Auth\LoginController@showLoginForm' ) -> name ( 'login' ) ;
$this -> post ( 'login' , 'Auth\LoginController@login' ) ;
$this -> post ( 'logout' , 'Auth\LoginController@logout' ) -> name ( 'logout' ) ;
// Registration Routes...
if ($options[ 'register' ] ?? true ) {
$this -> get ( 'register' , 'Auth\RegisterController@showRegistrationForm' ) -> name ( 'register' ) ;
$this -> post ( 'register' , 'Auth\RegisterController@register' ) ;
}
// Password Reset Routes...
if ($options[ 'reset' ] ?? true ) {
$this -> resetPassword () ;
}
// Password Confirmation Routes...
if ($options[ 'confirm' ] ?? class_exists ( $this -> prependGroupNamespace ( 'Auth\ConfirmPasswordController' )) ) {
$this -> confirmPassword () ;
}
// Email Verification Routes...
if ($options[ 'verify' ] ?? false ) {
$this -> emailVerification () ;
}
};
}
默认调用:
复制 Auth :: routes () ; // no parameters
但是你可以提供参数来启用或禁用真正的路由
复制 Auth :: routes ( [
'login' => true ,
'logout' => true ,
'register' => true ,
'reset' => true , // for resetting passwords
'confirm' => false , // for additional password confirmations
'verify' => false , // for email verification
] ) ;
suggestion 由 MimisK13 提供
路由模型绑定-你可以定义一个 Key
你可以像 Route::get('api/users/{user}', function (App\User $user) { … }
这样来进行路由模型绑定,但不仅仅是 ID 字段,如果你想让 {user} 是 username,你可以把它放在模型中:
复制 public function getRouteKeyName () {
return 'username' ;
}
快速从路由导航到控制器
在 Laravel 8
之前,这件事情是可选的。在 Laravel 8
中这将成为路由的标准语法
不用这么写:
复制 Route :: get ( 'page' , 'PageController@action' ) ;
你可以将控制器标识为 class
类名:
复制 Route :: get ( 'page' , [ \ App \ Http \ Controllers \ PageController ::class , 'action' ] ) ;
这样,你就可以在 PhpStorm
中点击 PageController
来跳转到控制器定义,而不是手动去搜索它
或者你想要让路由的定义更简洁,你可以在路由文件的开始提前引入控制器的类。
复制 use App \ Http \ Controllers \ PageController ;
// Then:
Route :: get ( 'page' , [ PageController ::class , 'action' ] ) ;
备选路由-当没有匹配到任何路由时
如果你想为未找到的路由指定其它逻辑,而不是直接显示 404 页面,你可以在路由文件的最后为其创建一个特殊的路由。
复制 Route :: group ( [ 'middleware' => [ 'auth' ] , 'prefix' => 'admin' , 'as' => 'admin.' ] , function () {
Route :: get ( '/home' , 'HomeController@index' ) ;
Route :: resource ( 'tasks' , 'Admin\TasksController' ) ;
} ) ;
// Some more routes....
Route :: fallback ( function () {
return 'Hm, why did you land here somehow?' ;
} ) ;
使用正则进行路由参数验证
我们可以在路由中使用 where
参数 来直接验证参数。一个典型的例子是,当使用语言区域的参数来作为路由前缀时,像是 fr/blog
和 en/article/333
等,这时我们如何来确保这两个首字母没有被用在其他语言呢?
routes/web.php
:
复制 Route :: group ( [
'prefix' => '{locale}' ,
'where' => [ 'locale' => '[a-zA-Z]{2}' ]
] , function () {
Route :: get ( '/' , 'HomeController@index' ) ;
Route :: get ( 'article/{id}' , 'ArticleController@show' ) ;
} ) ;
限流-全局配置与按用户配置
你可以使用 throttle:60,1
来限制一些 URL 在每分钟内最多被访问 60 次。
复制 Route :: middleware ( 'auth:api' , 'throttle:60,1' ) -> group ( function () {
Route :: get ( '/user' , function () {
//
} ) ;
} ) ;
另外,你也可以为公开请求和登录用户分别配置:
复制 // maximum of 10 requests for guests, 60 for authenticated users
Route :: middleware ( 'throttle:10|60,1' ) -> group ( function () {
//
} ) ;
此外,你也可以使用数据库字段 users.rate_limit
为一些特殊用户设定此值。
复制 Route :: middleware ( 'auth:api' , 'throttle:rate_limit,1' ) -> group ( function () {
Route :: get ( '/user' , function () {
//
} ) ;
} ) ;
路由中的 URL 参数
如果你在路由中使用数组传入了其它参数,这些键 / 值将会自动配对并且带入 URL
查询参数中。
复制 Route :: get ( 'user/{id}/profile' , function ($id) {
//
} ) -> name ( 'profile' ) ;
$url = route ( 'profile' , [ 'id' => 1 , 'photos' => 'yes' ] ) ; // Result: /user/1/profile?photos=yes
按文件为路由分类
如果你有一组与某些功能相关的路由,你可以将它们放在一个特殊的文件 routes/XXXXX.php
中,然后在 routes/web.php
中使用 include 引入它。`
Taylor Otwell 在 Laravel Breeze 中的例子: routes/auth.php
复制 Route :: get ( '/' , function () {
return view ( 'welcome' ) ;
} ) ;
Route :: get ( '/dashboard' , function () {
return view ( 'dashboard' ) ;
} ) -> middleware ( [ 'auth' ] ) -> name ( 'dashboard' ) ;
require __DIR__ . '/auth.php' ;
然后,在 routes/auth.php
中:
复制 use App \ Http \ Controllers \ Auth \ AuthenticatedSessionController ;
use App \ Http \ Controllers \ Auth \ RegisteredUserController ;
// ... more controllers
use Illuminate \ Support \ Facades \ Route ;
Route :: get ( '/register' , [ RegisteredUserController ::class , 'create' ] )
-> middleware ( 'guest' )
-> name ( 'register' ) ;
Route :: post ( '/register' , [ RegisteredUserController ::class , 'store' ] )
-> middleware ( 'guest' ) ;
// ... A dozen more routes
但是,你应该只在路由都各自具有相同的前缀 / 中间件配置时使用 include()
来引入路由,否则,更好的选择是将他们分类在 app/Providers/RouteServiceProvider
中。
复制 public function boot ()
{
$this -> configureRateLimiting () ;
$this -> routes ( function () {
Route :: prefix ( 'api' )
-> middleware ( 'api' )
-> namespace ( $this -> namespace )
-> group ( base_path ( 'routes/api.php' )) ;
Route :: middleware ( 'web' )
-> namespace ( $this -> namespace )
-> group ( base_path ( 'routes/web.php' )) ;
// ... Your routes file listed next here
} ) ;
}
翻译资源中的动词
当你使用了资源控制器,但希望变更 URL
谓词以适应非英语语言环境下的 SEO
,以在路由中用 /crear
替换 /create
,你可以使用 App\Providers\RouteServiceProvider 中的 Route::resourceVerbs()
配置。
复制 public function boot ()
{
Route :: resourceVerbs ( [
'create' => 'crear' ,
'edit' => 'editar' ,
] ) ;
// ...
}
自定义资源路由名称
当使用资源路由时,你可以在 routes/web.php
中指定 ->names() 参数
,这样一来,在整个 Laravel 项目中,浏览器中的 URL 前缀和路由名称前缀可能会不同。
复制 Route :: resource ( 'p' , ProductController ::class ) -> names ( 'products' ) ;
这行代码将会生成像 /p
, /p/{id}
, /p/{id}/edit
这样的路由,但是你可以在代码中使用 route('products.index')
, route('products.create')
等方式来调用它们。
可读性更强的路由列表
你有没有运行过 php artisan route:list
,然后发现这个列表又长,可读性又很差。 另一个方法是: php artisan route:list --compact
这样只会输出 3 列,而非 6 列:只展示方法名、 URI 和方法
复制 +----------+---------------------------------+-------------------------------------------------------------------------+
| Method | URI | Action |
+----------+---------------------------------+-------------------------------------------------------------------------+
| GET|HEAD | / | Closure |
| GET|HEAD | api/user | Closure |
| POST | confirm-password | App\Http\Controllers\Auth\ConfirmablePasswordController@store |
| GET|HEAD | confirm-password | App\Http\Controllers\Auth\ConfirmablePasswordController@show |
| GET|HEAD | dashboard | Closure |
| POST | email/verification-notification | App\Http\Controllers\Auth\EmailVerificationNotificationController@store |
| POST | forgot-password | App\Http\Controllers\Auth\PasswordResetLinkController@store |
| GET|HEAD | forgot-password | App\Http\Controllers\Auth\PasswordResetLinkController@create |
| POST | login | App\Http\Controllers\Auth\AuthenticatedSessionController@store |
| GET|HEAD | login | App\Http\Controllers\Auth\AuthenticatedSessionController@create |
| POST | logout | App\Http\Controllers\Auth\AuthenticatedSessionController@destroy |
| POST | register | App\Http\Controllers\Auth\RegisteredUserController@store |
| GET|HEAD | register | App\Http\Controllers\Auth\RegisteredUserController@create |
| POST | reset-password | App\Http\Controllers\Auth\NewPasswordController@store |
| GET|HEAD | reset-password/{token} | App\Http\Controllers\Auth\NewPasswordController@create |
| GET|HEAD | verify-email | App\Http\Controllers\Auth\EmailVerificationPromptController@__invoke |
| GET|HEAD | verify-email/{id}/{hash} | App\Http\Controllers\Auth\VerifyEmailController@__invoke |
+----------+---------------------------------+-------------------------------------------------------------------------+
你还可以特别地指定所需要的列:
php artisan route:list --columns=Method,URI,Name
复制 +----------+---------------------------------+---------------------+
| Method | URI | Name |
+----------+---------------------------------+---------------------+
| GET|HEAD | / | |
| GET|HEAD | api/user | |
| POST | confirm-password | |
| GET|HEAD | confirm-password | password.confirm |
| GET|HEAD | dashboard | dashboard |
| POST | email/verification-notification | verification.send |
| POST | forgot-password | password.email |
| GET|HEAD | forgot-password | password.request |
| POST | login | |
| GET|HEAD | login | login |
| POST | logout | logout |
| POST | register | |
| GET|HEAD | register | register |
| POST | reset-password | password.update |
| GET|HEAD | reset-password/{token} | password.reset |
| GET|HEAD | verify-email | verification.notice |
| GET|HEAD | verify-email/{id}/{hash} | verification.verify |
+----------+---------------------------------+---------------------+
预加载
如果你使用了路由模型绑定,并且你认为不会在绑定关系中使用预加载,请你再想一想。 所以当你用了这样的路由模型绑定:
复制 public function show ( Product $product) {
//
}
但是你有一个从属关系,这时候就不能使用 $product->with('category')
预加载了吗? 你当然可以,使用 ->load()
来加载关系
复制 public function show ( Product $product) {
$product -> load ( 'category' ) ;
//
}
本地化资源 URI
如果你使用了资源控制器,但是想要将 URL 谓词变为非英语形式的,比如你想要西班牙语的 /crear
而不是 /create
,你可以使用 Route::resourceVerbs()
方法来配置。
复制 public function boot ()
{
Route :: resourceVerbs ( [
'create' => 'crear' ,
'edit' => 'editar' ,
] ) ;
//
}
资源控制器命名
在资源控制器中,你可以在 routes/web.php
中指定 ->names()
参数,这样 URL
前缀与路由前缀可能会不同 . 这样会生成诸如 /p
, /p/{id}
, /p/{id}/edit
等等,但是你可以这样调用它们:
route('products.index)
route('products.create)
等等
复制 Route :: resource ( 'p' , \ App \ Http \ Controllers \ ProductController ::class ) -> names ( 'products' ) ;
更简单地高亮你的导航栏
使用 Route::is('route-name')
来更简单的高亮你的导航栏
复制 < ul >
< li @if(Route::is( 'home')) class = "active" @endif >
< a href = "/" >Home</ a >
</ li >
< li @if(Route::is( 'contact-us')) class = "active" @endif >
< a href = "/contact-us" >Contact us</ a >
</ li >
</ ul >
由 @anwar_nairi 提供
使用 route 辅助函数生成绝对路径
复制 route ( 'page.show' , $page -> id ) ;
// http://laravel.test/pages/1
route ( 'page.show' , $page -> id , false ) ;
// /pages/1
由 @oliverds_ 提供
为你的每个模型重写路由绑定解析器
你可以为你的所有模型重写路由绑定解析器。在这个例子里,我们没有对URL
中的 @
符号做任何处理,所以 用``resolveRouteBinding
我可以移除@
符号 然后解析模型
复制 // Route
Route :: get ( '{product:slug}' , Controller ::class ) ;
// Request
https: //nodejs.pub/@unlock/hello-world
// Product Model
public function resolveRouteBinding ($value , $field = null )
{
$value = str_replace ( '@' , '' , $value ) ;
return parent:: resolveRouteBinding ( $value , $field ) ;
}
由 @Philo01 提供
如果你需要一个公共 URL 但是你想让他们更安全
如果你需要一个公共URL但是你想让他们更安全,使用 Laravel signed URL
复制 class AccountController extends Controller
{
public function destroy ( Request $request)
{
$confirmDeleteUrl = URL :: signedRoute ( 'confirm-destroy' , [
$user => $request -> user ()
] ) ;
// Send link by email...
}
public function confirmDestroy ( Request $request , User $user)
{
if ( ! $request -> hasValidSignature () ) {
abort ( 403 ) ;
}
// User confirmed by clikcing on the email
$user -> delete () ;
return redirect () -> route ( 'home' ) ;
}
}
由 @anwar_nairi 提供
在中间件中使用 Gate
你可以在中间件中使用在 App\Providers\AuthServiceProvider
设置的 Gate
怎么做呢?你可以在路由中添加 can:
和必要 gate
的名字
复制 Route :: put ( '/post/{post}' , function ( Post $post) {
// The current user may update the post...
} ) -> middleware ( 'can:update,post' ) ;
简单路由-使用箭头函数
在路由中你可以使用PHP的箭头函数 而不需要用匿名函数。
要做到这一点 你可以使用 fn() =>
这样看起来更简单。
复制 // Instead of
Route :: get ( '/example' , function () {
return User :: all () ;
} ) ;
// You can
Route :: get ( '/example' , fn () => User :: all ()) ;
路由视图
使用 Route::view($uri , $bladePage)
直接返回 view 而不需要控制器方法
复制 //this will return home.blade.php view
Route :: view ( '/home' , 'home' ) ;
路由目录代替路由文件
你可以创建一个 /routes/web/ 目录,只在 /routes/web.php 中填写。
复制 foreach ( glob ( dirname ( __FILE__ ) . '/web/*' , GLOB_NOSORT ) as $route_file){
include $route_file;
}
现在,/routes/web/ 内的每个文件都作为一个路由文件,你可以将你的路由组织到不同的文件中。
路由资源分组
如果你的路由有很多资源控制器,你可以将它们分组并调用一个Route::resources(),而不是许多单一的Route::resource()语句。
复制 Route :: resources ( [
'photos' => PhotoController ::class ,
'posts' => PostController ::class ,
] ) ;
自定义路由绑定
你知道你可以在 Laravel 中自定义路由绑定吗?
在这个例子中,我需要通过 slug 来解析职务。但是 slug 不是唯一的,因为多个用户可以有名为 'Foo' 的职务
所以我配置了 Laravel 应该如何从路由参数中解析它们
复制 class RouteServiceProvider extends ServiceProvider
{
public const HOME = '/dashboard' ;
public function boot ()
{
Route :: bind ( 'portfolio' , function ( string $slug) {
return Portfolio :: query ()
-> whereBelongsto ( request () -> user ())
-> whereSlug ( $slug )
-> firstOrFail () ;
} ) ;
}
}
复制 Route :: get ( 'portfolios/{portfolio}' , function ( Portfolio $portfolio) {
/*
* The $portfolio will be the result of the query defined in the RouteServiceProvider
*/
} )