リダイレクトするのは早いほうがいい。コンポーネントの処理が終わってからリダイレクトするのと処理前にリダイレクトするのでは、場合によってはレスポンス時間にエライ違いがでる。
TLTR
結論から言うと、コンポーネントのinit
でcms.page.init
イベントをフックして、Redirectファサードのtoメソッドを使ってRedirectResponseオブジェクトを返してやればいい。
public function init()
{
Event::listen('cms.page.init', function () {
if ( $component->needRedirect() ) {
return Redirect::to('/path/to/redirect');
}
});
}
詳細
通常、コンポーネントからリダイレクトするには onRun
でRedirectResponseオブジェクトを返す。
しかし、他にもコンポーネントがたくさん読み込まれていると最悪、多くのコンポーネントの onRun
が処理されたあとにリダイレクトになる。場合によっては、無駄な処理のためにリダイレクトが遅くなる。
なので、できればコンポーネントの onRun
が実行される前にリダイレクトしたい。
コンポーネントの他のタイミングと言えば init
だが、このメソッドの呼び出し元である\Cms\Classes\Controller::initComponents
はinit
の返り値を期待していない。
どこでRedirectResponseオブジェクトを返せばリダイレクトしてもらえるか、このControllerクラスを見てみる。
コンポーネントからリダイレクトをかける話なので、最低限コンポーネントが初期化されている必要がある。ということで、コンポーネント初期化から後の処理をかいつまんで並べると下記のようになっている
- コンポーネント
init
- レイアウト
onInit
- ページ
onInit
-
cms.page.init
イベント発火 - Ajaxハンドラ実行
-
cms.page.start
イベント発火 - レイアウトコンポーネント
onRun
- ページコンポーネント
onRun
ここでコンポーネントが直接絡むのがコンポーネントのinit
とonRun
だが、イベントをフックするという手もあることがわかる。
cms.page.init
イベント発火部分をみるとコメントに「カスタムレスポンスを返す機会を提供する」と書かれてる。
/**
* @event cms.page.init
* Provides an opportunity to return a custom response ...
*/
if ($event = $this->fireSystemEvent('cms.page.init', [$page])) {
return $event;
}
このイベントをフックしてリダイレクトするには下記のようになる。
Redirect
ファサードのto
メソッドを使ってRedirectResponseオブジェクトを返してやればいい。
Event::listen('cms.page.init', function () {
if ( $component->needRedirect() ) {
return Redirect::to('/path/to/redirect');
}
});
Octoberドキュメントには「イベントフックはPlugin::boot
に記述するのが一般的」と書かれているが、コンポーネントのinit
がイベント発火よりも前に実行されているので、コンポーネントのinit
にEvent::listen
を記述しても問題ない。この方が、コンポーネントに実装をまとめられてきれいになる。また、このコンポーネントが使用されていないときもlistenしてしまうのを自然に避けられる。
ということで、コンポーネントのinit
で下記のようにすることで、どのコンポーネントのonRun
が走るよりも前に、コンポーネントの機能を使いつつ、リダイレクトをかけることができる。
public function init()
{
Event::listen('cms.page.init', function () {
if ( $component->needRedirect() ) {
return Redirect::to('/path/to/redirect');
}
});
}
参考
イベントのドキュメント
https://octobercms.com/docs/api/cms/page/init
(すべてが載っているとは限らないので、ソースコードを検索するのをお勧めする。)