NỘI DUNG
Thay vì định nghĩa tất cả các xử lý request logic như Closures ở trong file routes, bạn có thể tổ chức lại việc này bằng cách sử dụng các class Controller. Controllers có thể nhóm các xử lý request logic vào một class. Controllers để tại thư mục app/Http/Controllers.
Cơ bản Controllers
Định nghĩa Controllers
Dưới đây là một ví dụ cơ bản về class controller. Chú ý rằng controller đấy kế thừa từ class base controller của Laravel. Class base controller cung cấp một vài phương thức như middleware
có thể sử dụng để gắn middleware vào controller:
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
public function show($id)
{
return view('user.profile', ['user' => User::findOrFail($id)]);
}
}
Bạn có thể định nghĩa một route cho action của controller như sau:
Route::get('user/{id}', 'UserController@show');
Bây giờ, khi một request giống với route URI, phương thức show
của class UserController
sẽ được thực thi. Tất nhiên, tham số route sẽ được truyền đến hàm.
Controllers không yêu cầu kế thừa từ base class. Tuy nhiên, bạn sẽ không có thêm một số tính năng như một số phương thức middleware
, validate
, và dispatch
.
Controllers & Namespaces
Có điều rất quan trọng cần lưu ý là chúng ta không cần phải ghi rõ tên đẩu đủ của controller namespace khi chúng ta định nghĩa cho controller route. Kể từ khi RouteServiceProvider
tải file route bên trong nhóm route có chứa namespace, chúng ta chỉ cần chỉ định tên class sau App\Http\Controllers
namespace.
If you choose to nest your controllers deeper into the App\Http\Controllers
directory, simply use the specific class name relative to the App\Http\Controllers
root namespace. So, if your full controller class is App\Http\Controllers\Photos\AdminController
, you should register routes to the controller like so:
Route::get('foo', 'Photos\AdminController@method');
Một Action Controllers
Nếu bạn muốn định nghĩa một controller xử lý duy nhất một action, bạn có thể dùng phương thức __invoke
trong controller:
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
class ShowProfile extends Controller
{
public function __invoke($id)
{
return view('user.profile', ['user' => User::findOrFail($id)]);
}
}
Khi đó bạn đăng ký một route cho một action controllers, bạn không cần xác định phương thức:
Route::get('user/{id}', 'ShowProfile');
Controller Middleware
Middleware có thể được gán cho controller route ở trong file route:
Route::get('profile', 'UserController@show')->middleware('auth');
Tuy nhiên, sẽ tiện hơn nếu middlewar được để trong hàm constructor của controller. Sử dụng phương thức middleware
trong hàm constructor của controller, Bạn có thể dễ dàng gán middleware cho action controller. Bạn thậm chí còn có thể hạn chế cho một vài phương thức cụ thể ở trong class controller:
class UserController extends Controller
{
public function __construct()
{
$this->middleware('auth');
$this->middleware('log')->only('index');
$this->middleware('subscribed')->except('store');
}
}
ontroller còn cho phép bạn đăng ký middleware sử dụng một Closure. Phương thức này khá thuận tiện để định nghĩa một middleware cho một controller mà không cần định nghĩa class middleware:
$this->middleware(function ($request, $next) {
// ...
return $next($request);
});
Bạn có thể gán middleware cho một tập con các action của controller; tuy nhiên, tập con action có thể to ra khi controller của bạn nhiều action. Vì thế, nên cân nhắc việc chia thành nhiều controller nhỏ hơn.
Resource Controllers
Laravel resource routing gán kiểu “CRUD” routes cho một controller chỉ với một dòng code. Ví dụ, bạn có thể tạo một controller xử lý tất cả HTTP requests cho “photos” lưu trong ứng dụng của bạn. Sử dụng lệnh make:controller
Artisan, chúng ta có thể nhanh chóng tạo ra một controller:
php artisan make:controller PhotoController --resource
Câu lệnh trên sẽ sinh ra một controller tại thư mục app/Http/Controllers/PhotoController.php
. Controller sẽ bao gồm method cho các action của resource có sẵn.
Tiếp theo, bạn phải đăng ký một resourceful route cho controller:
Route::resource('photos', 'PhotoController');
Khai báo route này sẽ tạo ra nhiều route để xử lý đa dạng các actions trong resource. Controller tạo ra sẽ có sẵn vài phương thức gốc dễ cho từng action, gồm những thông báo cho bạn những method HTTP và URIs nó xử lý.
Các action xử lý bởi Resource Controller
Verb | URI | Action | Route Name |
---|---|---|---|
GET | /photos |
index | photos.index |
GET | /photos/create |
create | photos.create |
POST | /photos |
store | photos.store |
GET | /photos/{photo} |
show | photos.show |
GET | /photos/{photo}/edit |
edit | photos.edit |
PUT/PATCH | /photos/{photo} |
update | photos.update |
DELETE | /photos/{photo} |
destroy | photos.destroy |
Spoofing Form Methods
Hãy nhớ rằng HTML forms không hỗ trợ các request PUT
, PATCH
, hoặc DELETE
, bạn sẽ cần thêm một trường hidden _method
vào spoof HTTP verbs. Phương thức method_field
có thể làm điều đó sẽ giúp bạn:
{{ method_field('PUT') }}
Từng phần Resource Routes
Khi bạn khai báo một resource route, bạn có thể chỉ định các tập con action của controller cần xử lý thay vì toàn bộ action mặc định ban đầu:
Route::resource('photo', 'PhotoController', ['only' => [
'index', 'show'
]]);
Route::resource('photo', 'PhotoController', ['except' => [
'create', 'store', 'update', 'destroy'
]]);
Tên Resource Routes
Mặc định, tất cả các action của resource controller đều có tên route; tuy nhiên, bạn có thể ghi đè tên đó bằng cách truyền thêm mảng chứa names
với tùy chọn của bạn:
Route::resource('photo', 'PhotoController', ['names' => [
'create' => 'photo.build'
]]);
Tên tham số Resource Route
Mặc định, Route::resource
sẽ sinh ra tham số route cho resource routes dựa trên tên của resource. Bạn có thể dễ dàng ghi đè cho từng phần resource cơ bản bằng cách truyền parameters
trong mảng như bên dưới. Tham số parameters
nên là một mảng kết hợp giứa tên resource và tên tham số:
Route::resource('user', 'AdminUserController', ['parameters' => [
'user' => 'admin_user'
]]);
Ví dụ trên sẽ tạo ra những URI sau cho route show
của resource:
/user/{admin_user}
Bổ sung Resource Controllers
Nếu bạn cần thêm route cho một resource controller ngoài các thiết lập mặc định của resource route, thì bạn nên định nghĩa những routes đó trướckhi gọi Route::resource
; nếu không thì những route đã được định nghĩa bởi resource
method có thể vô tình bị ưu tiên hơn những route bạn bổ sung:
Route::get('photos/popular', 'PhotoController@method');
Route::resource('photos', 'PhotoController');
Bạn nên tập trung vào controllers. Nếu bạn thấy mình thường xuyên thêm các route bên ngoài của các resource route thì hãy cân nhắc chia nhỏ controller hơn.
Dependency Injection & Controllers
Constructor Injection
Phần service container Laravel sử dụng để xử lý tất cả các controllers. Kết quả là, bạn có thể type-hint bất cứ dependencies controller của bạn cần vào trong constructor. Các dependencies sẽ tự động xử lý và injected trong controller:
<?php
namespace App\Http\Controllers;
use App\Repositories\UserRepository;
class UserController extends Controller
{
protected $users;
public function __construct(UserRepository $users)
{
$this->users = $users;
}
}
Tất nhiên,bạn cũng có thể type-hint bất cứ Laravel contract. Nếu các thành phần có thể được giải quyết, bạn có thể type-hint nó. Phụ thuộc vào ứng dụng của bạn, inject dependencies của bạn vào trong controller có thể là một cách tốt hơn.
Phương thức Injection
Ngoài cách constructor injection, bạn cũng có thể type-hint dependencies trong phương thức controller. Một trường hợp phổ biến là phương thức injection là trường hợp injecting Illuminate\Http\Request
vào trong phương thức controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class UserController extends Controller
{
public function store(Request $request)
{
$name = $request->name;
//
}
}
Nếu phương thức controller của bạn cũng chờ đợi đầu vào từ tham số của routes, đơn giản là liệt kê các đối số của route sau các dependencies khác. ví dụ, nếu route của bạn định nghĩa như sau:
Route::put('user/{id}', 'UserController@update');
Bạn vẫn có thể type-hint vào Illuminate\Http\Request
và truy cập vào tham số id
bằng cách định nghĩa phương thức controller như sau:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class UserController extends Controller
{
public function update(Request $request, $id)
{
//
}
}
Route Caching
Closure based routes không hoạt động cached. Để sử dụng route caching, bạn phải chuyển các Closure routes sang sử dụng các class controller.
Nếu ứng dụng của bạn chỉ sử dụng các controller based routes, thì bạn có thể sử dụng phần nâng cao route cache của Laravel. Sử dụng route cache sẽ giảm thời gian cần đăng ký tất cả các route trong ứng dụng của bạn. Trong một vài trường hợp, việc đăng ký route mcó thể nhanh hơn 100x lần. Để tạo ra route cache, just execute thechỉ cần chạy lệnh route:cache
Artisan:
php artisan route:cache
Sau khi chạy lệnh, file cached routes của bạn sẽ được tải với mọi request. Nhớ rằng, nếu bạn thêm một route mới bạn cần phải làm mới lại route cache. Vì ký do này bạn chỉ lên chạy một lần khi route:cache
ứng dụng của bạn deploy.
Bạn có thể sử dụng lệnh route:clear
để xóa route cache:
php artisan route:clear