おそらくCakePHP2系になってからの機能だと思うのですが、コンポーネントやヘルパーの設定オプションに「className」というオプションが追加されました。
従来であれば、例えばSessionコンポーネントに手を加えるときには、CakeディレクトリにあるSessionコンポーネントをappディレクトリにまるごとコピーして、appディレクトリのSessionコンポーネントを修正するという方法をとっていました。
この方法のデメリットは、コアのアップデートでコンポーネントのバージョンが上がっても反映されないこと。それと、ソースの見通しが悪いことです。*1
もう一つの方法としては、Sessionコンポーネントを継承してMySessionコンポーネントを作ってしまうという方法がありました。この方法であれば前述の問題点は解決されるのですが、使用するときに$this->MySession->hoge()という風に名前が変わってしまうのが難点です。たった2文字増えるだけですが個人的に違和感があってイヤなんですよね。*2
「className」を使えば、この2つの問題を解決することができます。
classNameの使い方
classNameを利用すると、Sessionコンポーネントを継承したMySessionコンポーネントを$this->Session->hoge()で使えるようになります。
それでは、簡単に使い方を説明しますね。
SessionComponentを継承してMySessionComponentを作成する
/appディレクトリのComponentにMySessionComponent.phpというファイルを作成します。
/app/Controller/Component/MySessionComponent.php
<?php App::uses('SessionComponent', 'Controller/Component'); class MySessionComponent extends SessionComponent { public function hoge() { // SessionComponent のメソッドをオーバーライドしたり、 // 新しいメソッドを追加したりしてお楽しみください。 } }
MySessionComponentを$this->Sessionで使えるようにする
それでは作成したMySessionコンポーネントをSessionの名前で使えるようにしてみましょう。Sessionコンポーネントはほとんど使わないことのないコンポーネントだと思いますので、AppControllerで$componentsに入れるのがいいですね。
/app/Controller/AppController.php
public $components = array( 'Session' => array( // ここにclassNameとして、先ほど作成したMySessionを設定するだけ 'className' => 'MySession', ), );
これで、$this->SessionでMySessionコンポーネントのプロパティやメソッドを使用できます。
読み込み順に注意!
Controllerのcomponentsプロパティに自作のコンポーネントをclassNameで使用するときに、1点だけ注意が必要です。
それは、継承元のコンポーネントが他の場所ですでにloadされている場合、classNameの設定が効きません。
例えばコンポーネントの読み込みがこんな感じの場合。
public $components = array( 'DebugKit.Toolbar', 'Auth' => array( 'loginAction' => array( 'admin' => false, 'controller' => 'users', 'action' => 'login', ), 'authenticate' => array( 'Form' => array( 'fields' => array( 'username' => 'username', 'passsword' => 'password', ), 'scope' => array( 'deleted' => 0, ), ), ), ), 'Session' => array( 'className' => 'MySession', ), );
DebugKit.toolbarではSessionコンポーネントが使われているので、ここに書いたSessionコンポーネントの読み込みより先にtoolbarコンポーネントの中で読み込まれてしまいます。継承元となるコンポーネントが呼ばれてしまうとComponentCollectionの_loadedに追加されてしまうので、あとで読み込まれるSessionコンポーネントの設定がスルーされてclassNameが反映されないのです。
たぶんAuthコンポーネントもSessionコンポーネントを使っているので同様の現象が起こると思います。ですので、classNameが効かないな?って時にはclassNameを設定したいコンポーネントを先に書く!ことをお忘れなく。
このclassNameの設定はヘルパーでも有効なので、例えばFormHelperのdatetimeメソッドをオーバーライドして、separatorを年、月、日にするとかいうことも簡単にできてしまいます。
これはほんと、重宝しますね。
実際の使用例についても書きたかったのですが、時間も遅いので続きは次回。
次回予告:「classNameを使ってsetFlashを便利に拡張しよう!」