12/08/2018, 14:26

Tìm hiểu Laravel (P9) - Controller

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ẽ ...

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ục app/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 AppHttpControllers;

    use AppUser;
    use AppHttpControllersController;

    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ớp UserController 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', 'PhotosAdminController@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 AppHttpControllers;

    use AppUser;
    use AppHttpControllersController;

    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ệnh make: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, hay DELETE, 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');

0