シェアする

  • このエントリーをはてなブックマークに追加

【CakePHP2】コンポーネント、ヘルパーのメソッドをオーバーライドする

medium_5147220956

おそらく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を便利に拡張しよう!」

  1. オーバーライドであれば変更したいメソッド・プロパティだけをソースに書けばいいのでソースの見通しがいいですね。 []
  2. さらに奥の手としては$sessionとか$this->SessionにMySessionComponentをnew してしまうという方法もありますが、もっと気持ち悪いですよね。 []

シェアする

  • このエントリーをはてなブックマークに追加

フォローする