原文地址: Laravel 深刻理解路由和URL生成 在模板中咱們通常不會直接寫死url,而是用url助手生成url,本文介紹一下url助手的使用以及遇到的一些比較頭疼的問題。 首先,咱們建立了一個路由: Route::get('articles',['uses'=>'ArticlesController@index','as'=>'articles.index']); 假設咱們的項目部署在域名根目錄,那麼能夠經過下面的url訪問: http://localhost/articles 如今,咱們在模板中生成連接,有幾種方式: 簡單模式
連接 // or
連接 //爲了方便閱讀,下面省略html標籤 這種方式,只是簡單的將你指定的路徑拼接到網站根url上。 路由模式 URL::route('articles.index') 這種方式是指定匹配註冊路由時的 'as' 參數,獲得註冊的uri。 控制器動做模式 URL::action('ArticlesController@index') 這種方式是根據註冊路由時 'uses' 參數,自動生成映射到控制器方法的uri,規則同 Route::controller() 。 舉例以下: ArticlesController@index => articles ArticlesController@getAdd => articles/add ArticlesController@postAdd => articles/add ArticlesController@getDelete => articles/delete 基本教程到此結束,接下來咱們來面對一些使人惱怒的狀況。 如今,路由變得更加複雜了,咱們定義了一個這樣的: Route::controller('users','UsersController'); 一條簡單的語句,Laravel會自動反射 UsersController 類,並掃描其中的方法,而後生成普通的映射,舉例說明吧,假設控制器中有如下方法: function getIndex(); function getEdit(); function postEdit(); 實際上,經過 Route::controller() 最終結果相似於: Route::get('users',['uses'=>'UsersController@getIndex']); Route::get('users/edit',['uses'=>'UsersController@getEdit']); Route::post('users/edit',['uses'=>'UsersController@postEdit']); 說白了,高級路由方法只是對基本方法的封裝。 好的,如今咱們來生成一條url: echo URL::action('UsersController@getEdit'); 如願以償獲得 http://localhost/users/edit ,可是咱們要加點querystring參數呢?也就是俗稱的 get參數。 咱們想要獲得 http://localhost/users/edit?id=1 應該怎麼生成? 聰明人已經注意到了 URL::action() 有第二個參數,能夠指定一個數組,做爲url參數,那好,咱們來試試。 echo URL::action('UsersController@getEdit',['id'=>1]); 好了?NO!!你獲得的將是: http://localhost/users/edit/1 若是你再加一個參數: echo URL::action('UsersController@getEdit',['id'=>1,'author'=>'admin']); 獲得的是: http://localhost/users/edit/1/admin 它根本就忽視了你指定的key,而且沒有做爲 ?id=1&author=admin 附加在url末尾。 爲何?!! 確定是哪裏出問題了,這裏你不用去扒源碼,緣由我會在下面給出。 咱們先用另一種方式來測試,前面說過,高級路由是對基本路由的封裝,那麼咱們就構建一個基本路由來測試這個問題! Route::get('test/edit',['uses'=>'TestController@getEdit']) 生成URL: echo URL::action('TestController@getEdit',['id'=>1]); 獲得: http://localhost/test/edit?id=1 這特麼是對的啊?不是說 Route::controller() 是對 Route::get() 這種基本方法的封裝麼? 沒錯,但咱們憑什麼就認爲 Route::controller('users','UsersController'); 徹底等於 Route::get('users/edit',['uses'=>'UsersController@getEdit']); 等等?至少 uri部分不同,我一開始也只是用了」相似「來講明。 經過對源碼的剖析,我發現了,當經過 Route::controller() 註冊路由的時候,它實際上會在轉化的時候加點料進去,請查看 \Illuminate\Routing\ControllerInspector::addUriWildcards 方法。 實際上,會轉化爲: Route::get('users/edit/{one?}/{two?}/{three?}/{four?}/{five?}',['uses'=>'UsersController@getEdit']) Laravel默認url生成有個缺陷,它是按照這樣的步驟去匹配參數的。 echo URL::action('TestController@getEdit',['id'=>1]); 它會遍歷$parameters,也就是 ['id'=>1]。 它會檢測路由註冊uri中有沒有 {id?} 這個字符串,有的話就把值放在這個位置,好比 users/edit/{id?} 這樣的話,就會造成 users/edit/1。 將參數數組中剩下的元素再次遍歷,按順序替換到uri中剩下的 {.*\?} 這種格式的字符串。 最後將剩餘的 {.*\?} 刪掉,若是$parameters還有剩餘元素,則會被做爲querystring附加到url末尾。 也就是說,除非咱們在 id 前面增長五個參數,不然 id 的值只能出如今uri路徑中。 很奇葩不是麼? 那麼如何解決這個問題? querystring手寫到url後面,能夠經過 http_build_query $params = ['id'=>1]; echo URL::action('TestController@getEdit').'?'.http_build_query($params); 修改laravel源碼,在 vendor/laravel/framework/src/Illuminate/Support/helpers.php 文件中,找到 preg_replace_sub ,做以下修改: function preg_replace_sub($pattern, &$replacements, $subject) { return preg_replace_callback($pattern, function($match) use (&$replacements) { foreach ($replacements as $key => $value) { //return array_shift($replacements); if (is_numeric($key)) { unset($replacements[$key]); return $value; } } }, $subject); } 用哪一種,取決於你本身。 做者:多釐 連接:https://www.jianshu.com/p/7d5f325aa962 來源:簡書 著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。