在模板中咱們通常不會直接寫死url,而是用url助手生成url,本文介紹一下url助手的使用以及遇到的一些比較頭疼的問題。php
首先,咱們建立了一個路由:
Route::get('articles',['uses'=>'ArticlesController@index','as'=>'articles.index']);
html
假設咱們的項目部署在域名根目錄,那麼能夠經過下面的url訪問:
http://localhost/articles
laravel
如今,咱們在模板中生成連接,有幾種方式:
簡單模式數組
```<a href="{{ url('/articles') }}">連接</a>
// or <a href="{{ URL::to('/articles') }}">連接</a> //爲了方便閱讀,下面省略html標籤```post
這種方式,只是簡單的將你指定的路徑拼接到網站根url上。
路由模式測試
```URL::route('articles.index')``` 這種方式是指定匹配註冊路由時的 'as' 參數,獲得註冊的uri。
控制器動做模式網站
```URL::action('ArticlesController@index')``` 這種方式是根據註冊路由時 'uses' 參數,自動生成映射到控制器方法的uri,規則同 `Route::controller()` 。
舉例以下:ui
```ArticlesController@index => articles
ArticlesController@getAdd => articles/add ArticlesController@postAdd => articles/add ArticlesController@getDelete => articles/delete```url
**基本教程到此結束,接下來咱們來面對一些使人惱怒的狀況。** 如今,路由變得更加複雜了,咱們定義了一個這樣的:
Route::controller('users','UsersController');
code
一條簡單的語句,Laravel會自動反射 `UsersController` 類,並掃描其中的方法,而後生成普通的映射,舉例說明吧,假設控制器中有如下方法:
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]`。 1. 它會檢測路由註冊uri中有沒有 `{id?}` 這個字符串,有的話就把值放在這個位置,好比 `users/edit/{id?}` 這樣的話,就會造成 `users/edit/1`。 2. 將參數數組中剩下的元素再次遍歷,按順序替換到uri中剩下的 `{.*\?}` 這種格式的字符串。 3. 最後將剩餘的 `{.*\?}` 刪掉,若是$parameters還有剩餘元素,則會被做爲querystring附加到url末尾。 也就是說,除非咱們在 `id` 前面增長五個參數,不然 `id` 的值只能出如今uri路徑中。 很奇葩不是麼? 那麼如何解決這個問題? 1. querystring手寫到url後面,能夠經過 `http_build_query` ```$params = ['id'=>1]; echo URL::action('TestController@getEdit').'?'.http_build_query($params);``` 2. 修改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); }``` 用哪一種,取決於你本身。 就說這麼多吧,有什麼疑問請發郵件給我,郵箱地址在頁面底部。