在微型部落格專案中,我們的 routes.php 內容是這樣:
Route::get('post', 'HomeController@index');
Route::get('post/create', 'HomeController@create');
Route::post('post', 'HomeController@store');
Route::get('post/{id}', 'HomeController@show');
Route::get('post/{id}/edit', 'HomeController@edit');
Route::put('post/{id}', 'HomeController@update');
Route::delete('post/{id}', 'HomeController@destroy');
目前只有一個編輯文章的功能。假如你的網站功能很多,Route 肯定會多到難以維護,其實有幾個方法可以加以調整,本節將專注在 Route 的使用上。
群組化(group)
你會注意到,這些功能全都在 post 這個網址之下,因此我們可以將它往上提,改成這樣:Route::group(['prefix'=>'post'], function(){
Route::get('/', 'HomeController@index');
Route::get('create', 'HomeController@create');
Route::post('/', 'HomeController@store');
Route::get('{id}', 'HomeController@show');
Route::get('{id}/edit', 'HomeController@edit');
Route::put('{id}', 'HomeController@update');
Route::delete('{id}', 'HomeController@destroy');
});
使用 Route::group 將位於同一名稱底下的網址群組化。['prefix'=>'post']
的 prefix 是關鍵字,用來指定前置字 post,因此,原本 route 中的 post 就可以移除或改成斜線。如此在管理上就能很清楚的看到,它們是一夥的。除了
prefix
關鍵字外,還有 before
及 after
等可以使用。
資源控制器(Resource controllers)
這裡要先到終端機(Terminal)看一下我們現在的 route 表。使用 cd 指令進入 blog 網站目錄,輸入:php artisan routes
會列出目前所建立的 route 表: 現在我們要透過
Route::resource
的方式來換掉前面寫了七行的 route:
Route::resource('post', 'HomeController');
記得把前面的七行 route 刪掉(或註解掉),存檔後再次在終端機執行同樣的指令,你會得到幾乎相同的 routing 表:
多了一行 PATCH,功能和 PUT 相同。Name 的欄位多了 post.index、post.create...等的名稱,這個是 route 的名稱。在 laravel 框架中,你可以像我們範例中指定 連結網址 或 route 名稱 ,最後都會由同一個 Action 也就是 Controller 去執行。你也可以指定 resource 只產生某幾個 action:
Route::resource('post', 'HomeController', ['only' => ['create','store','destroy']]);
指定 Route Name
之前建立的 route 都沒有指定 route 名稱,所以就只能使用 URI 來請求。這裡示範 Route Name 怎麼寫:Route::get('post', array('uses' => 'HomeController@index', 'as' => 'post.home'));
原本第二個參數直接指定 Controller@method
,把它改為使用陣列,並且使用兩個關鍵字當 key:
- 'uses' 表示要使用哪個 Controller 的 method
- 'as' 表示這個 route 的名稱(Name)
如果把這行寫在
Route::resource
這行之後,由 resource 產生的相同 URI 的 route 就會被後面這個 route 取代(表示不會有重覆的route出現),所以自動產生的 route Name 就會是 post.home
而不是 post.index
,你可以在終端機下指令觀看 route 表的變化。要怎麼用 route,簡單舉例。在 app/views/home.blade.php 中,原本的
{{ link_to('post/'.$post->id, $post->title) }}
如果使用 route 的方式,要改為:
{{ link_to_route('post.show', $post->title, ['id'=>$post->id]) }}
備註:查了一下文件,link_to 及 link_to_route 是 3.x 的寫法,在 4.x 之後已經改了寫法,改成 HTML::linkRoute。要查看 4.x 的 API 在這裡,可以直接搜尋'link',或在左邊清單中,找到 Html -> HtmlBuilder 就可以看到全部可以使用的方法。
link_to 改為 HTML::link
link_to_route 改為 HTML::linkRoute
參數(Parameters)
選擇性參數
之前用過的Route::get('post/{id}', 'HomeController@show');
{id}
就是參數。如果這個參數是選擇性的:
Route::get('post/{id?}', 'HomeController@show');
後面加個問號,當網址是 http://localhost/blog/public/post
或 http://localhost/blog/public/post/1
都會由這個 route 控制。因為我們的例子中,已經有 "沒有$id" 的 route 了,所以基本上,這個例子沒作用。硬舉例的話,先將
Route::get('post', 'HomeController@show');
這行註解掉,就不能作用了。現在連到這個網址 http://localhost/blog/public/post
就會出錯。把 {id} 加上問號 {id?}。接著修改 HomeController 的 show() 為:
public function show($id=null)
{
if (is_null($id)) {
return $this->index();
}
//下略...
這樣當 $id 為 null 時,就會轉給 index() 去處理。這裡只是舉例,請在必要的時候才這麼做。
參數的正規表示式
Route::get('post/{id}', 'HomeController@show')->where('id', '[0-9]+');
加上 where 去做參數的正規表示式限定。但其實只要 id 不是數字,都會發生錯誤,在於錯誤會不同。非數字的 id 在加了 pattern 的 URI 中,不會被送入 Controller,而是出現找不到對應的網址錯誤。在加 pattern 之前,非數字的 id 仍會送進 Controller,但在 Model 查詢資料庫時,會因為資料型態不符合(id必須為數值)出現錯誤。
你也可以把模式寫成全域的
Route::pattern('id', '[0-9]+');
記得要寫在最上面,會影響之後所有參數為 id 的 route。
過濾器(filter)
Route 還可以設定過濾器,在執行某個網址之前,先做一些檢查。這些過濾器另外寫在 app/filters.php。之後我們會用到 auth 這個內建的過濾器來做登入的驗證。Model 綁定(Model Binding)
Route 提供 Model 及資料表的綁定。Route::model('pp', 'Post');
Route::get('p/{pp}', function(Post $post)
{
return $post->title;
});
我們把 pp 和 Post 綁定,這時候只要使用參數 {pp} 就會得到一個 Post 物件。也就是 http://localhost/blog/public/p/1
中的 1 會送入 {pp} 所綁定的 Post 物件,並以 id 查詢後,傳回給 $post 變數,然後就可以 $post->title
去取得標題。
你好,
回覆刪除我想問下關於put和delete的用法.
我見你的例子Route::put('post/{id}', 'HomeController@update');
請問post是否model/table呢? 而ID是否post的model/table內的pri key呢? 如果兩者都不是, 請問能否訴告這是什麼呢?
我打算用一張form來update table的record. 我現時是没有使用model的, 請問是否需要加回呢?
感謝
你寫在 Route 裡的都是網址的一部份,
回覆刪除例如 'post/{id}' 的網址大概會像這樣 http://www.mysite.com/post/1
所以 post 不是 model 或 table 的名稱,它是網址的一部份,
{id} 是 PK,會在 Controller 裡用來處理資料庫相關的動作,
因為更新和刪除都必須知道要對哪個 PK 做動作,所以它們的 URI 是一樣的,
差別在於你是指定哪個狀態,例如:PUT 或 DELETE 來區別。
請問在form的寫法是否如下?
刪除<form action={{action('EditController@update')}} method="put">
我在route加下面這句後
Route::put('edit/{no}', 'EditController@update');
就出現以下的error msg
Missing required parameters for [Route: ] [URI: edit/{no}]. (View: C:\xampp\htdocs\atwd2\resources\views\edit.blade.php)
感謝
form 的 method 只有兩種,GET 或 POST,
刪除PUT 及 DELETE 都必須另外附加一個隱藏欄位來送出,
大概像這樣:
<input type="hidden" name="_method" value="PUT">
Laravel 有提供快捷方法
{{ method_field('PUT') }}
你的 form 應該寫成
<form action="edit/123">
123 是你的 no 也就是要編輯的 PK。
你用 Laravel 提供的快捷方法也是可以,但要寫成
<form action="{{ action('EditController@update', ['no' => 123]); }}">
非常感謝.
刪除另外, 我剛啱遇到另一個問題. 我用laravel建立了get的API, 想在同一個環境下用作測試.
例如, 我的API叫://127.0.0.1/?no=1. 這個API是會出XML format.
咁我在另一個view內想使用這條API.
$url = 'http://127.0.0.1/api?no=1';
$xml = simplexml_load_strig($url);
但就不成功. 没有error msg. 只show等左60秒, server冇反應. 但我用postman測過API是没有問題的.
請問有冇這方面的經驗呢? 感謝
看一下說明書(http://php.net/manual/en/function.simplexml-load-string.php)
刪除「simplexml_load_string — Interprets a string of XML into an object」
這個方法是讀進 XML 字串然後轉成物件,你送網址進去它當然無法解讀,
你要先將 XML 內容下載下來,才放進去,例如:
//////////////////////
<?php
$url = 'https://tw.news.yahoo.com/rss';
$xml = file_get_contents($url);
if ($xml) {
$xmlObj = simplexml_load_string($xml);
if (xmlObj) {
print_r($xmlObj);
} else {
echo "XML 解析錯誤";
}
} else {
echo "下載發生錯誤";
}
//////////////////////
file_get_contents 適合用於檔案,雖然它也可以讀網址,
建議去研究一下 cURL (http://php.net/manual/en/book.curl.php)
Route::resource('post', 'HomeController', ['only' => ['create','store','destroy']]);
回覆刪除請教一下 這行如果要讓他產生如版大說的各自的route name,應該要怎麼寫才行呢?感謝~
你用 Route::resource 它就會幫你建立了,
刪除用指令 php artisan routes 查詢,看 Name 那一欄
另外,route name 跟uri 的差異是什麼啊~ 有點搞不太清楚說, 還請版大開示,感恩~
回覆刪除它們的用途都是用來指向 Controller,
刪除假設網址是 http://www.abc.com/post
uri 就是 post
route name 是你自訂的(或 resources 產生),
差別只在用 uri 和網址直接相關,route name 你可以自訂名稱,
選一個用就可以
感謝您熱心地對每個問題一一解答:~
刪除再請教一下,有個函式Redirect::intended 的用法 ,他通常會被放在認證通過後 執行, 不曉得跟Redirect::to 有什麼差別呢?
Redirect::to 是導向你指定的頁面,
刪除Redirect::intended 是使用者意圖進入某個頁面但被強制先登入時,
在登入後自動導向該頁,如果該頁無法進入,就導向你指定的頁面。
例如:
使用者在網址輸入 http://www.xxx.com/show <- 可是這個 show 必須先登入才能看,
因為使用者還未登入,於是就跳到 /login 頁面,輸入完資料按下登入後,
會自動導向 /show 這個使用者意圖進入的頁面,
在找不到該頁的情況下,才導向你指定的頁面,這裡和 Redirect::to 差不多。
請問如果 Resource controllers 要進一步設定參數要怎麼設定呢??
回覆刪除例如 Route::get('content', 'Admin\ContentController@index')
我還要加上 modelid跟lang這兩個參數~ 且lang是可有可無
Route::get('content/{modelid}/{lang?}', 'Admin\ContentController@index')
刪除對應的可能結果:
/content/1
/content/1/zh-TW