EventListener使いこなし術 - Symfony勉強会#10
-
Upload
yuichi-okada -
Category
Technology
-
view
981 -
download
4
description
Transcript of EventListener使いこなし術 - Symfony勉強会#10
EventListener 使いこなし術
Symfony 勉強会 #10岡田祐一 @okapon_pon
自己紹介•名前:岡田祐一 (@okapon_pon)
• 所属:株式会社クロコス エンジニア
• 2013年~ 日本Symfonyユーザー会
• Symfony歴 2年半ほど
本日の話
EventListener使いこなし術
あらため
EventListenerできること
まえおき
!
Symfonyについて
Symfony
!
素直で柔軟なフレームワーク
Symfony
!
HWに縛られず自由に開発できる
Symfony
柔軟性を支える屋台骨
• DI (+ configuration)
• Event DispatcherEventListenerはここの話
Symfony
イベント駆動のフレームワーク
!
フックポイントが用意されている!
Symfonyのイベント
標準で用意されてるイベント !
• kernel.request • kernel.controller • kernel.view • kernel.response • kernel.exception
Symfonyのイベント
任意のイベントにフック可能
任意のタイミングでResponseを返すことが可能
EventListener 実例
それでは例を見ていきましょう
kernel.controllerイベント
kernel.controllerイベント !
コントローラーの実行前に 発行されるイベント
kernel.controllerイベント
BeforFilterControllerListener というクラスを作ってみます
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 }
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(); } } }
EventListenerクラス作成
何やってるか分かりました?
コントローラー側/** * @Route("/blog") * @Template() */ class BlogController extends Controller { public function before(Request $request) { // Actionが呼ばれる前に実行したい処理が書ける } ! /** * @Route("/", name="blog_index") */ public function indexAction() { } }
Controller実行前のフック
どこかのフレームワークで 見たことある機能・・・
なぜSymfonyにないのか?
コントローラーに書くと
• 再利用しにくい
• テストしづらい
なぜSymfonyにないのか?
もう一度コードに戻ります
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クラス作成
コントローラー側に書く必要がないと感じませんか?
EventListener まとめ1
EventListenrに記述した方が変な依存を持たずシンプルに実装
できる 【サンプルコード】 https://gist.github.com/okapon/fd2dfdacf87e417f7957
EventListener 実装例
Securityコンポーネント よく分からなくて昔作ったオレオレ認証
https://gist.github.com/okapon/88f5bd56a886c287a7d1
EventListener 実装例
先ほどの実装例では isSecure()メソッドはマーカー → annotationにするとよい
!
【参考】Doctrine-Common-Annotations http://docs.doctrine-project.org/projects/doctrine-common/en/latest/reference/annotations.html
EventListener まとめ2
ユーザー認証の仕組みもEventListenrを使えば 簡単に実装できる
ちなみに
ここまでkernel.controllerを取り上げといてなんですが・・・ よく使うのは • kernel.request • kernel.response
では気を取り直して
EventListener使いどころ複数コントローラーで実行したい共通処理
• 認証まわり • 初回登録時のアクセス判定 • チュートリアルの完了状態で表示出し分け • アクセスの分析(referrerとか)
チュートリアルの表示判定する例
ユーザーはどこのURLにでもアクセスする可能性がある
!
• kernel.requestをフック • EventListenerでチュートリアル完了か判定 • 完了してなければチュートリアルを表示
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)); } } }
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)); } } }
アクセスデータの収集に使う例
!
• どこからアクセスされたかreferrerを取る • sessionに保存 • 必要なタイミングでsessionから取出し保存
アクセスデータの収集に使う例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); } } }
まとめ(無理矢理)!
• コントローラ実行前の共通処理を書くのに便利
• EventListener使えばアイデア次第で色々ハックできる
• オレオレ作ってしまってもいいじゃない
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