Laravel Controller
PHP:7.2
Laravel:5.7
正常的狀況下,在 routes
定義的 endpoint 不太可能會像範例一樣處理單一邏輯,而且如果把開發邏輯都寫在 routes
在架構上也不符合 MVC 原則。
Laravel Controller 是定義開發邏輯的一個 類別
,開發者可以透過繼承 Controller
定義不同邏輯的開發。Controller 的目錄統一放在 app/Http/Controllers
。
建立 Controller
Controller 雖然可以手動建立,但必須自己注意 Namespace 及繼承 Controller
,建議可以使用 artisan
建立 Controller。
# 使用 make:controller 建立 ProfileController(class name)
# 預設會建立在 app/Http/Controllers 目錄底下
php artisan make:controller ProfileController
# 建立在 app/Http/Controllers/Admin 目錄
php artisan make:controller Admin/ProfileController
建立出來的 Controller
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ProfileController extends Controller
{
//
}
Controller 基本使用
Controller 最典型的基本的應用就是建立一個可以傳入參數的 endpoint
,並在 Controller 端加以使用。
Route
Route::get('/profile/{id}', 'ProfileController@showID');
Controller
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ProfileController extends Controller
{
public function index()
{
return 'Hello';
}
public function showID($id)
{
return $id;
}
public function list()
{
// 使用 view
return view('test');
}
}
如果 Controller 只有一個 action 的話,可以使用 __invoke
當 action name,在 routes
就不需要特別指定。
Route::get('/profile/{id}', 'ProfileController');
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ProfileController extends Controller
{
public function __invoke($id)
{
return $id;
}
}
Resource Controller
在需要用到 CRUD 的情形下,Laravel 也提供了 Resource Controller
解決必須大量建立 action 和 對應 route 的困擾。
利用 artisan 建立 Resource Controller
# 使用 --resource 參數建立 Controller
php artisan make:controller DataController --resource
建立完成以後,就可以看到加入 --resource
參數建立出來的 Controller 裡面已經自動建出 CRUD 會需要用到的 action,接著只要再補入邏輯就可以了。
Route
// 使用 resource method 以後,Laravel 會自動對應到相對的 action
Route::resource('data', 'DataController');
// 也可以透過 resources method 一次對應多個 Resource Controller
Route::resources([
'photos' => 'PhotoController',
'posts' => 'PostController'
]);
Partial Resource Routes
開發的需求上如果沒有需要完整的 Resource Controller,但又想使用該功能的話,可以考慮使用 Partial Routes,只留部份 endpoint
。
// 只對應到 index、show
Route::resource('photos', 'PhotoController')->only([
'index', 'show'
]);
// 反向設定,只對應到 index、show
Route::resource('photos', 'PhotoController')->except([
'create', 'store', 'update', 'destroy'
]);
Resource Controller action 及 route 的對應表
Verb | URI | Action | Route Name |
---|---|---|---|
GET | /data |
index | data.index |
GET | /data/create |
create | data.create |
POST | /data |
store | data.store |
GET | /data/{id} |
show | data.show |
GET | /data/{id}/edit |
edit | data.edit |
PUT/PATCH | /data/{id} |
update | data.update |
DELETE | /data/{id} |
destroy | data.destroy |
API Resource Controller
除了一般頁面使用的 Resource Controller,Laravel 也有提供 API 專用的,除了 action 數量不同以外,用法基本上都是一樣的。
# 利用 artisan 建立 API Resource Controller
php artisan make:controller API/DataController --api
// 使用 apiResource method 以後,Laravel 會自動對應到相對的 action
Route::apiResource('data', 'DataController');
// 一次對應多個 API Resource Controller
Route::apiResources([
'photos' => 'PhotoController',
'posts' => 'PostController'
]);
Notice:PUT/PATCH、DELETE
PUT/PATCH、DELETE 是 HTTP 的 method ,並不是 HTML 的標準,因此要在 HTML 的 <form>
使用這幾個 HTTP Verbs 時,必須加入一個 hidden 的 _method
field 欺騙 HTTP。
而 Laravel 提供了一個 Blade directive 可以快速解決這件事。
<form action="/data/10" method="POST">
<!-- 使用 @method 的 Blade directive -->
@method('PUT')
<!-- 使用 csrf_field() 自動在 form 代入 token-->
{{ csrf_field() }}
<button type="submit">讚</button>
</form>
Controller 取得參數
Laravel 的 Service Container 實作了相依性注入(Dependency Injection) 解決函式相依的問題,讓其他的 Instance
注入到 Controller 中直接使用。
HTTP Requests
Laravel 的架構下,透過 Illuminate\Http\Request
這個物件可以取得 HTTP Request 的參數。
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class TestController extends Controller
{
// 注入 Request
public function create(Request $request)
{
// 透過 all method 取得所有參數
$result = $request->all();
// 透過 input method 取得 name 參數的值
$name = $request->input('name');
// 也可以直接取值
$name = $request->name;
// 當沒有該參數時,設定預設值
$age = $request->input('age', '25');
// 判斷是否有值
if ($request->has('name')) {
// Do something
}
}
// 注入 Request 和代入參數
public function update(Request $request, $id)
{
// 如果 Content-Type 是 application/json,可以用 dot 走訪 JSON arrays
$name = $request->input('user.name');
}
}