FirstChildRedirectについて

質問全般・改善要望
返信する
sama55
メンバー
メンバー
記事: 816
登録日時: 2009年8月03日(月) 08:16

FirstChildRedirectについて

投稿記事 by sama55 »

比較的リソースの階層が深いサイトでFirstChildRedirectを多用してみました。具体的に言うと、最下層より上(3階層であれば1階層目と2階層目のリソース)でFirstChildRedirectをコールし、上位階層のクリックで最下層のリソースを表示するようにしたところ、階層が深ければ深いほどクラサバ間のやりとりが増大し、画面の反応がリニアに悪くなりました。

親リソース(フォルダ/コンテナ属性のリソース)が多いサイトでは、親リソースを作るたびにコンテンツを作るのは面倒ですし、親リソースのクリックで最初に出現する(新着の)子リソースが表示できれば、製作コストとクリック数が同時に削減できるケースも多いと思います。その解決策としてFirstChildRedirecを多用してみたのですが、残念な結果に終わりました。

このような経験をされた方、または、Ditto等で下位リソースの一覧(プチリソースマップ?)を表示する方式以外の対処法などがあれば是非お聞きしたいです。
soushi
管理人
記事: 224
登録日時: 2009年7月30日(木) 01:59

Re: FirstChildRedirectについて

投稿記事 by soushi »

soushiです。

思いつきでFirstChildRedirectを改造しました。

コード: 全て選択

$docid = (isset($docid))? $docid: $modx->documentIdentifier;

$startid=$docid;
$firstChildUrl='';
while($firstChildUrl == ''){
  $children= $modx->getActiveChildren($docid, 'menuindex', 'ASC');
  if (!$children === false) {
      $firstChild = $children[0];
      $docid=$firstChild['id'];
  } else {
      if( $startid == $docid ){
          $docid = $modx->config['site_start'];
      }
      $firstChildUrl= $modx->makeUrl($docid);
  }
}
return $modx->sendRedirect($firstChildUrl);
最下層のリソースを一発で拾うようになっているので、ブラウザ-サーバ間のやり取りも一回になると思います。
ちなみに適当に作ったのでどの階層のコンテンツに載せても問答無用で最下層まで下ってしまいます(^^;
sama55
メンバー
メンバー
記事: 816
登録日時: 2009年8月03日(月) 08:16

Re: FirstChildRedirectについて

投稿記事 by sama55 »

soushiさん、レスありがとさんです。^^

上記、FirstChildRedirectの改造版でも最低一回はsendRedirectが走ることで希望する性能が出ないため、色々考えたあげく、下のマニアックな方法で対処してみました。満足いく性能は出ましたがこんな対応でよかったのか自信なしです・・・  :roll:

対応手順)
 ↓ 上位リソースをすべてウェブリンクにする
 ↓ ウェブリンク属性に下のスニペット(FirstChildUrl)を書く  ※1
 ↓ Wayfinderなどがリソースをパースする過程で、上位リソースのリンクに末端リソースのURLがセットされる

※1 ウェブリンクでは、documentIdentifierに常にスタートドキュメントが設定され自己のリソースIDは分かりません(FirstChildUrlのdocidを省略できない)。ということで、自分のリソースIDを明示的に与える必要があります(なぜこういう仕様なのか・・・本家に問い合わせてますが今のところレスなしです)。

参考スニペット)

スニペット名: FirstChildUrl

コード: 全て選択

$docid = (isset($docid))? $docid: $modx->documentIdentifier;
$fullLink = (isset($fullLink))? $fullLink : FALSE;
$ChildId = $modx->runSnippet('FirstChildId', array('docid'=>$docid));
if ($fullLink) {
    $firstChildUrl= $modx->makeUrl($ChildId, '', '', 'full');
} else {
    $firstChildUrl= $modx->makeUrl($ChildId);
}
return $firstChildUrl;
スニペット名: FirstChildId

コード: 全て選択

$docid = (isset($docid))? $docid: $modx->documentIdentifier;
$firstChildId = '';
while($firstChildId == ''){
  $children= $modx->getActiveChildren($docid, 'menuindex', 'ASC','id,type');
  if ($children) {
    $child = $children[0];
    if ($child['type'] == 'document') {
      $firstChildId = $child['id'];
    } else {
      $firstChildId = $modx->runSnippet('FirstChildId',array('docid'=>$child['id']));
    }
  } else {
    $firstChildId = $modx->config['site_start'];
  }
}
return $firstChildId;
注意)上記のスニペはリカーシブコールを含むのでリソースの構成次第ではダイナミックループするかもしれません。。。  :oops:

操作・確認手順)
 ↓ 上位リソースのリンクをクリックする
 ↓ リダイレクトされずに末端リソースが表示される
sama55
メンバー
メンバー
記事: 816
登録日時: 2009年8月03日(月) 08:16

Re: FirstChildRedirectについて

投稿記事 by sama55 »

追伸)
上記の方式は、リソースタイプ(ドキュメントとウェブリンクの違い)を意識して処理するWayfinderは問題ないようですが、リソースタイプを意識せずに単純にIDからURLを割り出すBreadcrumbsでは処理できないようです。

ウェブリンクも処理できるようにBreadcrumbs V1.0.2を改造してみました。
添付ファイル
Breadcrumbs2.txt
ウェブリンク対応版Breadcrumbs V1.0.2
(17.08 KiB) ダウンロード数: 372 回
soushi
管理人
記事: 224
登録日時: 2009年7月30日(木) 01:59

Re: FirstChildRedirectについて

投稿記事 by soushi »

soushiです。

1つのリダイレクトもなしですかぁ。
個人的に1回なら許容範囲かなと思ってました(^^;
リダイレクトをなくすと言うところだけ考えると $modx->sendForward() APIを使うといいかもしれません。
こちらはリダイレクトせず、MODx内部でリソースIDを変えてもう一度処理し直します。

コード: 全て選択

$docid = (isset($docid))? $docid: $modx->documentIdentifier;

$startid=$docid;
$firstChildId=0;
while(1){
  $children= $modx->getActiveChildren($docid, 'menuindex', 'ASC');
  if (!$children === false) {
      $firstChild = $children[0];
      $docid=$firstChild['id'];
  } else {
      $firstChildId= ($startid == $docid)?$modx->config['site_start']:$docid;
      break;
  }
}
return $modx->sendForward($firstChildId);
URLはそのままで中身は最下層の先頭子リソースの中身が表示されます。
少しでも処理を早くしたい場合はプラグイン化して「OnWebPageInit」あたりで実行させれば多分、早くなるのではないかなぁと思います。
実際に確認まではしてないのですが。。。

あとはsendForward()ってあまり使わないAPIなので、副作用が気になるところですね。
2回同じ処理をするので、例えばプラグインでアクセスをカウントしていると2回カウントされたりする可能性がある思います。
ちなみに回数制限があるので無限ループにはならないです(その代わりエラー画面になります)。
sama55
メンバー
メンバー
記事: 816
登録日時: 2009年8月03日(月) 08:16

Re: FirstChildRedirectについて

投稿記事 by sama55 »

おつかれさまです。
soushi さんが書きました:1つのリダイレクトもなしですかぁ。 個人的に1回なら許容範囲かなと思ってました(^^;
プロセッサの占有率とリッチな帯域があれば、こんなことは、はなから問題にもならないのかもしれませんが、最近うちのサバ&ネット重いんですよ~ 笑)
soushi さんが書きました:リダイレクトをなくすと言うところだけ考えると $modx->sendForward() APIを使うといいかもしれません。こちらはリダイレクトせず、MODx内部でリソースIDを変えてもう一度処理し直します。URLはそのままで中身は最下層の先頭子リソースの中身が表示されます。少しでも処理を早くしたい場合はプラグイン化して「OnWebPageInit」あたりで実行させれば多分、早くなるのではないかなぁと思います。実際に確認まではしてないのですが。。。
自分もこれを真っ先に考えて、最初はループさせずにsendForwardだけにしてみたのですが、それほど効果はありませんでした。
soushi さんが書きました:あとはsendForward()ってあまり使わないAPIなので、副作用が気になるところですね。
2回同じ処理をするので、例えばプラグインでアクセスをカウントしていると2回カウントされたりする可能性がある思います。
ちなみに回数制限があるので無限ループにはならないです(その代わりエラー画面になります)。
実際に適用してみたところ、確かに最下層のページは表示されますが、やはり性能がいまいちでした。どして?と思い、パフォーマンスタグを表示させてみると、どうもキャッシュが効いてないようで、二度表示させてもDBのアクセス回数が削減されませんでした。副作用は確かにそうですよね。セッションを見る処理が途中にあるとヤバい感じになったりして・・・  :mrgreen:
soushi
管理人
記事: 224
登録日時: 2009年7月30日(木) 01:59

Re: FirstChildRedirectについて

投稿記事 by soushi »

soushiです。

なるほど、何も考えずにsendForward()と書いてしまいましたが、キャッシュが効かないのは逆に問題になりますね。
なかなかうまくは行かないもんです…失礼しました(^^;
sama55
メンバー
メンバー
記事: 816
登録日時: 2009年8月03日(月) 08:16

Re: FirstChildRedirectについて

投稿記事 by sama55 »

上記の加速対応ですが、もう一つ弊害がありました。

現象)
テンプレートやリソース内でウェブリンクリソースへのURLをチルダで表現(例:[~99~])すると、子や孫のリソースに飛ばない。

原因)
リソースタイプに関係なくエイリアス(またはID)が単純にURLとして出力されるため。
※ウェブリンクリソースの場合は、ウェブリンク属性がURLとして出力された方がよさそうな気がします・・・仕様?バグ?

回避策)
チルダ表現の代わりに、GetFieldなどで当該ウェブリンクリソースの「ウェブリンク属性(content)」を直接取得する。
例: <a href="[[GetField? &docid=`99` &field=`content`]]">99リソースへのリンク</a> ※結果的に子/孫リソースへのURLが設定される。
sama55
メンバー
メンバー
記事: 816
登録日時: 2009年8月03日(月) 08:16

Re: FirstChildRedirectについて

投稿記事 by sama55 »

その後いろいろ調べたところ、FirstChildUrlによる対応が最も速いのは間違いないのですが、コアやアドオンとの相性が悪く、結局FirstChildRedirectに戻しました。仕切りなおして別な角度から調べたところ、以下が原因で性能が出なかったようです・・・  :oops:

原因)
 1.FirstChildRedirectをキャッシュオン([[FirstChildRedirect]])で呼んでたこと
 2.FirstChildRedirectを仕込んだリソースのテンプレートが重いものであったこと

対応)
 1.FirstChildRedirectはキャッシュオフで呼ぶ ([[FirstChildRedirect]] → [!FirstChildRedirect!])
 2.FirstChildRedirectを使うリソースのテンプレートを空(blank)に変更

考察)
性能のボトルネックはキャッシュのオーバーヘッド(assets/cache/siteCache.idx.phpの解析処理)だったようです。
assets/cache/siteCache.idx.phpの解析時間 × 階層数という図式で性能が劣化してたようです。
ただ、不思議なことに、FirstChildRedirectを呼ぶ上位層リソースをすべて「キャッシュしない」にすると逆に性能が悪くなりました。ということで、リソース自体のキャッシュはオンにし、FirstChildRedirectをキャッシュオフで呼ぶ組み合わせにしました。
返信する