コンポーネントには以下のコールバックメソッドがあります。
- initialize(Controller $controller)
- startup(Controller $controller)
- beforeRender(Controller $controller)
- shutdown(Controller $controller)
- beforeRedirect(Controller $controller, $url, $status=null, $exit=true)
いずれのコールバックメソッドも引数にコントローラを持っているので、コンポーネントからコントローラのプロパティやメソッドにアクセスできます。
例えばコントローラのbeforeFilterの前に実行されるinitializeメソッドで以下のように書けば、コンポーネントの別のメソッドでもコントローラにアクセスできるわけです。
HogeComponent
public function initialize(Controller $controller) { $this->controller = $controller; } public function test() { // Viewに変数を渡したり $this->controller->set('title_for_layout', 'Hogeコンポーネントのtestメソッドからセットしたタイトル'); // Sessionメッセージを設定したり(セッションコンポーネントをコンポーネントでセットすればコントローラを通さなくてもいいけど) $this->controller->Session->setFlash('Hogeコンポーネントのtestメソッドからセットしたメッセージ'); // Modelも使えます。(App::usesで呼ぶ方がスマートだけど) $this->controller->loadModel('Test'); }
ところが、コントローラでコンポーネントを読み込む場合はちょっと問題があります。
例えば呼び出し元コントローラのあるメソッドでこんな風にHogeコンポーネントを読み込む場合。
class FugasController { function aru() { $this->Hoge = $this->Components->load(Hoge); } }
この場合、コンポーネントのコールバックメソッド「initiazile」と「startup」は通すことができません。*1
コンポーネント側の通常のメソッドを、コントローラを使用する前提で作ったりすると困ったことになるわけです。
コンポーネントのコンストラクタで呼出元コントローラをセットする
そこで、コンストラクタを使って呼び出し元コントローラをプロパティにセットすることにしました。
HogeComponent
public function __constract(ComponentCollection $collection) { $this->controller = $collection->getController(); }
コンストラクタの引数はコントローラではなくComponentCollectionであることに注意しましょう。
ComponentCollectionは呼び出し元のコントローラを_Controllerプロパティに持っていますが、protectedのためHogeComponentからはアクセスできません。
なので、getControllerメソッドを使って取得しています。
コントローラ単位でコンポーネントをセットするのは勿体無い、だけどコントローラにもアクセスしたい。というのはよくあるケースだったのでφ(..)メモしておきます。
- どちらのメソッドもFugasコントローラのaruメソッド実行前に呼出が終わっているから [↩]