Laravel 5 事件綁定器
官方文件名稱為 Laravel Event
此篇文章主要是以實例的方式來描述在什麼樣的情況下會用到 Laravel Event.
舉例來說
想像我們現在有一個需求是要記錄使用者在登入登出時的 IP 及最後登入時間並寫入 logs
下列有幾種方法,在這篇文章中午會介紹各種用法:
- 在 中介層(Middleware) 時處理 – 在 route 時綁定 指定的 middleware.
- 在 事件(Event) 時處理 – 根據 Laravel 官方所提供的預設事件
- 在 控制器(Controller)時處理 – request
事件 | 參數 |
artisan.start | $application |
auth.attempt | $credentials, $remember, $login |
auth.login | $user, $remember |
auth.logout | $user |
cache.missed | $key |
cache.hit | $key, $value |
cache.write | $key, $value, $minutes |
cache.delete | $key |
connection.{name}.beginTransaction | $connection |
connection.{name}.committed | $connection |
connection.{name}.rollingBack | $connection |
illuminate.query | $query, $bindings, $time, $connectionName |
illuminate.queue.after | $connection, $job, $data |
illuminate.queue.failed | $connection, $job, $data |
illuminate.queue.stopping | null |
mailer.sending | $message |
router.matched | $route, $request |
composing:{view name} | $view |
creating:{view name} | $view |
上圖為 Laravel 5 所提供的預設事件
在 中介層(Middleware) 時處理
在 Route 中我們加上登入時的路由
路由設定中介層
app/Http/routes.php
| // Login middleware |
| Route::group(['middleware' => 'login'], function () { |
| Route::post('login', function () { |
| // 使用 Login 中介層 |
| }); |
| }); |
第 2 行使用 route group 將登入時須先過 login 這個中介層
註冊中介層
這個名稱需定義在app/Http/Kernel.php
| |
| namespace App\Http; |
| use Illuminate\Foundation\Http\Kernel as HttpKernel; |
| class Kernel extends HttpKernel |
| { |
| /** |
| * The application's global HTTP middleware stack. |
| * |
| * @var array |
| */ |
| protected $middleware = [ |
| \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class, |
| \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, |
| ]; |
| /** |
| * The application's route middleware. |
| * |
| * @var array |
| */ |
| protected $routeMiddleware = [ |
| 'auth' => \App\Http\Middleware\Authenticate::class, |
| 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, |
| 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, |
| // 加入一個我們自定義的 login middleware |
| 'login' => \App\Http\Middleware\Login\InsertLogs::class, |
| ]; |
| } |
第 29 行註冊我們自定義的 login middleware
實作中介層
接著我們就要來撰寫中介層的內容 middleware
app/Http/Middleware/InsertLogs.php
| |
| |
| namespace App\Http\Middleware\Login; |
| |
| use Closure; |
| use Carbon; |
| use Maras0830\Repository\LogsRepository; |
| |
| class InsertLogs |
| { |
| protected $logsRepository; |
| |
| /** |
| * Create the middleware. |
| * @param LogsRepository $logsRepository |
| * @return void |
| */ |
| public function __construct(LogsRepository $logsRepository) |
| { |
| $this->logsRepository = $logsRepository; |
| } |
| |
| /** |
| * Handle an incoming request. |
| * |
| * @param \Illuminate\Http\Request $request |
| * @param \Closure $next |
| * @return mixed |
| */ |
| public function handle($request, Closure $next) |
| { |
| $response = $next($request); |
| |
| // 執行登入後的記錄 |
| if (Auth::check()) |
| $this->logsRepository->insertMemberLoginLogs(Auth::user(), $request->ip(), Carbon::NOW()); |
| |
| return $response; |
| } |
| } |
我們在 _construct 時注入我自定義的 repository interface
第 35~36 行為當使用者成功登入時我們填加一筆紀錄,其實這邊又有更多寫法
例如你可以先用 eloquent-relationships 去關聯 logs 並直接新增
在此就不多實作 insertMemberLoginLogs 方法
在 事件(Event) 時處理
第 1 步:註冊事件
註冊 Event listren 在 app/Event.php , 處理事件通常放在 app/Handlers/Events
app/Events/MemberLoginEvent.php
| namespace App\Events; |
| use App\Events\Event; |
| use Illuminate\Queue\SerializesModels; |
| use Illuminate\Http\Request; |
| |
| class MemberLoginEvent extends Event { |
| use SerializesModels; |
| |
| public $request; |
| /** |
| * Create a new event instance. |
| * @param Request $request |
| * @return void |
| */ |
| public function __construct(Request $request) |
| { |
| $this->request = $request; |
| } |
| } |
第 2 步:註冊事件監聽器
app/Providers/EventServiceProvider.php
| |
| |
| namespace App\Providers; |
| |
| use Illuminate\Contracts\Events\Dispatcher as DispatcherContract; |
| use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; |
| |
| class EventServiceProvider extends ServiceProvider |
| { |
| /** |
| * The event listener mappings for the application. |
| * |
| * @var array |
| */ |
| protected $listen = [ |
| // 註冊自定義的監聽器 |
| 'App\Events\MemberLoginEvent' => [ |
| 'App\Handlers\Events\MemberLoginEventHandler', |
| ], |
| ]; |
| |
| /** |
| * Register any other events for your application. |
| * |
| * @param \Illuminate\Contracts\Events\Dispatcher $events |
| * @return void |
| */ |
| public function boot(DispatcherContract $events) |
| { |
| parent::boot($events); |
| |
| // |
| } |
| } |
第 17 行我們註冊監聽自定義的事件綁定到我們接下來會需要處理的 handler
注意:這邊的指定方法跟routes指定的方式一樣,意思是你可以使用 @ 去指定你想要的 handler class 中的方法(例如:EventServiceProvider@doSomethingMethod,EventServiceProvider class 中的 doSomethingMethod),若無指定預設使用 handle method。
| |
| namespace App\Providers; |
| use Illuminate\Contracts\Events\Dispatcher as DispatcherContract; |
| use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; |
| class EventServiceProvider extends ServiceProvider |
| { |
| /** |
| * The event listener mappings for the application. |
| * |
| * @var array |
| */ |
| protected $listen = [ |
| // 註冊登入監聽器 |
| 'auth.login' => [ |
| 'App\Handlers\Events\AuthLoginEventHandler', |
| ], |
| ]; |
| /** |
| * Register any other events for your application. |
| * |
| * @param \Illuminate\Contracts\Events\Dispatcher $events |
| * @return void |
| */ |
| public function boot(DispatcherContract $events) |
| { |
| parent::boot($events); |
| // |
| } |
| } |
第 3 步:實作事件
app/Handlers/Events/MemberLoginEventHandler.php
| namespace App\Handlers\Events; |
| use App\Events\MemberLoginEvent; |
| use Illuminate\Queue\InteractsWithQueue; |
| use Illuminate\Contracts\Queue\ShouldBeQueued; |
| use Maras\Contracts\LogsRepositoryInterface; |
| |
| class MemberLoginEventHandler { |
| |
| protected $logsRepository; |
| /** |
| * Create the event handler. |
| * @param LogsRepository $logsRepository |
| * @return void |
| */ |
| public function __construct(LogsRepositoryInterface $logsRepository) |
| { |
| $this->logsRepository = $logsRepository; |
| } |
| /** |
| * Handle the event. |
| * |
| * @param MemberLoginEvent $event |
| * @return void |
| */ |
| public function handle(MemberLoginEvent $event) |
| { |
| // 執行登入後的記錄 |
| if (Auth::check()) |
| $this->logsRepository->insertMemberLoginLogs(Auth::user(), $event->request->ip(), Carbon::NOW()); |
| } |
| } |
第 15 行為當 construct時注入自定義的 repository interface,第 28~29 行,為處理此事件的過程。
若是使用 laravel 所提供的事件方法
| namespace App\Handlers\Events; |
| use App\Events\MemberLoginEvent; |
| use Maras\Contracts\LogsRepositoryInterface; |
| use Auth; |
| use Carbon\Carbon; |
| |
| class MemberLoginEventHandler |
| { |
| protected $logsRepository; |
| /** |
| * Create the event handler. |
| * @param LogsRepository $logsRepository |
| * @return void |
| */ |
| public function __construct(LogsRepositoryInterface $logsRepository) |
| { |
| $this->logsRepository = $logsRepository; |
| } |
| /** |
| * Handle the event. |
| * |
| * @param MemberLoginEvent $event |
| * @return void |
| */ |
| public function handle(MemberLoginEvent $event) |
| { |
| 執行登入後的記錄 這裏為了範例起見 先將它註解掉 |
| if (Auth::check()) |
| $this->logsRepository->insertMemberLoginLogs(Auth::user(), $event->request->ip(), Carbon::NOW()); |
| } |
| |
| } |
第 4 步:觸發事件
方法一:使用 event 觸發:
- event(new MemberLoginEvent());
方法二:使用 Event facade 觸發:
- Event::fire(new MemberLoginEvent());
以上兩種方法其實都是 call 同一個 function
通常會在 controller 實作,但若是使用 laravel 5 的預設使用者登入方法則可以不用觸發事件。
在 控制器(Controller)時處理
這種方式是在確認使用者登入後於 controller 添加
app\Http\Controllers\AuthController.php
| namespace App\Http\Controllers; |
| |
| use Auth; |
| use Illuminate\Routing\Controller; |
| use Maras\Contracts\LogsRepositoryInterface; |
| class AuthController extends Controller |
| { |
| protected $logsRepository; |
| |
| /** |
| * Create AuthController. |
| * |
| * @param LogsRepository $logsRepository |
| * @return void |
| */ |
| public function __construct(LogsRepositoryInterface $logsRepository) |
| { |
| $this->logsRepository = $logsRepository; |
| } |
| |
| /** |
| * Handle an authentication attempt. |
| * |
| * @return Response |
| */ |
| public function authenticate() |
| { |
| if (Auth::attempt(['email' => $email, 'password' => $password])) |
| { |
| $this->logsRepository->insertMemberLoginLogs(Auth::user(), $this->request->ip(), Carbon::NOW()); |
| return redirect()->intended('dashboard'); |
| } |
| } |
| |
| } |
reference : http://codingweb.tw/2016/06/04/laravel-5-event-事件/
沒有留言:
張貼留言