質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
CakePHP

CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

Q&A

1回答

4637閲覧

cakephp3のeventについて

imamoto_browser

総合スコア1161

CakePHP

CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

0グッド

1クリップ

投稿2017/05/15 14:01

編集2022/01/12 10:55

cakephp3のeventについて質問があります。tableクラスからdispatch()を使って、eventをイベントリスナーに通知するところまでは理解できたのですが、eventを通知されたイベントリスナーがどのような動きをしているのか分かりません。

php

1class ArticlesTable extends Table { 2 3 public function initialize(array $config) 4 { 5 $this->belongsTo('Posts', [ 6 'foreignKey' => 'posts_id' 7 ]); 8 9 $listener = new ContactsListener(); 10 $this->eventManager()->on($listener); 11 } 12 13public function checkSomething() 14 { 15 $arr = ['a'=> 1, 'b'=> 2]; 16 //... some code here 17 $event = new Event('Model.Articles.SomethingCheck', $this, [ 18 'check_arr' => $arr 19 ]); 20 $this->eventManager()->dispatch($event); 21 22 }

↓イベントリスナー

php

1class ContactsListener implements EventListenerInterface 2{ 3 4 public function implementedEvents() 5 { 6 return [ 7 'Model.Articles.SomethingCheck' => 'createNotificationAfterCheck', 8 ]; 9 } 10 11 public function createNotificationAfterCheck(Event $event, array $arr) 12 { 13 dump($event); 14 15 } 16}

eventの追加はbeforeSaveのような概念を新しく追加しているだけなのでしょうか。上のcheckDuplicates()で仕込んだcheck_arrの連想配列はどうゆう場合に有効利用できるのでしょうか。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

eventの追加はbeforeSaveのような概念を新しく追加しているだけなのでしょうか。

beforeSaveなどもイベントの1つなので、おっしゃる通りです。
ただ、beforeSaveなどはCakePHPのライフサイクルに組み込まれているため、自分でイベントを新たに設定するよりも使う機会は多いと思います。
どちらにせよ、指定するイベントが起こったら、特定の処理を実行したいというときに使います。

上のcheckDuplicates()で仕込んだcheck_arrの連想配列はどうゆう場合に有効利用できるのでしょうか。

分かりにくくなっている原因は、以下のようにcreateNotificationAfterCheck(Event $event, array $arr)と書いているためかもしれません。
Eventクラスのコンストラクタに設定する第3引数の配列を$aとし、イベントを$eventとすると、createNotificationAfterCheck($event, $a[0], $a[1], $a[2], ……)と表せます。$aの値は$eventにも含まれているので(Event $event)だけでも十分です。

PHP

1public function createNotificationAfterCheck(Event $event, array $arr) 2{ 3} 4

PHP

1// この方が分かりやすいです 2public function createNotificationAfterCheck(Event $event) 3{ 4} 5

次に'check_arr'ですが、'check_arr'は何かの判断材料に使ったり、save()する前にデータを一定の基準で変更したりするときなどに使います。
何かデータを渡さないと、できることの幅が狭くなります。

PHP

1// この方が分かりやすいです 2public function createNotificationAfterCheck(Event $event) 3{ 4 // 処理の方法はCakePHPのバージョンによって違うので、適当に列挙しています 5 6 // $event->getData('check_arr') 7 // $event->setResult(['check_arr' => データ]); 8 // $event->data['check_arr'] 9} 10

利用法を適当に列挙してみます。

  • save()する前に、渡したデータを一定の条件で修正する
  • 渡す値によって異なるログファイルにログを書き込む
  • 渡す値によって異なる相手にメールを送る
  • 渡す値によって異なるキャッシュファイルに書き込む
  • 渡す値によってイベントを中止する

コメントに対するコメント

$this->eventManager()->dispatch($event);の部分が気になるのですが、これはEventManager.phpに$eventを通知して、atachされているeventに対して、適用するという動きでいいんでしょうか。

そうですね。新しいイベントを事前に紐づけていたリスナーに伝え、そのリスナーのメソッドを実行させるということですね。
具体的には、EventManager.phpのdispatchメソッドに$eventを渡し、そこでリスナーのメソッドに$eventを渡してそのメソッドを実行するという流れです。

createNotificationAfterCheckはpublic function createNotificationAfterCheck(Event $event , $entity , $options) {}を書かないと呼ばれないと思うのですが、beforeSaveだと「呼ばれるのはsave前だな」とフックされるタイミングが直感的にわかるのですが、独自イベントだとそのタイミングってどこで設定するんでしょうか。結局、コントローラからTableを呼ぶだけみたいになってしまうんでしょうか。

やはりイベントが発生したことをどこかで伝える必要があるので、$this->eventManager()->dispatch($event);は必要になるのではないでしょうか。ウェブサイト表示のリクエストを受けてからデータを返すまでの流れ以外については、CakePHPではタイミングを判断しようがありません。

しかし、独自にイベントを作成した場合、そのイベントの中で処理する内容に対して独自に優先順位をつけることはできます。具体的には、$this->eventManager()->on()['priority' => 数値](デフォルトは10)を設定する方法です(バージョンによってはattach())。$this->eventManager()->on()で同じリスナーを複数加えられるので、それらの優先順位を設定すれば、タイミングを好きに設定できます。例えば、①save()の前に行う処理、②save()、③save()の後に行う処理、のように分ければbeforeSaveやafterSaveができます。

あと設計スタイルの話になりますが、呼び出すには当然、public function beforeSave(Event $event , $entity , $options) {}の記述が必要かと思いますが、それってsaveの処理を対応するコントローラに書かないといけないので、コントローラから新たにサブコントローラを呼んでみたいな細分化された設計ってできないのかなぁとちょっと思いました。

すみません、なんとなくしかやりたいことが分からないのですが、管理が面倒になるだけでサブコントローラー(サブクラス)を作ってもかまわないと思います。

それと、save()はコントローラーだけではなく、config/bootstrap.phpでもできます。どこかで$this->eventManager()->dispatch($event);を実行した段階で、bootstrap.phpに書いたコードがイベントのdispatchを検知して、指定したリスナー名に該当した場合に処理を行うことができます。そこではsave()もできます。

例えば以下のように設定すると、Model.Hoge.exampleにイベントが伝わったことを検知して、function()内の処理を行います。
なお、Model.Hoge.exampleをModel.beforeSaveにすると、コントローラーにpublic function beforeSave(Event $event , $entity , $options) {}を記述しなくてもbeforeSaveを使うことができます。

PHP

1// bootstrap.php 2use Cake\ORM\TableRegistry; 3 4$hoge = TableRegistry::get('Hoges'); 5$hoge 6 ->eventManager() 7 ->on('Model.Hoge.example', ['priority' => 15], function($event, $entity) use ($hoge) 8 { 9 // バージョンによって$event->data['hoge']の取得方法が異なる 10 if($hoge->save($event->data['hoge'])) { 11 debug('save()できた!'); 12 } 13 });

投稿2017/05/16 16:39

編集2017/05/17 03:07
coba-coba

総合スコア1409

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

imamoto_browser

2017/05/16 21:52 編集

利用法についても言及していただき、ありがとうございます。 $this->eventManager()->dispatch($event);の部分が気になるのですが、これはEventManager.phpに$eventを通知して、atachされているeventに対して、適用するという動きでいいんでしょうか。 createNotificationAfterCheckはpublic function createNotificationAfterCheck(Event $event , $entity , $options) {}を書かないと呼ばれないと思うのですが、beforeSaveだと「呼ばれるのはsave前だな」とフックされるタイミングが直感的にわかるのですが、独自イベントだとそのタイミングってどこで設定するんでしょうか。結局、コントローラからTableを呼ぶだけみたいになってしまうんでしょうか。 あと設計スタイルの話になりますが、呼び出すには当然、public function beforeSave(Event $event , $entity , $options) {}の記述が必要かと思いますが、それってsaveの処理を対応するコントローラに書かないといけないので、コントローラから新たにサブコントローラを呼んでみたいな細分化された設計ってできないのかなぁとちょっと思いました。
coba-coba

2017/05/17 02:51

長くなってしまったので、ここにコメントせず、上に「コメントに対するコメント」を追記しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問