Ở phần trước ta đã cùng nhau tìm hiểu về Route nơi định nghĩa các định tuyến, quyết định các request sẽ được điều hướng đến các action nào, coltroller nào.Ở phần này ta sẽ cùng nhau tìm hiểu Middleware.

Middleware trong Laravel framework

Định nghĩa Middleware

Middleware(Trung gian) là nơi các request sẽ phải đi qua một phần trước khi thưc hiện cho 1 action nào đó. VD: Laravel đã có sẵn middleware xác thực người dùng đăng nhập vào hệ thống khi ta khởi tạo project, nếu người dùng đã đăng nhập thì sẽ cho phép thực hiện các request của người dùng, còn không sẽ chuyển hướng đến trang login và yêu cầu đăng nhập.

Tất nhiên, ngoài các middleware được Laravel cung cấp sẵn bạn có thể viết thêm middleware để thực hiện nhiều tác vụ nữa ngoài kiểm tra đăng nhập vào hệ thống và tất cả các middleware sẽ nằm trong thư mục app/Http/Middleware.

Tạo Middleware

Để tạo mới một middleware, ta sẽ dùng lệnh

php artisan make:middleware MyMiddleware

Lệnh này sẽ tạo ra một class mới Mymiddleware trong thư mục app/Http/Middleware.


<?php
namespace App\Http\Middleware;
use Closure;
class MyMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        return $next($request);
    }
}

Before & After Middleware

Việc middleware chạy trước hay chạy sau một request phụ thuộc vào middleware đó. Ví dụ, middleware sau sẽ thực hiện một số tác vụ trước khi request được chương trình xử lý:

<?php
 namespace
 App\Http\Middleware;
 use Closure;
 class BeforeMiddleware
 {
     public function handle($request, Closure $next)
     {
       // Perform action return $next($request);
     }   
 }

Tuy nhiên, middleware này sẽ thực hiện nhiệm vụ của nó sau khi request được xử lý bởi ứng dụng:

<?php
 namespace App\Http\Middleware;
 use Closure;
 class AfterMiddleware
 {
     public function handle($request, Closure $next)
       {
         $response = $next($request);
         // Perform action return $response; 
       }
 }

Sử dụng và đăng ký Middleware

-Global Middleware:Global middleware là một middleware mà bất cứ HTTP request nào muốn thực hiện được cũng bắt buộc phải qua nó. Để một middleware có thể thực thi trong mỗi HTTP request tới hệ thống, đơn giản ta chỉ cần thêm tên class của middleware đó vào trong thuộc tính middleware của class app/Http/Kernel.php

Để đăng ký global middleware bạn sẽ phải vào: app/Http/Kernel.php tìm đến đoạn:

protected $middleware = [ \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class, ];

Đăng ký với cú pháp:

\App\Http\Middleware\MiddlewareName::class

Trong đó : MiddlewareName là tên middleware các bạn muốn thêm.

VD: Mình muốn thêm middleware CheckAge

protected $middleware = [

          \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,

          \App\Http\Middleware\CheckAge::class,

];

-Gán middleware cho route: Khác với Global Middleware, Route middleware chỉ sử dụng được khi bạn gọi nó ở trong Route

Để đăng ký Route Middleware thì mọi người cũng cần phải vào app/Http/Kernel.php tìm đến đoạn code:

protected $routeMiddleware = [
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];

Đăng ký với cú pháp:

'Name'=> \App\Http\Middleware\MiddlewareName::class

Trong đó:

  • Name: là tên các bạn muốn đặt cho middleware.

  • MiddlewareName:  là tên của Middleware các bạn muốn thêm.

VD: Mình sẽ thêm middleware CheckNum vào Route Middleware.

'Checknum'=>\App\Http\Middleware\CheckNum::class,

Sau khi đăng ký xong middleware các bạn có thể sử dụng nó với route như sau:

Route::get('admin/profile', function () {
//
})->middleware('Checknum');

Hoặc cũng có thể sử dụng tên đầy đủ của Middleware như sau:

use App\Http\Middleware\CheckNum;
Route::get('admin/profile', function () {
//
})->middleware(Checknum::class);

-Middleware Groups

Đôi khi có thể bạn muốn nhóm một vài middleware lại trong một key để thực hiện gán vào route dễ dàng hơn.Ta có thể sử dụng thuộc tính `$middlewareGroups`của HTTP kernel.

Ngoài ra, Laravel đi kèm với các nhóm middleware web và api có chứa các middleware phổ biến mà bạn có thể áp dụng cho giao diện người dùng trên các route web và các api của mình:

protected $middlewareGroups = [
        'web' => [ \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
         ],
        'api' => [
            'throttle:60,1',
            'bindings', 
         ], 
  ];

Và sử dụng trong Route với cú pháp:

Route::get('/', function () {
//
})->middleware('web');

hoặc

Route::group(['middleware' => ['web']], function () {
//
});

-Middleware tham số: Middleware cũng có thể nhận các tham số truyền vào. Ví dụ, nếu chương trình cần xác nhận user đã được xác thực có "role" cụ thể trước khi thực hiện một thao tác nào đó, bạn có thể tạo ra CheckRole để nhận tên của role như một tham số.Các tham số của middleware sẽ được truyền vào thành tham số của hàm handle ngay sau tham số $next:

namespace App\Http\Middleware;
use Closure;
class CheckRole
{
   /**
     * Handle the incoming request.
     * * @param \Illuminate\Http\Request $request
     * @param \Closure $next
     * @param string $role
     * @return mixed
     */
      public function handle($request, Closure $next, $role)
      {
             if (! $request->user()->hasRole($role)) {
               // Redirect...
              }
       return $next($request);
     }
}

Tham số middleware có thể được khai báo trên route bằng cách phân chia tên middleware và tham số bởi dấu :. Nhiều tham số thì cần được phân chia bởi dấu phẩy:

Route::put('post/{id}', function ($id) {
//
})->middleware('role:editor');

-Terminable Middleware: Đôi khi một middleware có thể cần thực hiện sau khi HTTP response đã được gửi xong cho trình duyệt. Ví dụ, "session" middleware có trong Laravel ghi dữ liệu session cho storage sau khi response được gửi tới trình duyệt. Nếu bạn định nghĩa một phương thức terminate vào trong middleware, nó sẽ tự động được gọi sau khi response được gửi tới trình duyệt.

<?php
 namespace Illuminate\Session\Middleware;
 use Closure;
 class StartSession
  {
     public function handle($request, Closure $next)
          {
           return $next($request);
          }
     public function terminate($request, $response)
          {
          // Store the session data... 
          }
 }

Phương thức terminate sẽ nhận cả request và response (các phương thức này mình sẽ đề cập ở các bài viết về sau). Khi mà bạn khai báo một terminable middleware, bạn nên thêm nó vào trong danh sách global middleware trong HTTP kernel.

Khi gọi hàm terminate trong middleware, Laravel sẽ thực hiện giải quyết trường hợp mới cho middleware từ service container. Nếu bạn muốn sử dụng cùng một trường hợp khi mà hàm handle và hàm terminate được gọi, đăng ký middleware vào trong container sử dụng hàm singleton.

Tổng kết

Trên đây mình đã hướng dẫn mọi người làm việc với middleware trong Laravel.Hy vọng nó sẽ giúp bạn có thêm kiến thức khi sử dụng Laravel nhé!