Laravel 編碼技巧 路由

2023-02-16 17:10 更新

分組中的分組

在路由中,你可以在分組中創(chuàng)建分組,來實現(xiàn)僅僅為父分組中的某些路由分配中間件。

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');
    });
});

通配符子域名

你可以在分組中定義變量,來創(chuàng)建動態(tài)子域名分組,然后將這個變量傳遞給每一個子路由。

Route::domain('{username}.workspace.com')->group(function () {
    Route::get('user/{id}', function ($username, $id) {
        //
    });
});

路由之后?

想知道 Auth::routes() 路由之后是什么?

從 Laravel 7 之后,它被分在一個單獨的包中,你可以查閱文件 /vendor/laravel/ui/src/AuthRouteMethods.php。

public function auth()
{
    return function ($options = []) {
        // 鑒權(quán)路由……
        $this->get('login', 'Auth\LoginController@showLoginForm')->name('login');
        $this->post('login', 'Auth\LoginController@login');
        $this->post('logout', 'Auth\LoginController@logout')->name('logout');
        // 注冊路由……
        if ($options['register'] ?? true) {
            $this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register');
            $this->post('register', 'Auth\RegisterController@register');
        }
        // 重置密碼路由……
        if ($options['reset'] ?? true) {
            $this->resetPassword();
        }
        // 確認(rèn)密碼路由……
        if ($options['confirm'] ?? class_exists($this->prependGroupNamespace('Auth\ConfirmPasswordController'))) {
            $this->confirmPassword();
        }
        // 郵箱驗證路由……
        if ($options['verify'] ?? false) {
            $this->emailVerification();
        }
    };
}

Laravel 7 之前,請查閱 /vendor/laravel/framework/src/illuminate/Routing/Router.php。

路由模型綁定:你可以定義一個 Key

你可以像 Route::get('api/users/{user}', function (App\User $user) { … } 這樣來進行路由模型綁定,但不僅僅是 ID 字段,如果你想讓 {user} 是 username,你可以把它放在模型中:

public function getRouteKeyName() {
    return 'username';
}

快速從路由導(dǎo)航到控制器

在 Laravel 8 之前,這件事情是可選的。在 Laravel 8 中這將成為路由的標(biāo)準(zhǔn)語法。

你可以將控制器標(biāo)識為 :

Route::get('page', [\App\Http\Controllers\PageController::class, 'action']);

而不是

Route::get('page', 'PageController@action');

這樣,你就可以在 PhpStorm 中點擊 PageController 來跳轉(zhuǎn)到控制器定義,而不是手動去搜索它。

或者你想要讓路由的定義更簡潔,你可以在路由文件的開始提前引入控制器的類。

use App\Http\Controllers\PageController;

// 然后:
Route::get('page', [PageController::class, 'action']);

備選路由:當(dāng)沒有匹配到任何路由時

如果你想為未找到的路由指定其它邏輯,而不是直接顯示 404 頁面,你可以在路由文件的最后為其創(chuàng)建一個特殊的路由。

Route::group(['middleware' => ['auth'], 'prefix' => 'admin', 'as' => 'admin.'], function () {
    Route::get('/home', 'HomeController@index');
    Route::resource('tasks', 'Admin\TasksController');
});

// 一些其它的路由....
Route::fallback(function() {
    return 'emmm...出錯了~';
});

使用正則進行路由參數(shù)驗證

我們可以在路由中使用 where 來直接驗證參數(shù)。一個典型的例子是,當(dāng)使用語言區(qū)域的參數(shù)來作為路由前綴時,像是 fr/blog 和 en/article/333 等,這時我們?nèi)绾蝸泶_保這兩個首字母沒有被用在其他語言呢?

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 在每分鐘內(nèi)最多被訪問 60 次。

Route::middleware('auth:api', 'throttle:60,1')->group(function () {
    Route::get('/user', function () {
        //
    });
});

另外,你也可以為公開請求和登錄用戶分別配置:

// 游客最大 10 次,登錄用戶最大 60次
Route::middleware('throttle:10|60,1')->group(function () {
    //
});

此外,你也可以使用數(shù)據(jù)庫字段 users.rate_limit 為一些特殊用戶設(shè)定此值。

Route::middleware('auth:api', 'throttle:rate_limit,1')->group(function () {
    Route::get('/user', function () {
        //
    });
});

路由中的 URL 參數(shù)

如果你在路由中使用數(shù)組傳入了其它參數(shù),這些鍵 / 值將會自動配對并且?guī)?URL 查詢參數(shù)中。

Route::get('user/{id}/profile', function ($id) {
    //
})->name('profile');

$url = route('profile', ['id' => 1, 'photos' => 'yes']); // 結(jié)果: /user/1/profile?photos=yes

按文件為路由分類

如果你有一組與某些功能相關(guān)的路由,你可以將它們放在一個特殊的文件 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;
// ... 一些控制器

use Illuminate\Support\Facades\Route;

Route::get('/register', [RegisteredUserController::class, 'create'])
                ->middleware('guest')
                ->name('register');

Route::post('/register', [RegisteredUserController::class, 'store'])
                ->middleware('guest');

// ... 另外一些路由

但是,你應(yīng)該只在路由都各自具有相同的前綴 / 中間件配置時使用 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'));

        // ... 你的路由列在這后邊
    });
}

翻譯資源中的謂詞

當(dāng)你使用資源控制器,但希望變更 URL 謂詞以適應(yīng)非英語語言環(huán)境下的 SEO ,這樣在路由中就是 /crear 而非/create,你可以使用 App\Providers\RouteServiceProvider 中的 Route::resourceVerbs() 配置。

public function boot()
{
    Route::resourceVerbs([
        'create' => 'crear',
        'edit' => 'editar',
    ]);

    // ...
}

自定義資源路由名稱

當(dāng)使用資源路由時,你可以在 routes/web.php 中指定 ->names() 參數(shù),這樣一來,在整個 Laravel 項目中,瀏覽器中的 URL 前綴和路由名稱前綴可能會不同。

Route::resource('p', ProductController::class)->names('products');

這行代碼將會生成像 /p/p/{id}/p/{id}/edit 這樣的路由,但是你可以在代碼中使用 route('products.index')route('products.create') 等方式來調(diào)用它們。

可讀性更強的路由列表

你有沒有運行過 php artisan route:list ,然后發(fā)現(xiàn)這個列表又長,可讀性又很差。

另一個方法是:

?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 |
+----------+---------------------------------+---------------------+

急切加載

如果你使用了路由模型綁定,并且你認(rèn)為不會在綁定關(guān)系中使用急切加載,請你再想一想。

所以當(dāng)你用了這樣的路由模型綁定

public function show(Product $product) {
    //
}

但是你有一個從屬關(guān)系,并且不能使用 $product->with('category') 急切加載嗎?

但實際上這是可以的,使用 ->load() 來加載關(guān)系。

public function show(Product $product) {
    $product->load('category');
    //
}

本地化資源 URI

如果你使用了資源控制器,但是想要將 URL 謂詞變?yōu)榉怯⒄Z形式的,比如你想要西班牙語的 /crear 而不是 /create ,你可以使用 Route::resourceVerbs() 方法來配置。

public function boot()
{
    Route::resourceVerbs([
        'create' => 'crear',
        'edit' => 'editar',
    ]);
    //
}

資源控制器命名

在資源控制器中,你可以在 routes/web.php 中指定 ->names() 參數(shù),這樣 URL 前綴與路由前綴可能會不同

這樣會生成諸如 /p/p/{id}/p/{id}/edit 等等,但是你可以這樣調(diào)用它們:

  • route('products.index)
  • route('products.create)
  • 等等
Route::resource('p', \App\Http\Controllers\ProductController::class)->names('products');


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號