CakePHPで独自の共通コントローラを継承させて使用する

CakePHPさんはControllerを作成する場合は基本的にAppControllerを継承させて作成するわけですが、AppConroller→他の共通のController→HogeControllerみたいに1つ別の共通コントローラを継承させたいってときがあって、かなーりはまったのでメモ。
ただ、激しくバッドノウハウ

で、何にはまったかというと、AppControllerに共通のコンポーネントやヘルパーを書いて継承した場合は、HogeControllerに書いたコンポーネント、ヘルパーとかはちゃんとマージしてくれるんですが、自分で作ったコントローラを継承させた場合は親のコンポーネントやヘルパーを上書きしてくれるという素敵仕様だった。ひどくね?
というわけでControllerのソースを見に行ったら__mergeVars()で、AppControllerの内容をうまくマージさせてるっぽかったので、こいつを少し改造しました。
具体的には下記のような感じに。

まず、AppControllerを作る

<?php
class AppController extends Controller{

	var $margeClassName = null;


	function __mergeVars() {
		if($this->margeClassName){
			$pluginName = Inflector::camelize($this->plugin);
			$pluginController = $pluginName . $this->margeClassName;

			if (is_subclass_of($this, $this->margeClassName) || is_subclass_of($this, $pluginController)) {
				$appVars = get_class_vars($this->margeClassName);
				$uses = $appVars['uses'];
				$merge = array('components', 'helpers');
				$plugin = null;

				if (!empty($this->plugin)) {
					$plugin = $pluginName . '.';
					if (!is_subclass_of($this, $pluginController)) {
						$pluginController = null;
					}
				} else {
					$pluginController = null;
				}

				if ($uses == $this->uses && !empty($this->uses)) {
					if (!in_array($plugin . $this->modelClass, $this->uses)) {
						array_unshift($this->uses, $plugin . $this->modelClass);
					} elseif ($this->uses[0] !== $plugin . $this->modelClass) {
						$this->uses = array_flip($this->uses);
						unset($this->uses[$plugin . $this->modelClass]);
						$this->uses = array_flip($this->uses);
						array_unshift($this->uses, $plugin . $this->modelClass);
					}
				} elseif ($this->uses !== null || $this->uses !== false) {
					$merge[] = 'uses';
				}

				foreach ($merge as $var) {
					if (!empty($appVars[$var]) && is_array($this->{$var})) {
						if ($var !== 'uses') {
							$normal = Set::normalize($this->{$var});
							$app = Set::normalize($appVars[$var]);
							if ($app !== $normal) {
								$this->{$var} = Set::merge($app, $normal);
							}
						} else {
							$this->{$var} = array_merge($this->{$var}, array_diff($appVars[$var], $this->{$var}));
						}
					}
				}
			}

			if ($pluginController && $pluginName != null) {
				$appVars = get_class_vars($pluginController);
				$uses = $appVars['uses'];
				$merge = array('components', 'helpers');

				if ($this->uses !== null || $this->uses !== false) {
					$merge[] = 'uses';
				}

				foreach ($merge as $var) {
					if (isset($appVars[$var]) && !empty($appVars[$var]) && is_array($this->{$var})) {
						if ($var !== 'uses') {
							$normal = Set::normalize($this->{$var});
							$app = Set::normalize($appVars[$var]);
							if ($app !== $normal) {
								$this->{$var} = Set::merge($app, $normal);
							}
						} else {
							$this->{$var} = array_merge($this->{$var}, array_diff($appVars[$var], $this->{$var}));
						}
					}
				}
			}
		}
		parent::__mergeVars();

	}
}

$margeClassNameっていうプロパティを追加してやる。
そして__margeVarsをまるっとコピペして'AppController'って部分を$this->$margeClassNameに変えて、最後にスーパークラスの同じメソッドを読んでるだけ。

で、共通のControllerで$margeClassNameを設定してやる

<?php
class CommonAppController extends AppController{
	var $margeClassName = "CommonAppController ";
	var $components = array("共通のコンポーネント");
}

後はコントローラを実装するときにCommonAppControllerを普通に継承してやればよい。

<?php
App::import("Controller" , "CommonApp");
class HogeController extends CommonAppController {
	var $components = array("ここで使うコンポーネント");
}

これでCommonAppController,AppController,HogeControllerのコンポーネントをうまくマージしてくれました。
けど、__margeVarsをまるっとコピペしてあるあたりアレ。
それと当然だけど、多段継承をさらにすると上書いてくれます。\(^o^)/
まぁ、コンポーネント、ヘルパー、モデルあたりをマージするだけだったら、コンストラクタ読んでるところでマージしてあげるだけでもいいっぽいんだけど。
でももっとうまいやり方ありそうだよなあ。ググってもそれらしいのが見つからなかった!もっとエレガントな方法教えてぷりいいいいず。