eventlistener使いこなし術 - symfony勉強会#10
DESCRIPTION
Symfony勉強会#10 の LT枠で発表してきた内容です。 ブログ http://okapon-pon.hatenablog.com/entry/2014/07/29/015745TRANSCRIPT
![Page 1: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/1.jpg)
EventListener 使いこなし術
Symfony 勉強会 #10岡田祐一 @okapon_pon
![Page 2: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/2.jpg)
自己紹介•名前:岡田祐一 (@okapon_pon)
• 所属:株式会社クロコス エンジニア
• 2013年~ 日本Symfonyユーザー会
• Symfony歴 2年半ほど
![Page 3: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/3.jpg)
本日の話
EventListener使いこなし術
あらため
EventListenerできること
![Page 4: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/4.jpg)
まえおき
!
Symfonyについて
![Page 5: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/5.jpg)
Symfony
!
素直で柔軟なフレームワーク
![Page 6: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/6.jpg)
Symfony
!
HWに縛られず自由に開発できる
![Page 7: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/7.jpg)
Symfony
柔軟性を支える屋台骨
• DI (+ configuration)
• Event DispatcherEventListenerはここの話
![Page 8: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/8.jpg)
Symfony
イベント駆動のフレームワーク
!
フックポイントが用意されている!
![Page 9: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/9.jpg)
Symfonyのイベント
標準で用意されてるイベント !
• kernel.request • kernel.controller • kernel.view • kernel.response • kernel.exception
![Page 10: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/10.jpg)
Symfonyのイベント
任意のイベントにフック可能
任意のタイミングでResponseを返すことが可能
![Page 11: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/11.jpg)
EventListener 実例
それでは例を見ていきましょう
![Page 12: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/12.jpg)
kernel.controllerイベント
kernel.controllerイベント !
コントローラーの実行前に 発行されるイベント
![Page 13: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/13.jpg)
kernel.controllerイベント
BeforFilterControllerListener というクラスを作ってみます
![Page 14: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/14.jpg)
kernel.controllerイベント
EventLisnerを登録# service.yml services: my.blog.before_filter_controller_listener: class: My\BlogBundle\EventListener\BeforFilterControllerListener tags: - { name: kernel.event_listener, event: kernel.controller, method: onKernelController }
![Page 15: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/15.jpg)
EventListenerクラス作成class BeforeFilterControllerListener { public function onKernelController(FilterControllerEvent $event) { $c = $event->getController(); if (!is_array($c)) { return; } $controller = $c[0]; ! if (method_exists($controller, 'before')) { $controller->before($event->getRequest(); } } }
![Page 16: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/16.jpg)
EventListenerクラス作成
何やってるか分かりました?
![Page 17: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/17.jpg)
コントローラー側/** * @Route("/blog") * @Template() */ class BlogController extends Controller { public function before(Request $request) { // Actionが呼ばれる前に実行したい処理が書ける } ! /** * @Route("/", name="blog_index") */ public function indexAction() { } }
![Page 18: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/18.jpg)
Controller実行前のフック
どこかのフレームワークで 見たことある機能・・・
![Page 19: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/19.jpg)
なぜSymfonyにないのか?
コントローラーに書くと
• 再利用しにくい
• テストしづらい
![Page 20: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/20.jpg)
なぜSymfonyにないのか?
もう一度コードに戻ります
![Page 21: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/21.jpg)
class BeforeFilterControllerListener { public function onKernelController(FilterControllerEvent $event) { $c = $event->getController(); if (!is_array($c)) { return; } $controller = $c[0]; ! if (method_exists($controller, 'before')) { $controller->before($event->getRequest(); } } }
EventListenerクラス作成
コントローラー側に書く必要がないと感じませんか?
![Page 22: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/22.jpg)
EventListener まとめ1
EventListenrに記述した方が変な依存を持たずシンプルに実装
できる 【サンプルコード】 https://gist.github.com/okapon/fd2dfdacf87e417f7957
![Page 23: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/23.jpg)
EventListener 実装例
Securityコンポーネント よく分からなくて昔作ったオレオレ認証
https://gist.github.com/okapon/88f5bd56a886c287a7d1
![Page 24: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/24.jpg)
EventListener 実装例
先ほどの実装例では isSecure()メソッドはマーカー → annotationにするとよい
!
【参考】Doctrine-Common-Annotations http://docs.doctrine-project.org/projects/doctrine-common/en/latest/reference/annotations.html
![Page 25: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/25.jpg)
EventListener まとめ2
ユーザー認証の仕組みもEventListenrを使えば 簡単に実装できる
![Page 26: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/26.jpg)
ちなみに
ここまでkernel.controllerを取り上げといてなんですが・・・ よく使うのは • kernel.request • kernel.response
![Page 27: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/27.jpg)
では気を取り直して
![Page 28: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/28.jpg)
EventListener使いどころ複数コントローラーで実行したい共通処理
• 認証まわり • 初回登録時のアクセス判定 • チュートリアルの完了状態で表示出し分け • アクセスの分析(referrerとか)
![Page 29: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/29.jpg)
チュートリアルの表示判定する例
ユーザーはどこのURLにでもアクセスする可能性がある
!
• kernel.requestをフック • EventListenerでチュートリアル完了か判定 • 完了してなければチュートリアルを表示
![Page 30: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/30.jpg)
TutorialListener実装例1class TutorialListener { public function onKernelRequest(GetResponseEvent $event) { if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) { return; } if (!$this->securityContext->getToken()) { return; } ! $user = $this->securityContext->getToken()->getUser(); if ($this->doseNeedTutorial($user)) { // チュートリアルのURLにリダイレクトするとか $event->setResponse(new RedirectResponse('/tutorial', 302)); } } }
![Page 31: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/31.jpg)
TutorialListener実装例2class TutorialListener { public function onKernelRequest(GetResponseEvent $event) { if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) { return; } if (!$this->securityContext->getToken()) { return; } ! $user = $this->securityContext->getToken()->getUser(); if ($this->doseNeedTutorial($user)) { // sessionに状態を入れるとか $this->session->set(’needTutorial’, true)); } } }
![Page 32: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/32.jpg)
アクセスデータの収集に使う例
!
• どこからアクセスされたかreferrerを取る • sessionに保存 • 必要なタイミングでsessionから取出し保存
![Page 33: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/33.jpg)
アクセスデータの収集に使う例use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; !class AccessLogListener { public function onKernelRequest(GetResponseEvent $event) { if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) { return; } $request = $event->getRequest(); ! // あくまでrefを取るだけのサンプル
// 実際には各種属性情報を保存しとくと良い
$ref = $request->query->get('ref'); if ($ref) { $request->getSession()->set(‘ref’, $ref); } } }
![Page 34: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/34.jpg)
まとめ(無理矢理)!
• コントローラ実行前の共通処理を書くのに便利
• EventListener使えばアイデア次第で色々ハックできる
• オレオレ作ってしまってもいいじゃない
![Page 35: EventListener使いこなし術 - Symfony勉強会#10](https://reader033.vdocuments.site/reader033/viewer/2022052315/555a9008d8b42a3e268b45b2/html5/thumbnails/35.jpg)
EventListener おまけ
活用事例としてはbrtriverさんのお話が非常に参考になります !「運用しやすい管理画面とは」 http://tech.voyagegroup.com/archives/7644534.html !"PHP Fatal error: Allowed memory size of xxx" で落ちる前にできること http://d.hatena.ne.jp/brtRiver/20131206/1386345547