Tìm hiểu Laravel (P9) - Controller
Bài đăng này đã không được cập nhật trong 8 năm
Indexs
- Phần 1: Cài đặt
- Phần 2: Form đăng nhập
- Phần 3: Send Mail
- Phần 4: Error page
- Phần 5: Application Structure
- Phần 6: Logging
- Phần 7: Routing
- Phần 8: Middleware
- Để tiếp tục seri tìm hiểu laravel, bài này ta sẽ tìm hiểu về
controller
, nơi chứa các xử lý logic mà ta sẽ phải làm việc thường xuyên khi phát triển dự án.
1. Giới thiệu
- Thông thường ta hay có xu hướng viết tất tần tật xử lý logic trong
routes
, chẳng hạn như sau:
/* Add new Task */
Route::post('/task', function(Request $request) {
$validator = Validator::make($request->all(), [
'name' => 'required|max:225',
]);
if ($validator->fails()) {
return redirect('/')
->withInput()
->withErrors($validator);
}
$task = new Task;
$task->name = $request->name;
$task->save();
return redirect('/task');
});
- Cách viết như trên không sai, nhưng về lâu dài sẽ khiến cho file router phình to, khó quản lý và cũng không đúng với mục đích của Router. Vậy nên thay vì định nghĩa tất cả logic xử lý request của bạn ở file
routes.php
, thì ta có thể muốn quản lý việc này bằng cách sử dụng các lớp Controller, còn router chỉ làm nhiệm vụ điều hướng các request đến các controller. Các Controller có thể nhóm các request HTTP có logic liên quan vào cùng một lớp và được chứa tại thư mụcapp/Http/Controllers
.
2. Controllers cơ bản
- Một controller cơ bản sẽ được định nghĩa như sau, mỗi controller cần được lớp base controller được tạo sẵn bởi Laravel:
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
/**
* Show the profile for the given user.
*
* @param int $id
* @return Response
*/
public function show($id)
{
return view('user.profile', ['user' => User::findOrFail($id)]);
}
}
- Đây là controller xử lý việc lấy ra thông tin của một user, để hiển thị được thông tin của user ta cần định nghĩa định tuyến trong router như sau:
Route::get('user/{id}', 'UserController@show');
- Bây giờ, khi mà một request khớp với URI của định tuyến đã được xác định, thì method
show
của lớpUserController
sẽ được thực thi. Tất nhiên, tham số của định tuyến cũng sẽ được truyền đến method. - Nếu dự án của bạn ngày càng phát triển, ngày càng phình to hơn, và bạn muốn gom nhóm các xử lý, các controller lại thành từng nhóm như đã nói ở trên thì ta chỉ việc tạo thêm thư mục controng thư mục
app/Http/Controllers
, chẳng hạn nhưapp/Http/Controllers/Photos
. Khi đó router ta cần định nghĩa lại:
Route::get('foo', 'Photos\AdminController@method');
- Trường hợp controller của bạn chỉ xử lý một hành động đơn lẻ thì ta có thể thay thế method bằng method
__invoke
:
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
class ShowProfile extends Controller
{
/**
* Show the profile for the given user.
*
* @param int $id
* @return Response
*/
public function __invoke($id)
{
return view('user.profile', ['user' => User::findOrFail($id)]);
}
}
- Và khi đăng kí định tuyến ta không cần quan tâm đến method nữa:
Route::get('user/{id}', 'ShowProfile');
3. Controller Middleware
- Như đã tìm hiểu ở bài trước thì Middleware có thể được gán cho định tuyến của controller trong file route như sau:
Route::get('profile', 'UserController@show')->middleware('auth');
- Tuy nhiên, sẽ là tiện lợi hơn nếu như ta định nghĩa middleware từ trong hàm
contructor
của controller. Sử dụng method middleware từ trong controller, ta có thể dễ dàng gán middleware cho controller. Thậm ta chí có thể hạn chế middleware cho một vài method cụ thể trong lớp controller:
class UserController extends Controller
{
/**
* Instantiate a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('log')->only('index');
$this->middleware('subscribed')->except('store');
}
}
- Khi đó ta không cần gán middleware trong file router nữa mà request vẫn phải đi qua midlleware trước khi đến method
Route::get('profile', 'UserController@show');
4. Resource Controllers
- Còn nhớ ở phần 2 ta đã sử dụng lệnh
php artisan make:auth
để tạo nhanh các view, controller.. (có thể về sau mình sẽ có bài về câu lệnh artisan thần thánh này :v) - Tương tự như vậy ta cũng có thể dùng câu lệnh artisan sau để tạo ra một controller mẫu, chứa sẵn các method gốc rễ ứng với từng phương thức:
php artisan make:controller PhotoController --resource
- Kết quả thu được sau khi chạy câu lệnh trên là controller
app/Http/Controllers/PhotoController.php
được tạo ra. - Nếu lệnh
make:auth
đã update router cho ta thì với lệnhmake:controller
đơn lẻ ta cần thêm định tuyến bằng tay:
Route::resource('photos', 'PhotoController');
- Khai báo định tuyến duy nhất này tạo ra nhiều định tuyến tương ứng với mỗi method trong
PhotoController.php
, cụ thể như sau:
|_. Verb |_. Path |_. Action |_. Route Name |
| GET | /photo | index| photo.index |
| GET | /photo/create | create | photo.create |
| POST | /photo | store | photo.store |
| GET | /photo/{photo} | show | photo.show |
| GET | /photo/{photo}/edit | edit | photo.edit |
| PUT/PATCH | /photo/{photo} | update | photo.update |
| DELETE | /photo/{photo} | destroy | photo.destroy |
- Lưu ý HTML form không thể tạo ra các request như
PUT
,PATCH
, hayDELETE
, thì ta cần phải thêm một trường ẩn_method
để giả mạo những HTTP method.
{{ method_field('PUT') }}
hoặc
<input type="hidden" name="_method" value="PUT">
- Theo như khai báo route kiểu resource ở trên thì ta có thể gửi request đến tất cả các method với các URI tương ứng, nhưng vì lý do nào đó mà ta muôn giới hạn một số URI thì ta có thể làm như sau:
Route::resource('photo', 'PhotoController', ['only' => [
'index', 'show'
]]);
Route::resource('photo', 'PhotoController', ['except' => [
'create', 'store', 'update', 'destroy'
]]);
- Mặc định, tất cả các hành động của controller tài nguyên đều có tên; tuy nhiên, ta có thể ghi đè những tên đó bằng cách truyền thêm chuỗi name sao cho phù hợp:
Route::resource('photo', 'PhotoController', ['names' => [
'create' => 'photo.build'
]]);
- Để truyền tham số vào URI
Route::resource('user', 'AdminUserController', ['parameters' => [
'user' => 'admin_user'
]]);
- Hay thêm một định tuyến (cần định nghĩa trước
Route::resource
):
Route::get('photos/popular', 'PhotoController@method');
Route::resource('photos', 'PhotoController');
Tài liệu tham khảo Laravel Controller
All rights reserved