CakePHPのコントローラ内でマジックメソッドの __call を用いたいと思っても、そのままだと missing action のエラーが発生する。これは Controller::invokeAction において ReflectionMethod のコンストラクタでメソッドをチェックしメソッドが存在しない場合にエラーを発生させているため。

/* Controller::invokeAction */
public function invokeAction(CakeRequest $request) {
	try {
		$method = new ReflectionMethod($this, $request->params['action']); // メソッドが無い場合はここで ReflectionException が発生する

		if ($this->_isPrivateAction($method, $request)) {
			throw new PrivateActionException(array(
				'controller' => $this->name . "Controller",
				'action' => $request->params['action']
			));
		}
		return $method->invokeArgs($this, $request->params['pass']);

	} catch (ReflectionException $e) {
		if ($this->scaffold !== false) {
			return $this->_getScaffold($request);
		}
		throw new MissingActionException(array(
			'controller' => $this->name . "Controller",
			'action' => $request->params['action']
		));
	}
}

なので、次のように Controller::invokeAction をオーバーライドすれば回避できる。

public function invokeAction(CakeRequest $request) {
	try {
		$method = new ReflectionMethod($this, $request->params['action']);

		if ($this->_isPrivateAction($method, $request)) {
			throw new PrivateActionException(array(
				'controller' => $this->name . "Controller",
				'action' => $request->params['action']
			));
		}
		return $method->invokeArgs($this, $request->params['pass']);

	} catch (ReflectionException $e) {
		// まぁ、別に __call じゃなくてもいいってことですが変える必要もないと思うので。
		return $this -> __call( $request -> params['action'], $request -> params['pass'] );
	}
}

アクションにフィルタをかけたいなら

public function invokeAction(CakeRequest $request) {
	try {
		$method = new ReflectionMethod($this, $request->params['action']);

		if ($this->_isPrivateAction($method, $request)) {
			throw new PrivateActionException(array(
				'controller' => $this->name . "Controller",
				'action' => $request->params['action']
			));
		}
		return $method->invokeArgs($this, $request->params['pass']);

	} catch (ReflectionException $e) {
		$isValidAction = $this->_checkAction($this->request->params); // ここでアクションのフィルタリングをする
		if( $isValidAction ) {
			return $this -> __call( $request -> params['action'], $request -> params['pass'] );
		}

		if ($this->scaffold !== false) {
			return $this->_getScaffold($request);
		}
		throw new MissingActionException(array(
			'controller' => $this->name . "Controller",
			'action' => $request->params['action']
		));
	}
}

private function _checkAction( $args ) {
	// アクションのパラメータをチェックする
	// 正しければ true を返す。
	return true;
}

なおバージョンは CakePHP version 2.2.1 です。

ちなみに、__call  メソッドなどオーバーロードメソッドはすべて public 宣言しなくてはなりません。となると、url から __call を呼び出されたらと気になるかもしれませんが、アンダースコアから始まるメソッドを外部から直接呼び出した場合は try ブロックの $this -> _isPrivateAction でしっかり例外を発行してくれるのでご安心あれ。