Controllers

Giới thiệu

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

Phía dưới 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
{
    /**
     * Show the profile for the given user.
     *
     * @param    int  $id
     * @return  Response
     */
    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
{
    /**
     * Show the profile for the given user.
     *
     * @param    int  $id
     * @return  Response
     */
    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
{
    /**
     * Instantiate a new new controller instance.
     *
     * @return  void
     */
    public function __construct()
    {
        $this->middleware('auth');

        $this->middleware('log')->only('index');

        $this->middleware('subscribed')->except('store');
    }
}

Controller 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 đó gú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
{
    /**
     * The user repository instance.
     */
    protected $users;

    /**
     * Create a new controller instance.
     *
     * @param    UserRepository  $users
     * @return  void
     */
    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
{
    /**
     * Store a new user.
     *
     * @param    Request  $request
     * @return  Response
     */
    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
{
    /**
     * Update the given user.
     *
     * @param    Request  $request
     * @param    string  $id
     * @return  Response
     */
    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
Nguồn: https://laravel.com/docs/5.3/controllers