requestActionと通常のactionを共用することは可能か
requestActionはControllerやView内において、特定のactionを呼びだすときに使います。
たとえば、Viewの一部品であるelementのなかで使用し、「最新のニュースを数件表示する」といった機能を実装できます。
elementにしておけば複数のページから呼びだすことも、キャッシュを効かすことも可能ですので、非常に重宝します。
requestActionの仕様で、URLは「通常のactionとしてアクセス可能」なため、使い方には注意が必要です。
通常のactionとして実行してほしくない場合は、actionの先頭で(requestActionで呼ばれてない場合には)404ページを出力するようにしましょう
CakePHPでは、Viewをレンダリングするのは以下のようなケースです。
- $this->autoRenderがtrue(既定値)で、actionが終了するか$this->render()が呼ばれる、もしくはreturnが返される
- $this->autoRenderがfalseで、$this->render()が呼ばれる
反対に次のケースでは、returnで返された値が直に出力されます。
- $this->autoRenderがfalseで、returnが返される(かactionが終了する)
なお、requestActionによってactionが呼ばれた場合は、あらかじめautoRenderもautoLayoutもfalseとなり、何も指定していなければreturnによって返された値が返ります。
そのため明示的にViewで呼びだしても、layoutされたViewの中に、さらにlayoutされたViewが入るということはありません。
Viewをレンダリングして返してほしい場合は、以下のようにreturnを指定して呼びだしてください。
# view
// 第2引数にreturnを含めるとviewをレンダリングした結果を返す
// layoutは含まないviewの結果のみ
echo $this->requestAction('/controller/action/id' ,array('return') );
このケースでもlayoutはされませんのでご安心を。
requestActionと通常のactionを共用する
さてこれをふまえて、いよいよ本題です。
結論から言うと「共用は可能」です。
同じデータをレンダリングするかどうかの違いであれば、まったく意識することなく共用できますし、以下のどちらかの手順をふめば、requestActionで呼ばれたかどうかは判定可能でしょう。
- actionの先頭でautoLayoutとautoRenderの値をチェックする
- $this->params['requested']を確認する
前者は上述のとおりです。
後者は、requestActionの場合にセットされるようですので、次のように書くことができます。
# controller
function index() {
$posts = $this->Post->find('all');
if (!empty($this->params['requested'])) return $posts;
$categories = $this->Post->Category->find('all');
}
requestActionのときは、余計なデータを読み込むことがなくなります。
追記:Viewキャッシュを使用しているときには注意が必要だった
便利なViewキャッシュですが、どうやら、requestActionで呼ばれた場合でも、すでにページ全体のキャッシュが存在する場合、そのキャッシュを表示するようです。
そのため、elementのなかでrequestActionを呼んだ場合、同じURLのキャッシュが存在するときは、elementのなかにキャッシュされたページが丸々差し込まれるという、非常に不格好なことになります。
さらにさらに、ページ丸々ということは当然にhtmlやheadが入っていますので、そもそもhtmlとしてあり得ない状態になってしまうようです。
Viewキャッシュを使用したページと同じURLをrequestActionで呼びだすことはできないと考えるしかなさそうです。
なぜなら、action内で「requestActionかどうかを判定し・・・」とやろうにも、キャッシュを表示するときはcontrollerを通りません。requestActionがキャッシュを読まない処理を施してくれない以上どうしようもなさそうです。