Bài 6: Laravel – Controllers
Basic Controllers Trong framework MVC, ký tự ‘C’ là viết tắt Controller. Nó hoạt động như một điều phối luồng giữa Views và Models. Tạo một Controller Mở command prompt hoặc terminal tùy vào bạn đang xài window hay linux, bằng việc sử dụng Artisan CLI(Command Line ...
Basic Controllers
Trong framework MVC, ký tự ‘C’ là viết tắt Controller. Nó hoạt động như một điều phối luồng giữa Views và Models.
Tạo một Controller
Mở command prompt hoặc terminal tùy vào bạn đang xài window hay linux, bằng việc sử dụng Artisan CLI(Command Line Interface) để tạo controller.
php artisan make:controller <controller-name>
Thay thế <controller-name> với tên controller bạn muốn đặt.
Nếu bạn muốn thêm đối số để khi tạo ra file controller đồng thời cũng tạo một số phương thức CRUD thì bạn có thể thêm đối số –resource sau tên controller như sau:
php artisan make:controller <controller-name> –resource
Lưu ý: phiên bản cũ thì dùng –plain để tạo constructor (đã remove ở version dùng tutorial này)
File controller được tạo sẽ nằm ở app/Http/Controllers. Bạn sẽ thấy code cơ bản đã được tạo sẳn cho bạn và bạn có thể thêm code của bạn vào.
Controller đã tạo có thể được gọi từ file định tuyến routes/web.php với cú pháp sau:
Syntax
Route::get(‘base URI’,’controller@method’);
Example
Step 1: tạo controller UserController.
php artisan make:controller UserController –-resource
Step 2: sau khi thành công bạn sẽ thấy output sau:
Step 3: bạn có thể thấy controller đã tạo ở app/Http/Controller/UserController.php với một số code cơ bản đã được ghi cho bạn, và bạn có thể thêm code của bạn dựa vào nhu cầu của bạn.
Controller Middleware
Chúng ta đã thấy middleware ở bài trước đó và nó có thể được sử dụng với controller.
Middleware cũng có thể được phân công tới định tuyến(route) của controller hoặc bên trong constructor của controller. Bạn có thể sử dụng phương thức middleware để phân công middleware tới controller. Đăng ký middleware cũng có thể bị giới hạn tới các phương thức nhất định của controller.
Phân công Middleware tới Route
Route::get(‘profile’, [
‘middleware’ => ‘auth’,
‘uses’ => ‘UserController@showProfile’
]);
Ở đây chúng ta đang phân công middleware “auth” tới UserController trong định tuyến profile (profile route).
Phân công Middleware bên trong Constructor của Controller
class UserController extends Controller {
public function __construct(){
$this->middleware(‘auth’);
}
}
Ở đây chúng ta đang phân công middleware ‘auth’ sử dụng phương thức middleware trong constructor của controller.
Example
Step 1: thêm các dòng sau tới file routes/web.php và lưu nó lại.
Route::get(‘/usercontroller/path’,[
‘middleware’ => ‘First’,
‘uses’ => ‘UserController@showPath’
]);
Tốt nhất là để nó ở cuối file.
Step 2 : tạo một middleware gọi là FirstMiddleware bằng cách thực hiện lệnh sau:
php artisan make:middleware FirstMiddleware
Step 3 : thêm các dòng code trong phương thức handle trong file middleware vừa mới tạo ở app/Http/Middleware.
class FirstMiddleware {
public function handle($request, Closure $next) {
echo ‘<br>First Middleware’;
return $next($request);
}
}
Step 4: tạo một middleware gọi là SecondMiddleware.
php artisan make:middleware SecondMiddleware
Step 5: và thêm dòng code sau trong phương thức handle trong file SecondMiddleware.php.
class SecondMiddleware {
public function handle($request, Closure $next){
echo ‘<br>Second Middleware’;
return $next($request);
}
}
Step 6: tạo controller gọi là UserController, nếu các bạn đã tạo thử từ ví dụ đầu tiên để tracking bài viết thì tới bước này bạn không cần phải tạo nữa, tức là bạn đã tạo ở ví dụ giới thiệu controller ở trên rồi. (step 1).
Step 7: Copy dòng code sau tới app/Http/UserController.php.
class UserController extends Controller {
public function __construct(){
$this->middleware(‘Second’);
}
public function showPath(Request $request){
$uri = $request->path();
echo ‘<br>URI: ‘.$uri;
$url = $request->url();
echo ‘<br>’;
echo ‘URL: ‘.$url;
$method = $request->method();
echo ‘<br>’;
echo ‘Method: ‘.$method;
}
}
Step 8: chạy lệnh sau nếu bạn chưa chạy nó
php artisan serve
Lệnh này cho php chạy bên trong web server, tức là bạn gõ http://localhost:8000 nó sẽ thực thi laravel của bạn.
Step 9: chạy url sau trên browser
http://localhost:8000/usercontroller/path
Step 10: và kết quả ra là:
Lưu ý : nếu các bạn chạy ra lổi thì hãy đọc bài Laravel – Middleware sẽ hiểu nguyên do. Ở đây không phải đánh đố các bạn, mà tôi muốn chắc là các bạn đang luyện tập nó một cách nghiêm túc. Hoặc các bạn hãy comment bên dưới bài học, mình sẽ giải đáp cho các bạn.
Rồi chúng ta qua mục mới .
Restful Resource Controllers
Thường thì khi tạo một ứng dụng chúng ta cần thực hiện CRUD (Create, Read, Update, Delete). Laravel tạo công việc này dể dàng cho chúng ta. Chỉ cần tạo controller và Laravel sẽ tự động cung cấp tất cả các phương thức cho CRUD. Bạn cũng có thể đăng ký 1 route duy nhất cho tất cả các phương thức tại routes/web.php (xem step 3 ví dụ dưới đây).
Example
Step 1 : tạo một controller gọi là MyController với câu lệnh sau :
php artisan make:controller MyController –resource
Như tôi đã đề cập ở trên là khi tạo controller ta thêm đối số –resource thì controller khi mới tạo ra nó sẽ có đủ các phương thức CRUD cho các bạn.
Lưu ý: với phiên bản cũ thì không cần đối số để tạo controller CRUD.
Step 2: thêm code sau vào app/Http/Controllers/MyController.php.
Nếu tạo controller thành công bạn mở ra và sẽ thấy các function tạo sẳn, hãy vào thêm code như sau:
class MyController extends Controller {
public function index(){
echo ‘index’;
}
public function create(){
echo ‘create’;
}
public function store(Request $request){
echo ‘store’;
}
public function show($id){
echo ‘show’;
}
public function edit($id){
echo ‘edit’;
}
public function update(Request $request, $id){
echo ‘update’;
}
public function destroy($id){
echo ‘destroy’;
}
}
Chỉ là echo ra để biết nó chạy vô đâu mà thôi.
Step 3: định tuyến cho controller mới
Route::resource(‘my’,’MyController’);
Step 4: chúng ta đăng ký cho tất cả các phương thức của MyController bằng cách đăng ký một controller với ‘resource’. Bảng dưới đây mô tả các action xử lý bởi resource controller.
Method | Path | Action | Route Name |
GET | /my | index | my.index |
GET | /my/create | create | my.create |
POST | /my | store | my.store |
GET | /my/{my} | show | my.show |
GET | /my/{my}/edit | edit | my.edit |
PUT/PATCH | /my/{my} | update | my.update |
DELETE | /my/{my} | destroy | my.destroy |
Lưu ý: Các bạn truyền theo phương thức nào với path tương ứng thì sẽ chạy vào phương thức được liệt kê như bảng : GET => /my và POST => /my chạy vô 2 phương thức khác nhau nha các bạn.
Step 5: vì phương thức POST là dạng truyền đặc biệt, có thể bạn dùng form hoặc dùng CURL do vậy để đơn giản cho luyện tập bài học này, chúng ta thử chạy url get để test.
Rồi bây giờ bạn thực hiện lần lượt các URL sau để xem kết quả.
URL | Description | Output Image |
http://localhost:8000/my | Executes index method of MyController.php | index |
http://localhost:8000/my/create | Executes create method of MyController.php | create |
http://localhost:8000/my/1 | Executes show method of MyController.php | show |
http://localhost:8000/my/1/edit | Executes edit method of MyController.php | edit |
Constructor Injection
Vấn đề này liên quan đến các khái niệm về Dependency Injection. Chúng ta sẽ học chuyên sâu hơn với tutorial Dependency Injection.
Trong khuôn khổ Laravel thì tôi xin diễn giải cách đơn giản nhất để các bạn dể hiểu. Bởi vì hầu hết tất cả framework tiên tiến sau này điều viết theo lối pattern Dependency Injection để khởi tạo đối tượng.
Hiểu như thế này: Thay vì bạn khởi tạo đối tượng là new Object rồi sử dụng nó bên trong class bạn cần, tôi ví dụ là trong class User bạn cần khởi tạo đối tượng Database để tạo lấy dữ liệu hoặc làm các cái bạn cần. Nhưng vấn đề xãy ra là bạn khó mà unit test nó, bởi khi test class user bạn lại phải test cả database, tức là bạn cũng phải implement các class mà thèn user phụ thuộc vào. Hơn nữa, nếu mà tôi thay đổi database class thì bạn lại phải chạy hết các nơi có khởi tạo đối tượng Database mà thay đổi theo.
Phương pháp dependency injection sẽ giúp bạn. Thay vì bạn gọi nó thì hãy để nó tự gọi bạn.
Nghĩa là đối tượng được cấp phát từ bên ngoài và nó sẽ tiêm vào (injection) nơi bạn cần sử dụng.
Có nhiều cách để tiêm vào, trong mục này là sẽ tiêm vào con đường Constructor. Tức là vừa tạo đối tượng class của bạn thì đối tượng tiêm vào cũng được tạo theo.
Dependency Injection là giúp giảm sự phụ thuộc các đối tượng với nhau, class nào thì làm nhiệm vụ của class đó mà thôi.
Example
Step 1: tạo controller với tên gọi là ImplicitController
php artisan make:controller ImplicitController
Step 2: trong file định tuyến chúng ta thêm code sau:
class MyClass{
public $foo = ‘bar’;
}
Route::get(‘/myclass’,’ImplicitController@index’);
Step 3: trong ImplicitController.php thêm code sau:
class ImplicitController extends Controller {
private $myclass;
public function __construct(MyClass $myclass){
$this->myclass = $myclass;
}
public function index(){
dd($this->myclass);
}
}
Step 4: chạy url sau http://localhost:8000/myclass
Step 5: kết quả:
Lưu ý: hàm dd là hàm mà laravel viết lại để dump đối tượng ra, bạn không thích thì dùng bất kỳ hàm khác để debug như var_dump, print_r, dump
Diễn giải:
File định tuyến chạy đầu tiên nên nó đã có được class MyClass ta định nghĩa, và trong constructor của class ImplicitController chúng ta đã injection cái MyClass vào, thế là ta có thể sử dụng MyClass rồi, nếu bạn có sữa đổi MyClass thì bạn ra chổ tạo đối tượng nó mà đổi, đâu có ảnh hưởng ăn nhậu gì tới ImplicitController đúng không, hehe thì ra Dependency Injection sử dụng đơn giản và hiệu quả như vậy.
Nếu các bạn vẩn còn chưa rõ DI thì chúng ta sẽ nghiên cứu kỹ ở tutorial khác, chỉ hiểu là chúng ta gửi đối tượng vào class khác khi muốn sử dụng mà không phải tạo instance of bên trong class.
Nhắc lại giữa controller và action phân biệt nhau bởi @ ‘ImplicitController@Index’
Method Injection
Nếu bạn đã biết và hiểu Constructor Injection thì phần này cũng đơn giản, tức là thay vì bạn đưa đối tượng vào constructor, rồi trong class Implicit bạn có thể sử dụng đối tượng này bất kỳ nơi nào, thì nếu bạn không muốn, bạn chỉ muốn đối tượng đó sử dụng cho một hàm nhất định mà thôi.
Vậy thì chúng ta sẽ đưa đối tượng, tiêm nó vào phương thức cần thiết.
EX
Hãy thay đổi ImplicitController như sau:
class ImplicitController extends Controller {
public function index(MyClass $myclass){
dd($myclass);
}
}
Bạn đã remove __constructor và thay vào đó khởi tạo đối tượng MyClass trong phương thức index.
Chạy lại http://localhost:8000/myclass sẽ cho cùng kết quả.